309 lines
11 KiB
JavaScript
309 lines
11 KiB
JavaScript
/*
|
|
* Copyright 2015 IBM Corp.
|
|
* Copyright 2015 Kevin Fox.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
(function() {
|
|
'use strict';
|
|
|
|
angular
|
|
.module('horizon.dashboard.project.app_catalog', [])
|
|
.filter('encodeURIComponent', function() {
|
|
return window.encodeURIComponent;
|
|
}).directive('appAction', function () {
|
|
return {
|
|
restrict: 'EA',
|
|
//FIXME static
|
|
templateUrl: '/static/dashboard/project/app_catalog/action.html'
|
|
};
|
|
}).controller('appCatalogTableCtrl', [
|
|
'$scope',
|
|
'$http',
|
|
'$timeout',
|
|
'$modal',
|
|
'appCatalogModel',
|
|
appCatalogTableCtrl
|
|
]).controller('appComponentCatalogTableCtrl', [
|
|
'$scope',
|
|
'$http',
|
|
'$timeout',
|
|
'appCatalogModel',
|
|
appComponentCatalogTableCtrl
|
|
]).service('appCatalogModel', [
|
|
'$http',
|
|
'horizon.app.core.openstack-service-api.heat',
|
|
'horizon.app.core.openstack-service-api.glance',
|
|
'horizon.app.core.openstack-service-api.serviceCatalog',
|
|
appCatalogModel
|
|
]).directive('stars', stars);
|
|
|
|
function appCatalogModel($http, heatAPI, glanceAPI, serviceCatalog) {
|
|
var $scope = this;
|
|
var callbacks = [];
|
|
this.assets = [];
|
|
this.assets_filtered = [];
|
|
//FIXME reduce duplication here....
|
|
this.supported_service_type_to_label = {
|
|
heat: 'Orchestration',
|
|
glance: 'Images',
|
|
murano: 'Murano'
|
|
};
|
|
this.service_filters = [
|
|
{id:'heat', name:'Orchestration'},
|
|
{id:'glance', name: 'Images'},
|
|
{id:'murano', name: 'Murano'}
|
|
];
|
|
this.service_filters_selections = {
|
|
'heat':false,
|
|
'glance':false,
|
|
'murano':false
|
|
};
|
|
var notify = function(){
|
|
angular.forEach(callbacks, function(callback){
|
|
callback();
|
|
});
|
|
};
|
|
//FIXME [{'name':'heat', 'type':'orchestration'}, {'name':'glance', 'type':'image'}]
|
|
serviceCatalog.get().then(function(catalog){
|
|
angular.forEach(catalog, function(entry){
|
|
if(entry.name in $scope.supported_service_type_to_label) {
|
|
$scope.service_filters_selections[entry.name] = true;
|
|
}
|
|
});
|
|
$scope.catalog = catalog;
|
|
$scope.update_assets_filtered();
|
|
});
|
|
this.update_assets_filtered = function(){
|
|
$scope.assets_filtered.length = 0;
|
|
angular.forEach($scope.assets, function(asset){
|
|
if($scope.service_filters_selections[asset.service.type] == true || asset.service.type == 'bundle'){
|
|
var filtered_dep = false;
|
|
angular.forEach(asset.depends, function(dep){
|
|
if($scope.service_filters_selections[dep.asset.service.type] == false){
|
|
filtered_dep = true;
|
|
}
|
|
});
|
|
if(!filtered_dep) {
|
|
$scope.assets_filtered.push(asset);
|
|
}
|
|
}
|
|
});
|
|
var types = {};
|
|
angular.forEach($scope.assets_filtered, function(asset){
|
|
types[asset.service.type] = true;
|
|
});
|
|
//FIXME dedup some of this later.
|
|
var map = {'heat': 'Orchestration', 'glance': 'Images'};
|
|
var options = [];
|
|
|
|
for (var type in types) {
|
|
if(type in map) {
|
|
options.push({'key':type, 'label':map[type]});
|
|
}
|
|
}
|
|
angular.forEach($scope.asset_filter_facets, function(facet){
|
|
if(facet.name == 'service.type') {
|
|
//FIXME Doesn't seem to work currently
|
|
// facet['options'] = options;
|
|
}
|
|
});
|
|
notify();
|
|
};
|
|
this.toggle_service_filter = function(service_name) {
|
|
var value = $scope.service_filters_selections[service_name];
|
|
if(value) {
|
|
value = false;
|
|
} else {
|
|
value = true;
|
|
}
|
|
$scope.service_filters_selections[service_name] = value;
|
|
$scope.update_assets_filtered();
|
|
};
|
|
this.register_callback = function(callback) {
|
|
callbacks.push(callback);
|
|
};
|
|
this.init = function(app_catalog_url) {
|
|
var req = {
|
|
url: app_catalog_url + '/api/v1/assets',
|
|
headers: {'X-Requested-With': undefined}
|
|
}
|
|
$http(req).success(function(data) {
|
|
for (var i in data.assets){
|
|
var asset = data.assets[i];
|
|
$scope.assets.push(asset);
|
|
var process = function(asset) {
|
|
var url = asset.attributes.url;
|
|
heatAPI.validate({'template_url': url}, true).success(function(data){
|
|
asset.validated = true;
|
|
notify();
|
|
}).error(function(data, status){
|
|
var str = 'ERROR: Could not retrieve template:'
|
|
asset.validated = 'unsupported';
|
|
if(status == 400 && data.slice(0, str.length) == str) {
|
|
asset.validated = 'error'
|
|
}
|
|
notify();
|
|
});
|
|
}
|
|
if (asset.service.type == 'heat') {
|
|
process(asset);
|
|
}
|
|
}
|
|
$scope.glance_loaded = true;
|
|
$scope.murano_loaded = true;
|
|
update_found_assets($scope)
|
|
});
|
|
glanceAPI.getImages().success(function(data) {
|
|
$scope.glance_images = data;
|
|
var glance_names = {}
|
|
for (var i in data.items){
|
|
var name = data.items[i]['name'];
|
|
glance_names[name] = {'id': data.items[i]['id']};
|
|
}
|
|
$scope.glance_names = glance_names;
|
|
update_found_assets($scope)
|
|
});
|
|
};
|
|
this.asset_filter_strings = {
|
|
cancel: gettext('Cancel'),
|
|
prompt: gettext('Search'),
|
|
remove: gettext('Remove'),
|
|
text: gettext('Text')
|
|
};
|
|
this.asset_filter_facets = [
|
|
{
|
|
name: 'name',
|
|
label: gettext('Name'),
|
|
singleton: true
|
|
},
|
|
{
|
|
name: 'license',
|
|
label: gettext('License'),
|
|
singleton: true
|
|
},
|
|
{
|
|
name: 'service.type',
|
|
label: gettext('Service Type'),
|
|
//FIXME make dynamic later.
|
|
options: [
|
|
{key: 'heat', label: 'Orchestration'},
|
|
{key: 'glance', label: 'Images'},
|
|
{key: 'murano', label: 'Murano'}
|
|
],
|
|
singleton: true
|
|
}];
|
|
}
|
|
|
|
function common_init($scope, appCatalogModel) {
|
|
$scope.toggle_service_filter = appCatalogModel.toggle_service_filter;
|
|
$scope.service_filters = appCatalogModel.service_filters;
|
|
$scope.service_filters_selections = appCatalogModel.service_filters_selections;
|
|
$scope.asset_filter_strings = appCatalogModel.asset_filter_strings;
|
|
$scope.asset_filter_facets = appCatalogModel.asset_filter_facets;
|
|
$scope.init = appCatalogModel.init;
|
|
}
|
|
|
|
function appCatalogTableCtrl($scope, $http, $timeout, $modal, appCatalogModel) {
|
|
$scope.assets = []
|
|
var update = function(){
|
|
$scope.assets = []
|
|
for (var i in appCatalogModel.assets_filtered){
|
|
var asset = appCatalogModel.assets_filtered[i];
|
|
if(typeof asset.tags !== "undefined" && asset.tags.indexOf('app') > -1){
|
|
$scope.assets.push(asset);
|
|
}
|
|
}
|
|
};
|
|
//FIXME remove. probably belongs in its own directive...
|
|
// var textSearchWatcher = $scope.$on('textSearch', function(event, text) {
|
|
// console.log(text);
|
|
// });
|
|
appCatalogModel.register_callback(update);
|
|
common_init($scope, appCatalogModel);
|
|
$scope.switcher = {pannel: 'app', active: 'grid'};
|
|
$scope.changeActivePanel = function(name) {
|
|
$scope.switcher['active'] = name;
|
|
};
|
|
$scope.details = function(asset) {
|
|
var newscope = $scope.$new();
|
|
newscope.asset = asset;
|
|
var modal = $modal.open({
|
|
//FIXME static from where?
|
|
templateUrl: "/static/dashboard/project/app_catalog/details_panel.html",
|
|
scope: newscope
|
|
});
|
|
newscope.cancel = function() {
|
|
modal.dismiss('');
|
|
};
|
|
};
|
|
}
|
|
|
|
function appComponentCatalogTableCtrl($scope, $http, $timeout, appCatalogModel) {
|
|
$scope.assets = appCatalogModel.assets_filtered
|
|
var update = function(){
|
|
$timeout(function() {
|
|
$scope.assets = appCatalogModel.assets_filtered
|
|
}, 0, false);
|
|
};
|
|
appCatalogModel.register_callback(update);
|
|
common_init($scope, appCatalogModel);
|
|
$scope.switcher = {pannel: 'component', active: 'list'};
|
|
}
|
|
|
|
function update_found_assets($scope) {
|
|
if('glance_loaded' in $scope && 'glance_names' in $scope){
|
|
for (var i in $scope.assets){
|
|
if($scope.assets[i].service.type != 'glance'){
|
|
continue;
|
|
}
|
|
var name = $scope.assets[i].name;
|
|
var is_installed = name in $scope.glance_names;
|
|
$scope.assets[i].installed = is_installed;
|
|
if(is_installed){
|
|
$scope.assets[i].installed_id = $scope.glance_names[name]['id'];
|
|
}
|
|
}
|
|
}
|
|
var asset_name_to_asset = {};
|
|
angular.forEach($scope.assets, function(asset){
|
|
asset_name_to_asset[asset.name] = asset;
|
|
});
|
|
angular.forEach($scope.assets, function(asset){
|
|
if('depends' in asset) {
|
|
angular.forEach(asset.depends, function(dep){
|
|
dep.asset = asset_name_to_asset[dep.name];
|
|
});
|
|
}
|
|
});
|
|
$scope.update_assets_filtered();
|
|
}
|
|
|
|
function stars() {
|
|
var star = angular.element('<i>');
|
|
star.addClass('fa fa-star');
|
|
star.css({ color: 'goldenrod' });
|
|
return {
|
|
restrict: 'E',
|
|
scope: { value: '=' },
|
|
link: function(scope, element){
|
|
for (var i = 0; i < scope.value; i++){
|
|
element.append(star.clone());
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
})();
|