aboutsummaryrefslogtreecommitdiffstats
path: root/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify
diff options
context:
space:
mode:
authorChristopher Lott (cl778h) <clott@research.att.com>2017-08-17 14:52:44 -0400
committerChristopher Lott (cl778h) <clott@research.att.com>2017-08-17 14:53:24 -0400
commit9015d0d86d23a83e578ded1bd95485d467515208 (patch)
tree577556c635e60bbd8446416c2cb6492f4b583a5f /ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify
parent3a32363f46a29cfed9ed1c28053424852f54382d (diff)
Publish seed code for the OOM Dashboard
First open-source release of the ONAP Operations Manager Dashboard web application. Issue: CCSDK-61 Change-Id: I902f789692d76ee583aa967682e39f03b6578fe9 Signed-off-by: Christopher Lott (cl778h) <clott@research.att.com>
Diffstat (limited to 'ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify')
-rw-r--r--ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/blueprint-controllers.js467
-rw-r--r--ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/blueprint-service.js114
-rw-r--r--ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/blueprint_popups.html187
-rw-r--r--ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/blueprint_table.html98
-rw-r--r--ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/deployment-controllers.js371
-rw-r--r--ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/deployment-service.js89
-rw-r--r--ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/deployment_popups.html170
-rw-r--r--ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/deployment_table.html93
-rw-r--r--ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/execution-service.js110
-rw-r--r--ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/execution-table-controller.js126
-rw-r--r--ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/execution_table.html101
-rw-r--r--ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/tosca-table-controller.js106
-rw-r--r--ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/tosca_table.html87
13 files changed, 2119 insertions, 0 deletions
diff --git a/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/blueprint-controllers.js b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/blueprint-controllers.js
new file mode 100644
index 0000000..2845782
--- /dev/null
+++ b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/blueprint-controllers.js
@@ -0,0 +1,467 @@
+/*******************************************************************************
+ * =============LICENSE_START=========================================================
+ *
+ * =================================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ *******************************************************************************/
+appDS2.controller('blueprintTableController', function(
+ $rootScope, $scope, $log, $modal, modalService, BlueprintService) {
+
+ 'use strict';
+
+ // Controls logging in this controller
+ var debug = false;
+
+ // this object holds all app data and functions
+ $scope.ecdapp = {};
+ // models for controls on screen
+ $scope.ecdapp.tableData = [];
+ $scope.ecdapp.currentPageNum = 1;
+ $scope.ecdapp.viewPerPage = 10;
+ // other
+ $scope.ecdapp.errMsg = null;
+ $scope.ecdapp.isDataLoading = true;
+ $scope.ecdapp.isRequestFailed = false;
+
+ /**
+ * Loads the table. Interprets the remote controller's response and copies
+ * to scope variables. The response is either list to be assigned to
+ * tableData, or an error to be shown.
+ */
+ $scope.ecdapp.loadTable = function() {
+ $scope.ecdapp.isDataLoading = true;
+ BlueprintService.getBlueprints($scope.ecdapp.currentPageNum, $scope.ecdapp.viewPerPage)
+ .then(function(jsonObj) {
+ if (jsonObj.error) {
+ $log.error("blueprintController.loadTable failed: " + jsonObj.error);
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = jsonObj.error;
+ $scope.ecdapp.tableData = [];
+ } else {
+ if (debug)
+ $log.debug("bluePrintController.loadTable succeeded, size " + jsonObj.data.length);
+ $scope.ecdapp.isRequestFailed = false;
+ $scope.ecdapp.errMsg = null;
+ $scope.ecdapp.totalPages = jsonObj.totalPages;
+ $scope.ecdapp.tableData = jsonObj.items;
+ }
+ $scope.ecdapp.isDataLoading = false;
+ }, function(error) {
+ $log.error("blueprintController.loadTable failed: " + error);
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = error;
+ $scope.ecdapp.tableData = [];
+ $scope.ecdapp.isDataLoading = false;
+ });
+ };
+
+ /**
+ * Invoked at first page load AND when
+ * user clicks on the B2B pagination control.
+ */
+ $scope.pageChangeHandler = function(page) {
+ // console.log('pageChangeHandler: current is ' + $scope.ecdapp.currentPageNum + ' new is ' + page);
+ $scope.ecdapp.currentPageNum = page;
+ $scope.ecdapp.loadTable();
+ }
+
+ /**
+ * Shows a modal pop-up with blueprint content.
+ * Passes data in via an object named "message".
+ */
+ $scope.ecdapp.viewBlueprintModalPopup = function(blueprint) {
+ $scope.ecdapp.editBlueprint = null;
+ var modalInstance = $modal.open({
+ templateUrl : 'blueprint_view_popup.html',
+ controller : 'blueprintViewCtrl',
+ windowClass: 'modal-docked',
+ sizeClass: 'modal-medium',
+ resolve : {
+ message : function() {
+ var dataForPopup = {
+ blueprint : blueprint
+ };
+ return dataForPopup;
+ }
+ }
+ });
+ modalInstance.result.then(function(response) {
+ // No response.
+ });
+ };
+
+ /**
+ * Shows a modal pop-up to upload a blueprint.
+ * Passes data in via an object named "message".
+ * On success, updates the table.
+ */
+ $scope.ecdapp.uploadBlueprintModalPopup = function() {
+ $scope.ecdapp.editBlueprint = null;
+ var modalInstance = $modal.open({
+ templateUrl : 'blueprint_upload_popup.html',
+ controller : 'blueprintUploadCtrl',
+ windowClass: 'modal-docked',
+ sizeClass: 'modal-small',
+ resolve : {
+ message : function() {
+ var dataForPopup = {
+ blueprint : $scope.ecdapp.editBlueprint,
+ blueprintList : $scope.ecdapp.tableData,
+ };
+ return dataForPopup;
+ }
+ }
+ });
+ modalInstance.result.then(function(response) {
+ if (debug)
+ $log.debug('uploadBlueprintModalPopup: response: ' + JSON.stringify(response));
+ if (response == null) {
+ // $log.debug('user closed dialog');
+ }
+ else {
+ if (response.error != null) {
+ $log.error('uploadBlueprintModalPopup failed: ' + response.error);
+ alert('Failed to upload blueprint:\n' + response.error);
+ }
+ else {
+ // success, get the updated list.
+ $scope.ecdapp.loadTable()
+ }
+ }
+ });
+ };
+
+ /**
+ * Shows a modal pop-up to create a deployment from a blueprint.
+ * Passes data in via an object named "message".
+ */
+ $scope.ecdapp.deployBlueprintModalPopup = function(blueprint) {
+ var modalInstance = $modal.open({
+ templateUrl : 'blueprint_deploy_popup.html',
+ controller : 'blueprintDeployCtrl',
+ windowClass: 'modal-docked',
+ sizeClass: 'modal-medium',
+ resolve : {
+ message : function() {
+ var dataForPopup = {
+ blueprint : blueprint,
+ };
+ return dataForPopup;
+ }
+ }
+ });
+ modalInstance.result.then(function(response) {
+ if (debug)
+ $log.debug('deployBlueprintModalPopup: response: ' + JSON.stringify(response));
+ if (response == null) {
+ if (debug)
+ $log.debug('user closed dialog');
+ }
+ else {
+ if (response.error != null) {
+ $log.error('deployBlueprintModalPopup failed: ' + response.error);
+ alert('Failed to deploy blueprint:\n' + response.error);
+ // No need to update THIS table.
+ // Must switch to deployments page to see result? Awkward.
+ }
+ }
+ });
+ };
+
+ /**
+ * Shows a modal pop-up to confirm deletion.
+ * On successful completion, updates the table.
+ */
+ $scope.ecdapp.deleteBlueprintModalPopup = function(blueprint) {
+ modalService.popupConfirmWin("Confirm", "Delete blueprint with ID '"
+ + blueprint.id + "'?", function() {
+ BlueprintService.deleteBlueprint(blueprint.id).then(
+ function(response) {
+ if (debug)
+ $log.debug('deleteBlueprintModalPopup: response: ' + JSON.stringify(response));
+ if (response && response.error) {
+ // $log.error('deleteBlueprint failed: ' + response.error);
+ alert('Failed to delete blueprint:\n' + response.error);
+ }
+ else {
+ // No response body on success.
+ $scope.ecdapp.loadTable();
+ }
+ },
+ function(error) {
+ $log.error('BlueprintService.deleteBlueprint failed: ' + error);
+ alert('Service failed to delete blueprint:\n' + error);
+ });
+ })
+ };
+
+ // Populate the table on load. Note that the b2b selector code
+ // sets the page-number value, and the change event calls load table.
+ // Do not call this here to avoid double load:
+ // $scope.ecdapp.loadTable();
+
+});
+
+/*************************************************************************/
+
+appDS2.controller('blueprintUploadCtrl', function(
+ $scope, $log, $modalInstance, message, BlueprintService) {
+
+ 'use strict';
+
+ // this object holds all app data and functions
+ $scope.ecdapp = {};
+
+ $scope.ecdapp.label = 'Upload Blueprint';
+ $scope.ecdapp.uploadRequest =
+ {
+ blueprint_id : '',
+ blueprint_filename : '',
+ zip_url : ''
+ };
+
+ /**
+ * Validates content of user-editable fields.
+ * Uses the list in message.feedList
+ * Returns null if all is well,
+ * a descriptive error message otherwise.
+ */
+ $scope.ecdapp.validateRequest = function(uploadRequest) {
+ if (uploadRequest == null)
+ return "No data found.\nPlease enter some values.";
+ if (uploadRequest.blueprint_id == null || uploadRequest.blueprint_id.trim() == '')
+ return "ID is required.\nPlease enter a value.";
+ if (uploadRequest.blueprint_filename == null || uploadRequest.blueprint_filename.trim() == '')
+ return "File name is required.\nPlease enter a value.";
+ if (uploadRequest.blueprint_filename.toLowerCase().substr(-4) != 'yaml')
+ return "File name must end with YAML.\nPlease use that suffix.";
+ if (uploadRequest.zip_url == null || uploadRequest.zip_url.trim() == '')
+ return "Zip file URL is required.\nPlease enter a value.";
+ return null;
+ }
+
+ $scope.ecdapp.uploadBlueprint = function(uploadRequest) {
+ var validateMsg = $scope.ecdapp.validateRequest(uploadRequest);
+ if (validateMsg != null) {
+ alert('Invalid upload request:\n' + validateMsg);
+ return;
+ }
+ BlueprintService.uploadBlueprint(uploadRequest)
+ .then(function(response) {
+ // $log.debug('blueprintPopupCtrl: response: ' + response);
+ if (response.error)
+ alert('Failed to upload blueprint:\n' + response.error);
+ else
+ $modalInstance.close(response);
+ },
+ function (error) {
+ $log.error('blueprintUploadCtrl: error while uploading: ' + error);
+ alert('Server rejected upload request:\n' + error);
+ }
+ );
+
+ };
+
+});
+
+/*************************************************************************/
+
+appDS2.controller('blueprintViewCtrl', function(
+ $scope, $log, message, BlueprintService) {
+
+ 'use strict';
+
+ var debug = false;
+
+ if (debug)
+ $log.debug("blueprintViewCtrl.message: " + JSON.stringify(message));
+
+ // this object holds all app data and functions
+ $scope.ecdapp = {};
+ $scope.ecdapp.blueprintId = message.blueprint.id;
+
+ $scope.ecdapp.label = 'View Blueprint ' + message.blueprint.id;
+
+ // Fetch the blueprint
+ $scope.ecdapp.isDataLoading = true;
+ BlueprintService.viewBlueprint(message.blueprint.id).then(function(jsonObj) {
+ if (debug)
+ $log.debug("blueprintViewCtrl.viewBlueprint response: " + JSON.stringify(jsonObj));
+ if (jsonObj.error) {
+ $scope.ecdapp.errMsg = 'Request Failed';
+ }
+ else {
+ $scope.ecdapp.blueprint = jsonObj.content;
+ }
+ $scope.ecdapp.isDataLoading = false;
+ }, function(error) {
+ $scope.ecdapp.isDataLoading = false;
+ alert('Failed to get blueprint. Please retry.');
+ $log.error("blueprintViewCtrl failed: " + error);
+ });
+
+});
+
+
+/*************************************************************************/
+
+appDS2.controller('blueprintDeployCtrl', function(
+ $scope, $log, $modalInstance, message, DeploymentService) {
+
+ 'use strict';
+
+ // Controls logging in this controller
+ var debug = false;
+
+ // this object holds all app data and functions
+ $scope.ecdapp = {};
+ $scope.ecdapp.label = 'Deploy Blueprint';
+
+ // Cache the input parameter names for validation
+ if (debug)
+ $log.debug('blueprintDeployCtrl: inputs: ' + JSON.stringify(message.blueprint.plan.inputs));
+ $scope.ecdapp.inputsDict = message.blueprint.plan.inputs;
+
+ // Copy the input parameter names and default values
+ let inputsAndDefaults = {};
+ for (var pkey in message.blueprint.plan.inputs) {
+ if (debug)
+ $log.debug('blueprintDeployCtrl: checking key ' + pkey);
+ let dval = message.blueprint.plan.inputs[pkey].default;
+ if (! dval)
+ dval = '';
+ inputsAndDefaults[pkey] = dval;
+ }
+ if (debug)
+ $log.debug('blueprintDeployCtrl: inputsAndDefaults: ' + JSON.stringify(inputsAndDefaults));
+
+ // Create an object for edit
+ $scope.ecdapp.editRequest = {
+ deployment_id : '',
+ blueprint_id : message.blueprint.id,
+ fileModel : null,
+ parmFileDict : inputsAndDefaults
+ };
+
+ /**
+ * Handler for file-read event reads file, parses YAML, validates content.
+ */
+ var fileReader = new FileReader();
+ fileReader.onload = function(event) {
+ let yamlString = fileReader.result;
+ if (debug)
+ $log.debug('fileReader.onload: read: ' + yamlString);
+ let ydict = {};
+ try {
+ ydict = YAML.parse(yamlString);
+ }
+ catch (ex) {
+ alert('Failed to parse file as YAML:\n' + ex);
+ }
+ // Process the file
+ for (var ykey in ydict) {
+ let yval = ydict[ykey];
+ if (debug)
+ $log.debug('fileReader.onload: typeof ' + ykey + ' is ' + typeof ykey);
+ // Allow only expected keys with scalar values
+ if (! (ykey in $scope.ecdapp.editRequest.parmFileDict))
+ alert('Unexpected file content:\nKey not defined by blueprint:\n' + ykey);
+ else if (typeof yval !== 'string' && typeof yval !== 'number')
+ alert('Unexpected file content:\nNot a simple key-value pair:\n' + ykey);
+ else
+ $scope.ecdapp.editRequest.parmFileDict[ykey] = yval;
+ }
+ if (debug)
+ $log.debug('fileReader.onload: parmFileDict: ' + JSON.stringify($scope.ecdapp.editRequest.parmFileDict));
+
+ // Update table in all cases
+ $scope.$apply();
+ }
+
+ // Handler for file-select event
+ $scope.handleFileSelect = function() {
+ if (debug)
+ $log.debug('handleFileSelect: $scope.ecdapp.fileModel.name is ' + $scope.ecdapp.editRequest.fileModel.name);
+ fileReader.readAsText($scope.ecdapp.editRequest.fileModel);
+ };
+
+ /**
+ * Validates content of user-editable fields.
+ * Returns null if all is well,
+ * a descriptive error message otherwise.
+ */
+ $scope.ecdapp.validateRequest = function(editRequest) {
+ if (editRequest == null)
+ return 'No data found.\nPlease enter some values.';
+ if (editRequest.deployment_id == null || editRequest.deployment_id.trim() == '')
+ return 'Deployment ID is required.\nPlease enter a value.';
+ if (editRequest.blueprint_id == null || editRequest.blueprint_id.trim() == '')
+ return 'Blueprint ID is required.\nPlease enter a value.';
+ // Check that every file parameter is defined by blueprint
+ for (var pkey in $scope.ecdapp.editRequest.parmFileDict) {
+ // Defined in blueprint?
+ if (! $scope.ecdapp.inputsDict[pkey])
+ return 'Unexpected input parameter\n' + pkey;
+ // Populated?
+ let parmVal = $scope.ecdapp.editRequest.parmFileDict[pkey];
+ if (parmVal == null || (typeof (parmVal) === 'string' && parmVal.trim().length == 0))
+ return 'Missing value for parameter\n' + pkey;
+ }
+ // Check that a value is supplied for every expected input
+ for (var bkey in $scope.ecdapp.inputsDict) {
+ if (! $scope.ecdapp.editRequest.parmFileDict[bkey])
+ return 'Missing input parameter\n' + bkey;
+ }
+ return null;
+ }
+
+ $scope.ecdapp.deployBlueprint = function(editRequest) {
+ if (debug)
+ $log.debug('deployBlueprint: editRequest is ' + JSON.stringify($scope.ecdapp.editRequest));
+ var validateMsg = $scope.ecdapp.validateRequest(editRequest);
+ if (validateMsg != null) {
+ alert('Invalid Request:\n' + validateMsg);
+ return;
+ }
+ // Create request with key:value parameters dictionary
+ let deployRequest = {
+ deployment_id : editRequest.deployment_id,
+ blueprint_id : editRequest.blueprint_id,
+ parameters : {}
+ };
+ for (var pkey in $scope.ecdapp.editRequest.parmFileDict)
+ deployRequest.parameters[pkey] = $scope.ecdapp.editRequest.parmFileDict[pkey];
+ if (debug)
+ $log.debug('deployBlueprint: deployRequest is ' + JSON.stringify(deployRequest));
+
+ DeploymentService.deployBlueprint(deployRequest)
+ .then(function(response) {
+ if (response.error)
+ alert('Failed to deploy blueprint:\n' + response.error);
+ else
+ $modalInstance.close(response);
+ },
+ function (error) {
+ $log.error('blueprintDeployCtrl: error while deploying: ' + error);
+ alert('Server rejected deployment request:\n' + error);
+ }
+ );
+
+ };
+
+});
diff --git a/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/blueprint-service.js b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/blueprint-service.js
new file mode 100644
index 0000000..422e53d
--- /dev/null
+++ b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/blueprint-service.js
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * =============LICENSE_START=========================================================
+ *
+ * =================================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ *******************************************************************************/
+appDS2.factory('BlueprintService', function ($http, $q, $log) {
+ return {
+ /**
+ * Gets one page of blue prints objects.
+ * @param {Number} pageNum - page number; e.g., 1
+ * @param {Number} viewPerPage - number of items per page; e.g., 25
+ * @return {JSON} Response object from remote side
+ */
+ getBlueprints: function(pageNum,viewPerPage) {
+ // cache control for IE
+ let cc = "&cc=" + new Date().getTime().toString();
+ let url = 'blueprints?pageNum=' + pageNum + '&viewPerPage=' + viewPerPage + cc;
+ return $http({
+ method: 'GET',
+ url: url,
+ cache: false,
+ responseType: 'json'
+ }).then(function(response) {
+ if (response.data == null || typeof response.data != 'object')
+ return $q.reject('BlueprintService.getBlueprints: response.data null or not object');
+ else
+ return response.data;
+ },
+ function(error) {
+ $log.error('BlueprintService.getBlueprints failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+
+ /**
+ * Gets blueprint content.
+ * @return {JSON} Response object from remote side
+ */
+ viewBlueprint: function(id) {
+ // cache control for IE
+ let url = 'viewblueprints/' + id;
+ return $http({
+ method: 'GET',
+ url: url,
+ cache: false,
+ responseType: 'json'
+ }).then(function(response) {
+ if (response.data == null || typeof response.data != 'object')
+ return $q.reject('BlueprintService.viewBlueprint: response.data null or not object');
+ else
+ return response.data;
+ },
+ function(error) {
+ $log.error('BlueprintService.viewBlueprint failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+
+ uploadBlueprint: function(uploadRequest) {
+ let url = 'blueprints';
+ return $http({
+ method: 'POST',
+ url: url,
+ data: uploadRequest,
+ responseType: 'json'
+ }).then(function(response) {
+ if (response.data == null || typeof response.data != 'object')
+ return $q.reject('BlueprintService.uploadBlueprint: response.data null or not object');
+ else
+ return response.data;
+ },
+ function(error) {
+ $log.error('BlueprintService.uploadBlueprint failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+
+ deleteBlueprint: function(id) {
+ let url = 'blueprints/' + id;
+ return $http({
+ method: 'DELETE',
+ url: url,
+ cache: false,
+ responseType: 'json'
+ }).then(function(response) {
+ // This is called on response code 200..299.
+ // On success, response.data is null.
+ // On failure, response.data has an error message.
+ return response.data;
+ },
+ function(error) {
+ $log.error('BlueprintService.deleteBlueprint failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+
+ };
+});
diff --git a/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/blueprint_popups.html b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/blueprint_popups.html
new file mode 100644
index 0000000..ee92d84
--- /dev/null
+++ b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/blueprint_popups.html
@@ -0,0 +1,187 @@
+<script type="text/ng-template" id="blueprint_upload_popup.html">
+
+ <div class="b2b-modal-header ng-scope">
+ <h2 id="myModalLabel" modal-title="">{{ecdapp.label}}</h2>
+ <div class="corner-button in">
+ <button type="button" class="close" aria-label="Close"
+ ng-click="$dismiss('cancel')"></button>
+ </div>
+ </div>
+
+ <div class="b2b-modal-body ng-scope ng-isolate-scope" tabindex="0"
+ role="region" aria-label="Modal body content">
+
+ <div class="row-nowrap">
+ <div class="span12">
+ <div class="form-row">
+ <label for="blueprintId">*Blueprint ID</label>
+ <div class="field-group">
+ <!--autofocus is HTML5 attribute; doesn't work in Firefox-->
+ <input id="blueprintId" class="span12" type="text" data-ng-model="ecdapp.editBlueprint.blueprint_id" autofocus>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="row-nowrap">
+ <div class="span12">
+ <div class="form-row">
+ <label for="blueprintFileName">*File Name</label>
+ <div class="field-group">
+ <input id="blueprintFileName" class="span12" type="text" data-ng-model="ecdapp.editBlueprint.blueprint_filename">
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="row-nowrap">
+ <div class="span12">
+ <div class="form-row">
+ <label for="zipFileUrl">*Zip File URL</label>
+ <div class="field-group">
+ <input id="zipFileUrl" class="span12" type="text" data-ng-model="ecdapp.editBlueprint.zip_url">
+ </div>
+ </div>
+ </div>
+ </div>
+
+ </div>
+
+ <div class="b2b-modal-footer ng-scope ng-isolate-scope">
+ <div class="cta-button-group in">
+ <button class="btn btn-alt btn-small" type="button"
+ ng-click="ecdapp.uploadBlueprint(ecdapp.editBlueprint);">
+ Save
+ </button>
+ <button class="btn btn-small" type="button"
+ ng-click="$dismiss('cancel')">
+ Cancel
+ </button>
+ </div>
+ </div>
+
+</script>
+
+<script type="text/ng-template" id="blueprint_view_popup.html">
+
+ <div class="b2b-modal-header ng-scope">
+ <h2 id="myModalLabel" modal-title="">{{ecdapp.label}}</h2>
+ <div class="corner-button in">
+ <button type="button" class="close" aria-label="Close"
+ ng-click="$dismiss('cancel')"></button>
+ </div>
+ </div>
+
+ <div class="b2b-modal-body ng-scope ng-isolate-scope" tabindex="0"
+ role="region" aria-label="Modal body content">
+
+ <!-- show progress indicator -->
+ <div ng-show="ecdapp.isDataLoading">
+ <div class="span" style="margin-bottom:20px;">
+ <i class="icon-primary-spinner small" role="img" aria-label="Please wait while the content loads"></i>
+ Please wait while the content loads.
+ </div>
+ </div>
+
+ <div ng-show="ecdapp.errMsg">
+ <span class="ecd-error-message">{{ecdapp.errMsg}}</span>
+ </div>
+
+ <div ng-hide="ecdapp.errMsg">
+ <pre>{{ecdapp.blueprint}}</pre>
+ </div>
+
+ </div>
+
+ <div class="b2b-modal-footer ng-scope ng-isolate-scope">
+ <div class="cta-button-group in">
+ <button class="btn btn-alt btn-small" type="button"
+ ng-click="$dismiss('cancel');">
+ Close
+ </button>
+ </div>
+ </div>
+
+</script>
+
+<script type="text/ng-template" id="blueprint_deploy_popup.html">
+
+ <style>
+ .ecd-parameter-table
+ {
+ border: 1px;
+ overflow: auto;
+ }
+ .ecd-parameter-table th
+ {
+ font-size: 1.4rem;
+ }
+ </style>
+
+ <div class="b2b-modal-header ng-scope">
+ <h2 id="myModalLabel" modal-title="">{{ecdapp.label}}</h2>
+ <div class="corner-button in">
+ <button type="button" class="close" aria-label="Close"
+ ng-click="$dismiss('cancel')"></button>
+ </div>
+ </div>
+
+ <div class="b2b-modal-body ng-scope ng-isolate-scope" tabindex="0"
+ role="region" aria-label="Modal body content">
+
+ <div class="row-nowrap">
+ <div class="span12">
+ <label for="blueprintFileName">*Deployment ID</label>
+ <!--autofocus is HTML5 attribute; doesn't work in Firefox-->
+ <input id="blueprintFileName" class="span12" type="text" data-ng-model="ecdapp.editRequest.deployment_id" autofocus/>
+ </div>
+ <div class="span12">
+ <label for="blueprintId">Blueprint ID</label>
+ <!--not editable-->
+ <input id="blueprintId" class="span12" type="text" disabled="disabled" data-ng-model="ecdapp.editRequest.blueprint_id"/>
+ </div>
+ </div>
+
+ <div class="row-nowrap">
+ <div class="span12">
+ <div class="form-row">
+ <label for="parameters">*Parameters</label>
+ <div b2b-file-drop file-model="ecdapp.editRequest.fileModel" on-drop="handleFileSelect()" align="center">
+ <span b2b-file-link file-model="ecdapp.editRequest.fileModel" on-file-select="handleFileSelect()" >
+ Drag &amp; drop a parameters YAML file here, or click to browse.
+ </span>
+ </div>
+ </div>
+ <div class="ecd-parameter-table">
+ <table id="parameters">
+ <tr id="ecd-table-header">
+ <th width="40%">Name</th>
+ <th width="60%">Value</th>
+ </tr>
+ <tbody ng-repeat="(pkey, pval) in ecdapp.editRequest.parmFileDict">
+ <tr id="tr-rowData">
+ <td ng-bind="pkey"/>
+ <td ng-bind="pval"/>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+
+ </div>
+
+ <div class="b2b-modal-footer ng-scope ng-isolate-scope">
+ <div class="cta-button-group in">
+ <button class="btn btn-alt btn-small" type="button"
+ ng-click="ecdapp.deployBlueprint(ecdapp.editRequest);">
+ Save
+ </button>
+ <button class="btn btn-small" type="button"
+ ng-click="$dismiss('cancel')">
+ Cancel
+ </button>
+ </div>
+ </div>
+
+</script>
diff --git a/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/blueprint_table.html b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/blueprint_table.html
new file mode 100644
index 0000000..3ce60b9
--- /dev/null
+++ b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/blueprint_table.html
@@ -0,0 +1,98 @@
+<div id="page-content">
+
+ <h1 class="heading-page" id="blueprints-page">Blueprints</h1>
+
+ <!-- show progress indicator -->
+ <div ng-show="ecdapp.isDataLoading">
+ <div class="span" style="margin-bottom:20px;">
+ <i class="icon-primary-spinner small" role="img" aria-label="Please wait while the content loads"></i>
+ Please wait while the content loads.
+ </div>
+ </div>
+
+ <div ng-hide="ecdapp.isDataLoading">
+
+ <div id="button-search-row">
+ <button class="btn btn-alt btn-small"
+ type="submit"
+ ng-click="ecdapp.uploadBlueprintModalPopup();">
+ Upload Blueprint...
+ </button>
+ <div style="float:right;">
+ <div class="form-field form-field__small">
+ <input
+ type="text"
+ placeholder="Search Blueprints"
+ ng-model="ecdapp.searchString"/>
+ </div>
+ </div>
+ </div>
+
+ <div ng-show="ecdapp.isRequestFailed">
+ <span class="ecd-error-message">{{ecdapp.errMsg}}</span>
+ </div>
+
+ <div ng-hide="ecdapp.isRequestFailed">
+
+ <div
+ b2b-table
+ id="blueprints-table"
+ class="b2b-table-div"
+ table-data="ecdapp.tableData"
+ search-string="ecdapp.searchString"
+ current-page="ecdapp.currentPageIgnored"
+ next-sort="ecdapp.nextSortIgnored">
+
+ <table>
+
+ <thead b2b-table-row type="header">
+ <tr id="th-header-row">
+ <th b2b-table-header key="id">ID</th>
+ <th b2b-table-header key="main_file_name">File Name</th>
+ <th b2b-table-header key="description">Description</th>
+ <th b2b-table-header key="created_at">Created Date</th>
+ <th b2b-table-header key="updated_at">Updated Date</th>
+ <th b2b-table-header sortable="false"><i class="icon-controls-gear ecd-icon-display"></i></th>
+ </tr>
+ </thead>
+
+ <tbody b2b-table-row type="body" row-repeat="rowData in ecdapp.tableData">
+ <tr id="tr-rowData">
+ <td b2b-table-body
+ ng-bind="rowData.id"/>
+ <td b2b-table-body
+ ng-bind="rowData.main_file_name"/>
+ <td b2b-table-body
+ ng-bind="rowData.description"/>
+ <td b2b-table-body
+ ng-bind="rowData.created_at"/>
+ <td b2b-table-body
+ ng-bind="rowData.updated_at"/>
+ <td b2b-table-body>
+ <div ng-click="ecdapp.viewBlueprintModalPopup(rowData);">
+ <a href="" title="View blueprint" class="icon-people-preview ecd-icon-action"></a>
+ </div>
+ <div ng-click="ecdapp.deployBlueprintModalPopup(rowData);">
+ <a href="" title="Deploy blueprint" class="icon-datanetwork-cloudupload ecd-icon-action"></a>
+ </div>
+ <div ng-click="ecdapp.deleteBlueprintModalPopup(rowData);">
+ <a href="" title="Delete blueprint" class="icon-misc-trash ecd-icon-action"></a>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
+ <div b2b-pagination="" total-pages="ecdapp.totalPages"
+ current-page="ecdapp.currentPageNum" click-handler="pageChangeHandler"
+ role="navigation">
+ </div>
+
+ <div style="height: 10px;">
+ <!-- space between page number and black footer -->
+ </div>
+
+ </div><!-- loading -->
+
+</div><!-- page content -->
diff --git a/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/deployment-controllers.js b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/deployment-controllers.js
new file mode 100644
index 0000000..b46d242
--- /dev/null
+++ b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/deployment-controllers.js
@@ -0,0 +1,371 @@
+/*******************************************************************************
+ * =============LICENSE_START=========================================================
+ *
+ * =================================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ *******************************************************************************/
+appDS2.controller('deploymentTableController', function(
+ $rootScope, $scope, $log, $modal, DeploymentService) {
+
+ 'use strict';
+
+ // Controls logging in this controller
+ var debug = false;
+
+ // this object holds all app data and functions
+ $scope.ecdapp = {};
+ // models for controls on screen
+ $scope.ecdapp.tableData = [];
+ $scope.ecdapp.currentPageNum = 1;
+ $scope.ecdapp.viewPerPage = 10;
+ // other
+ $scope.ecdapp.errMsg = null;
+ $scope.ecdapp.isDataLoading = true;
+ $scope.ecdapp.isRequestFailed = false;
+
+ /**
+ * Loads the table. Interprets the remote controller's response and copies
+ * to scope variables. The response is either a list to be assigned to
+ * tableData, or an error to be shown.
+ */
+ $scope.ecdapp.loadTable = function() {
+ $scope.ecdapp.isDataLoading = true;
+ DeploymentService.getDeployments($scope.ecdapp.currentPageNum,
+ $scope.ecdapp.viewPerPage).then(
+ function(jsonObj) {
+ if (jsonObj.error) {
+ $log.error("deploymentController.loadTable failed: "
+ + jsonObj.error);
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = jsonObj.error;
+ $scope.ecdapp.tableData = [];
+ } else {
+ $scope.ecdapp.isRequestFailed = false;
+ $scope.ecdapp.errMsg = null;
+ $scope.ecdapp.totalPages = jsonObj.totalPages;
+ $scope.ecdapp.tableData = jsonObj.items;
+ }
+ $scope.ecdapp.isDataLoading = false;
+ },
+ function(error) {
+ $log.error("deploymentController.loadTable failed: "
+ + error);
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = error;
+ $scope.ecdapp.tableData = [];
+ $scope.ecdapp.isDataLoading = false;
+ });
+ };
+
+ /**
+ * Invoked at first page load AND when
+ * user clicks on the B2B pagination control.
+ */
+ $scope.pageChangeHandler = function(page) {
+ // console.log('pageChangeHandler: current is ' + $scope.ecdapp.currentPageNum + ' new is ' + page);
+ $scope.ecdapp.currentPageNum = page;
+ $scope.ecdapp.loadTable();
+ }
+
+ /**
+ * Shows a modal pop-up to create an execution from a deployment.
+ * Passes data in via an object named "message".
+ * On success, updates the table.
+ */
+ $scope.ecdapp.createExecutionModalPopup = function(deployment) {
+ var modalInstance = $modal.open({
+ templateUrl : 'deployment_execute_popup.html',
+ controller : 'deploymentExecuteCtrl',
+ windowClass: 'modal-docked',
+ sizeClass: 'modal-large',
+ resolve : {
+ message : function() {
+ var dataForPopup = {
+ deployment : deployment,
+ };
+ return dataForPopup;
+ }
+ }
+ });
+ modalInstance.result.then(function(response) {
+ if (debug)
+ $log.debug('createExecutionModalPopup: response: ' + JSON.stringify(response));
+ if (response == null) {
+ // $log.debug('user closed dialog');
+ }
+ else {
+ if (response.error != null) {
+ $log.error('createExecutionModalPopup: failed to delete: ' + error);
+ alert('Failed to create execution:\n' + response.error);
+ // No need to update THIS table.
+ // Must switch to executions page to see result? Awkward.
+ }
+ }
+ });
+ };
+
+ /**
+ * Shows a modal pop-up to confirm deletion.
+ * On successful completion, updates the table.
+ */
+ $scope.ecdapp.deleteDeploymentModalPopup = function(deployment) {
+ var modalInstance = $modal.open({
+ templateUrl : 'deployment_delete_popup.html',
+ controller : 'deploymentDeleteCtrl',
+ sizeClass: 'modal-small',
+ resolve : {
+ message : function() {
+ var dataForPopup = {
+ deployment : deployment,
+ };
+ return dataForPopup;
+ }
+ }
+ });
+ modalInstance.result.then(function(response) {
+ if (debug)
+ $log.debug('deleteDeploymentPopup: response: ' + JSON.stringify(response));
+ if (response == null) {
+ // $log.debug('user closed dialog');
+ }
+ else {
+ if (response.error != null) {
+ $log.error('deleteDeploymentModalPopup failed: ' + response.error);
+ alert('Failed to delete deployment:\n' + response.error);
+ }
+ else {
+ // success, get the updated list.
+ $scope.ecdapp.loadTable()
+ }
+ }
+ });
+ };
+
+});
+
+/*************************************************************************/
+
+appDS2.controller('deploymentDeleteCtrl', function(
+ $scope, $log, $modalInstance, message, DeploymentService) {
+
+ 'use strict';
+
+ // Controls logging in this controller
+ var debug = false;
+
+ // this object holds all app data and functions
+ $scope.ecdapp = {};
+ $scope.ecdapp.label = 'Delete Deployment';
+ $scope.ecdapp.deploymentId = message.deployment.id;
+ $scope.ecdapp.ignoreLiveNodes = false;
+
+ $scope.ecdapp.deleteDeploymentById = function(){
+ DeploymentService.deleteDeployment($scope.ecdapp.deploymentId, $scope.ecdapp.ignoreLiveNodes).then(
+ function(response) {
+ if (debug)
+ $log.debug('deploymentDeleteCtrl.deleteDeployment: ' + JSON.stringify(response));
+ if (response && response.error) {
+ $log.error('DeploymentService.deleteDeployment failed: ' + response.error);
+ alert('Failed to delete deployment:\n' + response.error);
+ }
+ else {
+ // Delete service returns null on success.
+ $modalInstance.close("success");
+ }
+ },
+ function(error) {
+ $log.error('DeploymentService.deleteDeployment failed: ' + error);
+ alert('Service failed to delete deployment:\n' + error);
+ });
+ }
+
+});
+
+/*************************************************************************/
+
+appDS2.controller('deploymentExecuteCtrl', function(
+ $scope, $log, $modalInstance, message, ExecutionService) {
+
+ 'use strict';
+
+ // Controls logging in this controller
+ var debug = false;
+
+ // this object holds all app data and functions
+ $scope.ecdapp = {};
+ $scope.ecdapp.label = 'Execute Deployment';
+
+ // Cache the input parameter names for validation
+ $scope.ecdapp.inputsDict = {};
+ if (debug)
+ $log.debug('DeploymentXeqCtrl: inputsDict is ' + JSON.stringify($scope.ecdapp.inputsDict));
+
+ // Copy the input names and values
+ // (different structure than blueprint)
+ /*for (var pkey in message.deployment.inputs) {
+ let dval = message.deployment.inputs[pkey];
+ inputsAndValues[pkey] = dval;
+ }*/
+
+ // Gather workflow names as a simple list
+ var workflowList = [];
+ for (var i = 0; i < message.deployment.workflows.length; i++)
+ workflowList.push(message.deployment.workflows[i].name);
+ if (debug)
+ $log.debug('DeploymentXeqCtrl: workflowList is ' + JSON.stringify(workflowList));
+
+ // Create an object for edit.
+ $scope.ecdapp.editRequest = {
+ deployment_id : message.deployment.id,
+ allow_custom_parameter : false,
+ force : false,
+ // Has title and value objects
+ workflow_name: { value : '' },
+ workflow_list : workflowList,
+ fileModel : null,
+ parmFileDict : {}
+ };
+
+ $scope.selectWorkflowName = function(){
+ var workflows = message.deployment.workflows;
+ let inputsAndValues = {};
+ var res = workflows.filter(function(d){
+ if(d.name == $scope.ecdapp.editRequest.workflow_name.value){
+ return d
+ }
+ });
+ for(var key in res[0].parameters){
+ inputsAndValues[key] = typeof (res[0].parameters[key].default) === 'string' ? res[0].parameters[key].default : null;
+ }
+ $scope.ecdapp.inputsDict = inputsAndValues;
+ $scope.ecdapp.editRequest.parmFileDict = inputsAndValues;
+ };
+
+ if (debug)
+ $log.debug('DeploymentXeqCtrl: editRequest is ' + JSON.stringify($scope.ecdapp.editRequest));
+
+ /**
+ * Handler for file-read event reads file, parses YAML, validates content.
+ */
+ var fileReader = new FileReader();
+ fileReader.onload = function(event) {
+ let yamlString = fileReader.result;
+ if (debug)
+ $log.debug('fileReader.onload: read: ' + yamlString);
+ let ydict = {};
+ try {
+ ydict = YAML.parse(yamlString);
+ }
+ catch (ex) {
+ alert('Failed to parse file as YAML:\n' + ex);
+ }
+ for (var ykey in ydict) {
+ let yval = ydict[ykey];
+ if (debug)
+ $log.debug('fileReader.onload: typeof ' + ykey + ' is ' + typeof ykey);
+ // Only accept valid, expected key-value pairs
+ if (typeof yval !== 'string' && typeof yval!=='number')
+ alert('Unexpected file content:\nNot a simple key-value pair:\n' + ykey);
+ else if (! (ykey in $scope.ecdapp.editRequest.parmFileDict))
+ alert('Unexpected file content:\nKey not defined by deployment:\n' + ykey);
+ else
+ $scope.ecdapp.editRequest.parmFileDict[ykey] = yval;
+ }
+ if (debug)
+ $log.debug('fileReader.onload: parmFileDict: ' + JSON.stringify($scope.ecdapp.editRequest.parmFileDict));
+
+ // Update table in all cases
+ $scope.$apply();
+ }
+
+ // Handler for file-select event
+ $scope.handleFileSelect = function() {
+ if (debug)
+ $log.debug('handleFileSelect: $scope.ecdapp.fileModel.name is ' + $scope.ecdapp.editRequest.fileModel.name);
+ fileReader.readAsText($scope.ecdapp.editRequest.fileModel);
+ };
+
+ /**
+ * Validates content of user-editable fields.
+ * Returns null if all is well,
+ * a descriptive error message otherwise.
+ */
+ var validateRequest = function(editRequest) {
+ if (debug)
+ $log.debug('validateRequest: editRequest is ' + JSON.stringify(editRequest));
+ if (editRequest == null)
+ return "No data found.\nPlease enter some values.";
+ if (editRequest.deployment_id == null || editRequest.deployment_id.trim() == '')
+ return "Deployment ID is required.\nPlease enter a value.";
+ if (editRequest.workflow_name.value == null || editRequest.workflow_name.value.trim() == '')
+ return "Workflow name is required.\nPlease select a workflow.";
+ // Check that every file parameter is defined by blueprint
+ for (var pkey in $scope.ecdapp.editRequest.parmFileDict) {
+ // Defined in blueprint?
+ if (! $scope.ecdapp.inputsDict[pkey])
+ return 'Unexpected input parameter\n' + pkey;
+ // Populated?
+ let parmVal = $scope.ecdapp.editRequest.parmFileDict[pkey];
+ if (parmVal.trim().length == 0)
+ return 'Missing value for parameter ' + pkey;
+ }
+ // Check that a value is supplied for every expected input
+ for (var bkey in $scope.ecdapp.inputsDict) {
+ if (! $scope.ecdapp.editRequest.parmFileDict[bkey])
+ return 'Missing input parameter\n' + bkey;
+ }
+ return null;
+ }
+
+ $scope.ecdapp.executeDeployment = function(editRequest) {
+ var validateMsg = validateRequest(editRequest);
+ if (validateMsg != null) {
+ alert('Invalid execution request:\n' + validateMsg);
+ return;
+ }
+
+ // Create request with key:value parameters dictionary
+ let executeRequest = {
+ deployment_id : editRequest.deployment_id,
+ workflow_name : editRequest.workflow_name.value,
+ allow_custom_parameter : editRequest.allow_custom_parameter,
+ force : editRequest.force,
+ parameters : {}
+ };
+ for (var pkey in $scope.ecdapp.editRequest.parmFileDict)
+ executeRequest.parameters[pkey] = $scope.ecdapp.editRequest.parmFileDict[pkey];
+ if (debug)
+ $log.debug('executeDeployment: executeRequest is ' + JSON.stringify(executeRequest));
+
+ ExecutionService.executeDeployment(executeRequest)
+ .then(function(response) {
+ if (response.error)
+ alert('Failed to create execution:\n' + response.error);
+ else
+ $modalInstance.close(response);
+ },
+ function (error) {
+ $log.error('deploymentExecuteCtrl: error while creating execution: ' + error);
+ alert('Server rejected execute request:\n' + error);
+ }
+ );
+
+ };
+
+});
+
diff --git a/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/deployment-service.js b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/deployment-service.js
new file mode 100644
index 0000000..886cba1
--- /dev/null
+++ b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/deployment-service.js
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * =============LICENSE_START=========================================================
+ *
+ * =================================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ *******************************************************************************/
+appDS2.factory('DeploymentService', function ($http, $q, $log) {
+ return {
+ /**
+ * Gets one page of objects.
+ * @param {Number} pageNum - page number; e.g., 1
+ * @param {Number} viewPerPage - number of items per page; e.g., 25
+ * @return {JSON} Response object from remote side
+ */
+ getDeployments: function(pageNum,viewPerPage) {
+ // cache control for IE
+ let cc = "&cc=" + new Date().getTime().toString();
+ let url = 'deployments?pageNum=' + pageNum + '&viewPerPage=' + viewPerPage + cc;
+ return $http({
+ method: 'GET',
+ url: url,
+ cache: false,
+ responseType: 'json'
+ }).then(function(response) {
+ if (response.data == null || typeof response.data != 'object')
+ return $q.reject('DeploymentService.getDeployments: response.data null or not object');
+ else
+ return response.data;
+ },
+ function(error) {
+ $log.error('DeploymentService.getDeployments failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+
+ deployBlueprint: function(deployRequest) {
+ let url = 'deployments';
+ return $http({
+ method: 'POST',
+ url: url,
+ data: deployRequest,
+ responseType: 'json'
+ }).then(function(response) {
+ if (response.data == null || typeof response.data != 'object')
+ return $q.reject('DeploymentService.deployBlueprint: response.data null or not object');
+ else
+ return response.data;
+ },
+ function(error) {
+ $log.error('DeploymentService.deployBlueprint failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+
+ deleteDeployment: function(id, forceDelete) {
+ let url = 'deployments/' + id + '?ignore_live_nodes=' + forceDelete;
+ return $http({
+ method: 'DELETE',
+ url: url,
+ cache: false,
+ responseType: 'json'
+ }).then(function(response) {
+ // This is called on response code 200..299.
+ // On success, response.data is null.
+ // On failure, response.data has an error message.
+ return response.data;
+ },
+ function(error) {
+ $log.error('DeploymentService.deleteDeployment failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+ };
+});
diff --git a/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/deployment_popups.html b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/deployment_popups.html
new file mode 100644
index 0000000..f4a4cdd
--- /dev/null
+++ b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/deployment_popups.html
@@ -0,0 +1,170 @@
+<script type="text/ng-template" id="deployment_execute_popup.html">
+
+ <style>
+ .ecd-parameter-table
+ {
+ border: 0px;
+ overflow: auto;
+ }
+ .ecd-parameter-table th
+ {
+ font-size: 1.4rem;
+ }
+ </style>
+
+ <div class="b2b-modal-header ng-scope">
+ <h2 id="myModalLabel" modal-title="">{{ecdapp.label}}</h2>
+ <div class="corner-button in">
+ <button type="button" class="close" aria-label="Close"
+ ng-click="$dismiss('cancel')"></button>
+ </div>
+ </div>
+
+ <div class="b2b-modal-body ng-scope ng-isolate-scope" tabindex="0"
+ role="region" aria-label="Modal body content">
+
+ <div class="row-nowrap">
+ <div class="span12">
+ <div class="form-row">
+ <label for="blueprintId">Deployment ID</label>
+ <div class="field-group">
+ <!--autofocus is HTML5 attribute; doesn't work in Firefox-->
+ <input id="blueprintId" class="span12" type="text" data-ng-model="ecdapp.editRequest.deployment_id" autofocus/>
+ </div>
+ </div>
+ </div>
+ <div class="span12">
+ <div class="form-row">
+ <label for="allowCustom">&nbsp;</label>
+ <div class="field-group">
+ <label for="allowCustomParameters" class="checkbox">
+ <input id="allowCustomParameters" type="checkbox" ng-model="ecdapp.editRequest.allow_custom_parameter" />
+ <i class="skin"></i><span>Allow Custom Parameters</span>
+ </label>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="row-nowrap">
+ <div class="span12">
+ <div class="form-row">
+ <label for="workflowName">Workflow Name</label>
+ <div class="field-group">
+ <select b2b-dropdown id="workflowName" name="workflowName" ng-model="ecdapp.editRequest.workflow_name.value" ng-change="selectWorkflowName()">
+ <option b2b-dropdown-list option-repeat="w in ecdapp.editRequest.workflow_list" value="{{w}}">
+ {{w}}
+ </option>
+ </select>
+ </div>
+ </div>
+ </div>
+ <div class="span12">
+ <div class="form-row">
+ <label for="force">&nbsp;</label>
+ <div class="field-group">
+ <label for="force" class="checkbox">
+ <input id="force" type="checkbox" ng-model="ecdapp.editRequest.force" />
+ <i class="skin"></i><span>Force</span>
+ </label>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="row-nowrap">
+ <div class="span12">
+ <div class="form-row">
+ <label for="parameters">*Parameters</label>
+ <div b2b-file-drop file-model="ecdapp.editRequest.fileModel" on-drop="handleFileSelect()" align="center">
+ <span b2b-file-link file-model="ecdapp.editRequest.fileModel" on-file-select="handleFileSelect()" >
+ Drag &amp; drop a parameters YAML file here, or click to browse.
+ </span>
+ </div>
+ </div>
+ <div class="ecd-parameter-table">
+ <table id="parameters">
+ <tr id="ecd-table-header">
+ <th width="40%">Name</th>
+ <th width="60%">Value</th>
+ </tr>
+ <tbody ng-repeat="(pkey, pval) in ecdapp.editRequest.parmFileDict">
+ <tr id="tr-rowData">
+ <td ng-bind="pkey"/>
+ <td ng-bind="pval"/>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+
+ </div>
+
+ <div class="b2b-modal-footer ng-scope ng-isolate-scope">
+ <div class="cta-button-group in">
+ <button class="btn btn-alt btn-small" type="button"
+ ng-click="ecdapp.executeDeployment(ecdapp.editRequest);">
+ Save
+ </button>
+ <button class="btn btn-small" type="button"
+ ng-click="$dismiss('cancel')">
+ Cancel
+ </button>
+ </div>
+ </div>
+
+</script>
+
+<script type="text/ng-template" id="deployment_delete_popup.html">
+
+
+ <div class="b2b-modal-header ng-scope">
+ <h2 id="myModalLabel" modal-title="">{{ecdapp.label}}</h2>
+ <div class="corner-button in">
+ <button type="button" class="close" aria-label="Close"
+ ng-click="$dismiss('cancel')"></button>
+ </div>
+ </div>
+
+ <div class="b2b-modal-body ng-scope ng-isolate-scope" tabindex="0"
+ role="region" aria-label="Modal body content">
+
+ <div class="span12">
+ <div class="form-row">
+ <div class="field-group">
+ <label>
+ Delete deployment with ID '{{ecdapp.deploymentId}}'?
+ </label>
+ </div>
+ </div>
+ </div>
+
+ <div class="span12">
+ <div class="form-row">
+ <label for="ignoreLiveNodesCheck">&nbsp;</label>
+ <div class="field-group">
+ <label for="ignoreLiveNodes" class="checkbox">
+ <input id="ignoreLiveNodes" type="checkbox" ng-model="ecdapp.ignoreLiveNodes" />
+ <i class="skin"></i><span>Ignore Live Nodes</span>
+ </label>
+ </div>
+ </div>
+ </div>
+
+ </div>
+
+ <div class="b2b-modal-footer ng-scope ng-isolate-scope">
+ <div class="cta-button-group in">
+ <button class="btn btn-alt btn-small" type="button"
+ ng-click="ecdapp.deleteDeploymentById(deployment);">
+ Delete
+ </button>
+ <button class="btn btn-small" type="button"
+ ng-click="$dismiss('cancel')">
+ Cancel
+ </button>
+ </div>
+ </div>
+
+</script> \ No newline at end of file
diff --git a/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/deployment_table.html b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/deployment_table.html
new file mode 100644
index 0000000..c414484
--- /dev/null
+++ b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/deployment_table.html
@@ -0,0 +1,93 @@
+<div id="page-content">
+
+ <h1 class="heading-page" id="deployments-page">Deployments</h1>
+
+ <!-- show progress indicator -->
+ <div ng-show="ecdapp.isDataLoading">
+ <div class="span" style="margin-bottom:20px;">
+ <i class="icon-primary-spinner small" role="img" aria-label="Please wait while the content loads"></i>
+ Please wait while the content loads.
+ </div>
+ </div>
+
+ <div ng-hide="ecdapp.isDataLoading">
+
+ <div id="button-search-row">
+ <div style="float:right;">
+ <div class="form-field form-field__small">
+ <input
+ type="text"
+ placeholder="Search Deployments"
+ ng-model="ecdapp.searchString"/>
+ </div>
+ </div>
+ </div>
+
+ <div ng-show="ecdapp.isRequestFailed">
+ <span class="ecd-error-message">{{ecdapp.errMsg}}</span>
+ </div>
+
+ <div ng-hide="ecdapp.isRequestFailed">
+
+ <div
+ b2b-table
+ id="deployments-table"
+ class="b2b-table-div"
+ table-data="ecdapp.tableData"
+ search-string="ecdapp.searchString"
+ current-page="ecdapp.currentPageIgnored"
+ next-sort="ecdapp.nextSortIgnored">
+
+ <table>
+
+ <thead b2b-table-row type="header">
+ <tr id="th-header-row">
+ <th b2b-table-header key="deployment_id">ID</th>
+ <th b2b-table-header key="blueprint_id">Blueprint ID</th>
+ <th b2b-table-header key="description">Description</th>
+ <th b2b-table-header key="created_at">Created Date</th>
+ <th b2b-table-header key="updated_at">Updated Date</th>
+ <th b2b-table-header sortable="false"><i class="icon-controls-gear ecd-icon-display"></i></th>
+ </tr>
+ </thead>
+
+ <tbody b2b-table-row type="body" row-repeat="rowData in ecdapp.tableData">
+ <tr id="tr-rowData">
+ <td b2b-table-body
+ ng-bind="rowData.id"/>
+ <td b2b-table-body
+ ng-bind="rowData.blueprint_id"/>
+ <td b2b-table-body
+ ng-bind="rowData.description"/>
+ <td b2b-table-body
+ ng-bind="rowData.created_at"/>
+ <td b2b-table-body
+ ng-bind="rowData.updated_at"/>
+ <td b2b-table-body>
+ <div ng-click="ecdapp.createExecutionModalPopup(rowData);">
+ <a href="" title="Create execution" class="icon-controls-playalt ecd-icon-action"></a>
+ </div>
+ <div ng-click="ecdapp.deleteDeploymentModalPopup(rowData);">
+ <a href="" title="Delete deployment" class="icon-misc-trash ecd-icon-action"></a>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
+ <div b2b-pagination="" total-pages="ecdapp.totalPages"
+ current-page="ecdapp.currentPageNum" click-handler="pageChangeHandler"
+ role="navigation">
+ </div>
+
+ </div>
+ </div>
+
+ <div style="height: 10px;">
+ <!-- space between page number and black footer -->
+ </div>
+
+ </div><!-- loading -->
+
+</div><!-- page content -->
diff --git a/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/execution-service.js b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/execution-service.js
new file mode 100644
index 0000000..f1a5698
--- /dev/null
+++ b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/execution-service.js
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * =============LICENSE_START=========================================================
+ *
+ * =================================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ *******************************************************************************/
+appDS2.factory('ExecutionService', function ($http, $q, $log) {
+ return {
+ /**
+ * Gets one page of objects.
+ * @param {Number} pageNum - page number; e.g., 1
+ * @param {Number} viewPerPage - number of items per page; e.g., 25
+ * @return {JSON} Response object from remote side
+ */
+ getExecutions: function(pageNum,viewPerPage) {
+ // cache control for IE
+ let cc = "&cc=" + new Date().getTime().toString();
+ let url = 'executions?pageNum=' + pageNum + '&viewPerPage=' + viewPerPage + cc;
+ return $http({
+ method: 'GET',
+ url: url,
+ cache: false,
+ responseType: 'json'
+ }).then(function(response) {
+ if (response.data == null || typeof response.data != 'object')
+ return $q.reject('ExecutionService.getExecutions: response.data null or not object');
+ else
+ return response.data;
+ },
+ function(error) {
+ $log.error('ExecutionService.getExecutions failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+
+ getExecutionsByStatus: function(status) {
+ // cache control for IE
+ let cc = "&cc=" + new Date().getTime().toString();
+ let url = 'executions?status=' + status + cc;
+ return $http({
+ method: 'GET',
+ url: url,
+ cache: false,
+ responseType: 'json'
+ }).then(function(response) {
+ if (response.data == null || typeof response.data != 'object')
+ return $q.reject('ExecutionService.getExecutions: response.data null or not object');
+ else
+ return response.data;
+ },
+ function(error) {
+ $log.error('ExecutionService.getExecutions failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+
+ executeDeployment: function(executeRequest) {
+ let url = 'executions';
+ return $http({
+ method: 'POST',
+ url: url,
+ data: executeRequest,
+ responseType: 'json'
+ }).then(function(response) {
+ if (response.data == null || typeof response.data != 'object')
+ return $q.reject('ExecutionService.executeDeployment: response.data null or not object');
+ else
+ return response.data;
+ },
+ function(error) {
+ $log.error('ExecutionService.executeDeployment failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+
+ cancelExecution: function(id, deploymentId, action) {
+ let url = 'executions/' + id + '?deployment_id=' + deploymentId + '&action=' + action;
+ return $http({
+ method: 'DELETE',
+ url: url,
+ cache: false,
+ responseType: 'json'
+ }).then(function(response) {
+ // This is called on response code 200..299.
+ // On success, response.data is null.
+ // On failure, response.data has an error message.
+ return response.data;
+ },
+ function(error) {
+ $log.error('ExecutionService.cancelExecution failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+ };
+});
diff --git a/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/execution-table-controller.js b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/execution-table-controller.js
new file mode 100644
index 0000000..a9c8574
--- /dev/null
+++ b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/execution-table-controller.js
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * =============LICENSE_START=========================================================
+ *
+ * =================================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ *******************************************************************************/
+appDS2.controller('executionTableController', function(
+ $rootScope, $scope, $log, $modal, modalService, ExecutionService) {
+
+ 'use strict';
+
+ // Controls logging in this controller
+ var debug = false;
+
+ // this object holds all app data and functions
+ $scope.ecdapp = {};
+ // models for controls on screen
+ $scope.ecdapp.tableData = [];
+ $scope.ecdapp.currentPageNum = 1;
+ $scope.ecdapp.viewPerPage = 10;
+ // other
+ $scope.ecdapp.errMsg = null;
+ $scope.ecdapp.isDataLoading = true;
+ $scope.ecdapp.isRequestFailed = false;
+
+ /**
+ * Loads the table. Interprets the remote controller's response and copies
+ * to scope variables. The response is either a list to be assigned to
+ * tableData, or an error to be shown.
+ */
+ $scope.ecdapp.loadTable = function() {
+ $scope.ecdapp.isDataLoading = true;
+ ExecutionService.getExecutions($scope.ecdapp.currentPageNum,
+ $scope.ecdapp.viewPerPage).then(
+ function(jsonObj) {
+ if (jsonObj.error) {
+ $log.error("executionController.loadTable failed: "
+ + jsonObj.error);
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = jsonObj.error;
+ $scope.ecdapp.tableData = [];
+ } else {
+ $scope.ecdapp.isRequestFailed = false;
+ $scope.ecdapp.errMsg = null;
+ $scope.ecdapp.totalPages = jsonObj.totalPages;
+ $scope.ecdapp.tableData = jsonObj.items;
+ }
+ $scope.ecdapp.isDataLoading = false;
+ },
+ function(error) {
+ $log.error("executionController.loadTable failed: "
+ + error);
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = error;
+ $scope.ecdapp.tableData = [];
+ $scope.ecdapp.isDataLoading = false;
+ });
+ };
+
+ /**
+ * Invoked at first page load AND when
+ * user clicks on the B2B pagination control.
+ */
+ $scope.pageChangeHandler = function(page) {
+ if (debug)
+ console.log('pageChangeHandler: current is ' + $scope.ecdapp.currentPageNum + ' new is ' + page);
+ $scope.ecdapp.currentPageNum = page;
+ $scope.ecdapp.loadTable();
+ }
+
+ /**
+ * Shows a modal pop-up with the error.
+ */
+ $scope.ecdapp.viewErrorModalPopup = function(row) {
+ modalService.showFailure('Error Details', row.error, function() { } );
+ };
+
+ /**
+ * Shows a modal pop-up to confirm deletion.
+ * On successful completion, updates the table.
+ */
+ $scope.ecdapp.cancelExecutionModalPopup = function(execution) {
+ modalService.popupConfirmWin("Confirm", "Cancel execution with ID '"
+ + execution.id + "'?", function() {
+ // TODO: gather action from user
+ ExecutionService.cancelExecution(execution.id, execution.deploymentId, "cancel").then(
+ function(response) {
+ if (debug)
+ $log.debug("xeqTblController.cancelExecutionModalPopup: " + JSON.stringify(response));
+ if (response && response.error) {
+ // $log.error('cancelExectuion failed: ' + response.error);
+ alert('Failed to cancel execution:\n' + response.error);
+ }
+ else {
+ // No response body on success.
+ $scope.ecdapp.loadTable();
+ }
+ },
+ function(error) {
+ $log.error('ExecutionService.cancelExecution failed: ' + error);
+ alert('Service failed to cancel execution:\n' + error);
+ });
+ })
+ };
+
+ // Populate the table on load. Note that the b2b selector code
+ // sets the page-number value, and the change event calls load table.
+ // Do not call this here to avoid double load:
+ // $scope.ecdapp.loadTable();
+
+});
diff --git a/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/execution_table.html b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/execution_table.html
new file mode 100644
index 0000000..f29e90d
--- /dev/null
+++ b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/execution_table.html
@@ -0,0 +1,101 @@
+<div id="page-content">
+
+ <h1 class="heading-page" id="executions-page">Executions</h1>
+
+ <!-- show progress indicator -->
+ <div ng-show="ecdapp.isDataLoading">
+ <div class="span" style="margin-bottom:20px;">
+ <i class="icon-primary-spinner small" role="img" aria-label="Please wait while the content loads"></i>
+ Please wait while the content loads.
+ </div>
+ </div>
+
+ <div ng-hide="ecdapp.isDataLoading">
+
+ <div id="button-search-row">
+ <div style="float:right;">
+ <div class="form-field form-field__small">
+ <input
+ type="text"
+ placeholder="Search Executions"
+ ng-model="ecdapp.searchString"/>
+ </div>
+ </div>
+ </div>
+
+ <div ng-show="ecdapp.isRequestFailed">
+ <span class="ecd-error-message">{{ecdapp.errMsg}}</span>
+ </div>
+
+ <div ng-hide="ecdapp.isRequestFailed">
+
+ <div
+ b2b-table
+ id="executions-table"
+ class="b2b-table-div"
+ table-data="ecdapp.tableData"
+ search-string="ecdapp.searchString"
+ current-page="ecdapp.currentPageIgnored"
+ next-sort="ecdapp.nextSortIgnored">
+
+ <table>
+
+ <thead b2b-table-row type="header">
+ <tr id="th-header-row">
+ <th b2b-table-header key="id">ID</th>
+ <th b2b-table-header key="deployment_id">Deployment ID</th>
+ <th b2b-table-header key="blueprint_id">Blueprint ID</th>
+ <th b2b-table-header key="workflow_id">Workflow ID</th>
+ <th b2b-table-header key="description">Description</th>
+ <th b2b-table-header key="created_at">Created Date</th>
+ <th b2b-table-header key="status">Status</th>
+ <th b2b-table-header key="error">Error</th>
+ <th b2b-table-header sortable="false"><i class="icon-controls-gear ecd-icon-display"></i></th>
+ </tr>
+ </thead>
+
+ <tbody b2b-table-row type="body" row-repeat="rowData in ecdapp.tableData">
+ <tr id="tr-rowData">
+ <td b2b-table-body
+ ng-bind="rowData.id"/>
+ <td b2b-table-body
+ ng-bind="rowData.deployment_id"/>
+ <td b2b-table-body
+ ng-bind="rowData.blueprint_id"/>
+ <td b2b-table-body
+ ng-bind="rowData.workflow_id"/>
+ <td b2b-table-body
+ ng-bind="rowData.description"/>
+ <td b2b-table-body
+ ng-bind="rowData.created_at"/>
+ <td b2b-table-body
+ ng-bind="rowData.status"/>
+ <td b2b-table-body>
+ <div ng-show="rowData.error" ng-click="ecdapp.viewErrorModalPopup(rowData);">
+ <a href="" title="View error details" class="icon-people-preview ecd-icon-action"></a>
+ </div>
+ </td>
+ <td b2b-table-body>
+ <div ng-click="ecdapp.cancelExecutionModalPopup(rowData);">
+ <a href="" title="Cancel execution" class="icon-controls-stop ecd-icon-action"></a>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
+ <div b2b-pagination="" total-pages="ecdapp.totalPages"
+ current-page="ecdapp.currentPageNum" click-handler="pageChangeHandler"
+ role="navigation">
+ </div>
+
+ </div>
+
+ <div style="height: 10px;">
+ <!-- space between page number and black footer -->
+ </div>
+
+ </div><!-- loading -->
+
+</div><!-- page content -->
diff --git a/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/tosca-table-controller.js b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/tosca-table-controller.js
new file mode 100644
index 0000000..cafc517
--- /dev/null
+++ b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/tosca-table-controller.js
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * =============LICENSE_START=========================================================
+ *
+ * =================================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ *******************************************************************************/
+appDS2.controller('toscaTableController', function(
+ $rootScope, $scope, $log, $modal, modalService, ExecutionService) {
+
+ 'use strict';
+
+ // this object holds all app data and functions
+ $scope.ecdapp = {};
+ // models for controls on screen
+ $scope.ecdapp.tableData = [];
+ $scope.ecdapp.currentPageNum = 1;
+ $scope.ecdapp.viewPerPage = 10;
+ // other
+ $scope.ecdapp.errMsg = null;
+ $scope.ecdapp.isDataLoading = true;
+ $scope.ecdapp.isRequestFailed = false;
+
+ /**
+ * Loads the table. Interprets the remote controller's response and copies
+ * to scope variables. The response is either a list to be assigned to
+ * tableData, or an error to be shown.
+ */
+ $scope.ecdapp.loadTable = function() {
+ var toBeDefined = true;
+ if (toBeDefined) {
+ $scope.ecdapp.isDataLoading = false;
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = 'TOSCA Models not available (yet).';
+ }
+ else {
+ $scope.ecdapp.isDataLoading = true;
+ ExecutionService.getExecutions($scope.ecdapp.currentPageNum,
+ $scope.ecdapp.viewPerPage).then(
+ function(jsonObj) {
+ if (jsonObj.error) {
+ $log.error("executionController.loadTable failed: "
+ + jsonObj.error);
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = jsonObj.error;
+ $scope.ecdapp.tableData = [];
+ } else {
+ $scope.ecdapp.isRequestFailed = false;
+ $scope.ecdapp.errMsg = null;
+ $scope.ecdapp.totalPages = jsonObj.totalPages;
+ $scope.ecdapp.tableData = jsonObj.items;
+ }
+ $scope.ecdapp.isDataLoading = false;
+ },
+ function(error) {
+ $log.error("executionController.loadTable failed: "
+ + error);
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = error;
+ $scope.ecdapp.tableData = [];
+ $scope.ecdapp.isDataLoading = false;
+ });
+ }
+ };
+
+ /**
+ * Invoked at first page load AND when
+ * user clicks on the B2B pagination control.
+ */
+ $scope.pageChangeHandler = function(page) {
+ // console.log('pageChangeHandler: current is ' + $scope.ecdapp.currentPageNum + ' new is ' + page);
+ $scope.ecdapp.currentPageNum = page;
+ $scope.ecdapp.loadTable();
+ }
+
+ /**
+ * Shows a modal pop-up to confirm deletion.
+ * On successful completion, updates the table.
+ */
+ $scope.ecdapp.deleteToscaModalPopup = function(execution) {
+ modalService.popupConfirmWin("Confirm", "Delete TOSCA model with ID '"
+ + execution.id + "'?", function() {
+ // TODO: gather action from user
+ })
+ };
+
+ // Populate the table on load. Note that the b2b selector code
+ // sets the page-number value, and the change event calls load table.
+ // Do not call this here to avoid double load:
+ // $scope.ecdapp.loadTable();
+
+});
diff --git a/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/tosca_table.html b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/tosca_table.html
new file mode 100644
index 0000000..affec91
--- /dev/null
+++ b/ecd-app-overlay/src/main/webapp/app/ecdapp/cloudify/tosca_table.html
@@ -0,0 +1,87 @@
+<div id="page-content">
+
+ <h1 class="heading-page" id="blueprints-page">TOSCA Models</h1>
+
+ <!-- show progress indicator -->
+ <div ng-show="ecdapp.isDataLoading">
+ <div class="span" style="margin-bottom:20px;">
+ <i class="icon-primary-spinner small" role="img" aria-label="Please wait while the content loads"></i>
+ Please wait while the content loads.
+ </div>
+ </div>
+
+ <div ng-hide="ecdapp.isDataLoading">
+
+ <div id="button-search-row">
+ <div style="float:right;">
+ <div class="form-field form-field__small">
+ <input
+ type="text"
+ placeholder="Search TOSCA Models"
+ ng-model="ecdapp.searchString"/>
+ </div>
+ </div>
+ </div>
+
+ <div ng-show="ecdapp.isRequestFailed">
+ <span class="ecd-error-message">{{ecdapp.errMsg}}</span>
+ </div>
+
+ <div ng-hide="ecdapp.isRequestFailed">
+
+ <div
+ b2b-table
+ id="tosca-table"
+ class="b2b-table-div"
+ table-data="ecdapp.tableData"
+ search-string="ecdapp.searchString"
+ current-page="ecdapp.currentPageIgnored"
+ next-sort="ecdapp.nextSortIgnored">
+
+ <table>
+
+ <thead b2b-table-row type="header">
+ <tr id="th-header-row">
+ <th b2b-table-header key="id">ID</th>
+ <th b2b-table-header key="name">Name</th>
+ <th b2b-table-header key="description">Description</th>
+ <th b2b-table-header key="created_at">Created Date</th>
+ <th b2b-table-header key="updated_at">Updated Date</th>
+ <th b2b-table-header sortable="false"><i class="icon-controls-gear ecd-icon-display"></i></th>
+ </tr>
+ </thead>
+
+ <tbody b2b-table-row type="body" row-repeat="rowData in ecdapp.tableData">
+ <tr id="tr-rowData">
+ <td b2b-table-body
+ ng-bind="rowData.id"/>
+ <td b2b-table-body
+ ng-bind="rowData.main_file_name"/>
+ <td b2b-table-body
+ ng-bind="rowData.description"/>
+ <td b2b-table-body
+ ng-bind="rowData.created_at"/>
+ <td b2b-table-body
+ ng-bind="rowData.updated_at"/>
+ <td b2b-table-body>
+ <div ng-click="ecdapp.deleteToscaModalPopup(rowData);">
+ <a href="" title="Delete TOSCA model" class="icon-misc-trash ecd-icon-action"></a>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
+ <div b2b-pagination="" total-pages="ecdapp.totalPages"
+ current-page="ecdapp.currentPageNum" click-handler="pageChangeHandler"
+ role="navigation">
+ </div>
+
+ <div style="height: 10px;">
+ <!-- space between page number and black footer -->
+ </div>
+
+ </div><!-- loading -->
+
+</div><!-- page content -->