diff options
Diffstat (limited to 'ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard')
11 files changed, 1893 insertions, 0 deletions
diff --git a/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/WidgetSettingsCtrl.js b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/WidgetSettingsCtrl.js new file mode 100644 index 00000000..4b420a27 --- /dev/null +++ b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/WidgetSettingsCtrl.js @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014 DataTorrent, Inc. 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. + */ + +'use strict'; + +angular.module('ui.dashboard') + .controller('WidgetSettingsCtrl', ['$scope', '$uibModalInstance', 'widget', function ($scope, $uibModalInstance, widget) { + // add widget to scope + $scope.widget = widget; + + // set up result object + $scope.result = jQuery.extend(true, {}, widget); + + $scope.ok = function () { + $uibModalInstance.close($scope.result); + }; + + $scope.cancel = function () { + $uibModalInstance.dismiss('cancel'); + }; + }]);
\ No newline at end of file diff --git a/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/WidgetSettingsRaptorReportCtrl.js b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/WidgetSettingsRaptorReportCtrl.js new file mode 100644 index 00000000..fd6a0b02 --- /dev/null +++ b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/WidgetSettingsRaptorReportCtrl.js @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2014 DataTorrent, Inc. 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. + */ + +'use strict'; + +angular.module('ui.dashboard') + .controller('WidgetSettingsRaptorReportCtrl', ['$http','$scope','$rootScope','$uibModalInstance', 'widget', function ($http,$scope,$rootScope,$uibModalInstance, widget) { + + // add watch function for widget here + // leave ajax call to the dashboard.js + + console.log("============= WidgetSettingsRaptorReportCtrl scope ================="); + console.log($scope); + + var getFormFieldListUrl = "raptor.htm?action=report.run.container&c_master="+widget.report_id + "&refresh=Y" + console.log("============= getFormFieldListUrl ============="); + console.log(getFormFieldListUrl); + $http.get(getFormFieldListUrl).then( + function(res){ + $scope.reportData = res.data; + // add widget to scope + $scope.showFormFieldIds = false; + $scope.formFieldSelectedValues = {}; +}); + + var parseQueryString = function( queryString ) { + var params = {}, queries, temp, i, l; + // Split into key/value pairs + queries = queryString.split("&"); + // Convert the array of strings into an object + for ( i = 0, l = queries.length; i < l; i++ ) { + temp = queries[i].split('='); + //console.log(temp[0]); + //console.log(temp[0] != "refresh"); + if(temp[0] && temp[0] != "refresh") + params[temp[0]] = temp[1]; + } + return params; + }; + + var paginationOptions = { + pageNumber: 1, + pageSize: 5, + sort: null + }; + + $scope.gridOptions = { + paginationPageSizes: [5], + paginationPageSize: 5, + useExternalPagination: true, + columnDefs: [], + data: [], + enableGridMenu: true, + enableSelectAll: true, + exporterMenuPdf: false, + exporterMenuCsv: false, + exporterCsvFilename: 'myFile.csv', + exporterPdfDefaultStyle: {fontSize: 9}, + exporterPdfTableStyle: {margin: [30, 30, 30, 30]}, + exporterPdfTableHeaderStyle: {fontSize: 10, bol$rootScoped: true, italics: true, color: 'red'}, + exporterPdfHeader: { text: "My Header", style: 'headerStyle' }, + exporterPdfFooter: function ( currentPage, pageCount ) { + return { text: currentPage.toString() + ' of ' + pageCount.toString(), style: 'footerStyle' }; + }, + exporterPdfCustomFormatter: function ( docDefinition ) { + docDefinition.styles.headerStyle = { fontSize: 22, bold: true }; + docDefinition.styles.footerStyle = { fontSize: 10, bold: true }; + return docDefinition; + }, + exporterPdfOrientation: 'portrait', + exporterPdfPageSize: 'LETTER', + exporterPdfMaxGridWidth: 500, + exporterCsvLinkElement: angular.element(document.querySelectorAll(".custom-csv-link-location")), + onRegisterApi: function(gridApi) { + $scope.gridApi = gridApi; + gridApi.pagination.on.paginationChanged($scope, function (newPage, pageSize) { + paginationOptions.pageNumber = newPage; + paginationOptions.pageSize = pageSize; + $scope.runReport(); + }); + } + }; + + + + $scope.getFormFieldSelectedValuesAsURL = function(){ + var formFieldsUrl = ''; + $scope.widget.reportData.formFieldList.forEach(function(formField) { + if(formField.fieldType==='LIST_BOX') { + if($scope.formFieldSelectedValues && $scope.formFieldSelectedValues[formField.fieldId] && $scope.formFieldSelectedValues[formField.fieldId].value != '') { + formFieldsUrl = formFieldsUrl+formField.fieldId+'='+$scope.formFieldSelectedValues[formField.fieldId].value+'&'; + } + } else if(formField.fieldType==='LIST_MULTI_SELECT') { + if($scope.formFieldSelectedValues[formField.fieldId].length >0) { + for (var i = 0; i < $scope.formFieldSelectedValues[formField.fieldId].length; i++) { + if($scope.formFieldSelectedValues[formField.fieldId][i].defaultValue){ + formFieldsUrl = formFieldsUrl+formField.fieldId+'='+$scope.formFieldSelectedValues[formField.fieldId][i].value+'&'; + } + } + } + } else if((formField.fieldType === 'text' || formField.fieldType === 'TEXT') && formField.validationType === 'DATE'){ + formFieldsUrl = formFieldsUrl+formField.fieldId+'='+dateFilter($scope.formFieldSelectedValues[formField.fieldId],$scope.dateformat)+'&'; + } else if((formField.fieldType === 'text' || formField.fieldType === 'TEXT') && formField.validationType === 'TIMESTAMP_MIN'){ + formFieldsUrl = formFieldsUrl+formField.fieldId+'='+dateFilter($scope.formFieldSelectedValues[formField.fieldId],$scope.datetimeformat)+'&'; + } else if((formField.fieldType === 'text' || formField.fieldType === 'TEXT') && $scope.formFieldSelectedValues[formField.fieldId] && $scope.formFieldSelectedValues[formField.fieldId] != ''){ + formFieldsUrl = formFieldsUrl+formField.fieldId+'='+$scope.formFieldSelectedValues[formField.fieldId]+'&'; + } + }); + return formFieldsUrl; + + } + + $scope.triggerOtherFormFields = function(){ + console.log("report_run"); + var formFieldsUrl = $scope.getFormFieldSelectedValuesAsURL(); + $http.get('raptor.htm?action=report.formfields.run.container&c_master='+widget.report_id+'&'+formFieldsUrl).then( + function(response){ + $scope.widget.reportData = response.data; + }); + }; + + + $scope.runReport = function(pagination){ + var formFieldsUrl = $scope.getFormFieldSelectedValuesAsURL(); + console.log("pagination"); + if(!pagination) { + console.log("refreshed ..."); + $scope.gridOptions.pageNumber = 1; + $scope.gridOptions.paginationPageSizes= [widget.reportData.pageSize]; + $scope.gridOptions.paginationPageSize= widget.reportData.pageSize; + if(widget.reportData.totalRows<14){ + $scope.gridHeight = (widget.reportData.totalRows+7)*30+'px'; + } else{ + $scope.gridHeight = '400px'; + } + $scope.gridOptions.totalItems = widget.reportData.totalRows; + $scope.gridOptions.data= widget.reportData.reportDataRows; + $scope.gridOptions.exporterPdfHeader.text= widget.reportData.reportName; + } +/* $scope.currentReportUrlParams = 'c_master='+$scope.urlParams.c_master+'&'+formFieldsUrl+'&display_content=Y&r_page='+(paginationOptions.pageNumber-1); + console.log('raptor.htm?action=report.run.container&c_master='+$scope.urlParams.c_master+'&'+formFieldsUrl+'refresh=Y&display_content=Y&r_page='+(paginationOptions.pageNumber-1)); + $http.get('raptor.htm?action=report.run.container&c_master='+$scope.urlParams.c_master+'&'+formFieldsUrl+'refresh=Y&display_content=Y&r_page='+(paginationOptions.pageNumber-1)).then( + */ + $scope.currentReportUrlParams = 'c_master='+ widget.report_id+'&'+formFieldsUrl+'&display_content=Y&r_page='+(paginationOptions.pageNumber-1); + $scope.urlParams = parseQueryString($scope.currentReportUrlParams); + + console.log('raptor.htm?action=report.run.container&c_master='+ widget.report_id +'&'+formFieldsUrl+'refresh=Y&display_content=Y&r_page='+(paginationOptions.pageNumber-1)); + $http.get('raptor.htm?action=report.run.container&c_master='+widget.report_id+'&'+formFieldsUrl+'refresh=Y&display_content=Y&r_page='+(paginationOptions.pageNumber-1)).then( + function(response){ + widget.reportData = response.data; + if(widget.reportData.errormessage) { + document.getElementById('errorDiv').innerHTML = widget.reportData.errormessage; + console.log(document.getElementById('errorDiv').innerHtml); + console.log(widget.reportData.errormessage); + } + if(!pagination) { + if(!$scope.urlParams.hideChart && widget.reportData.chartAvailable && widget.reportData.totalRows>1){ + console.log('raptor.htm?action=chart.run&c_master='+widget.report_id+'&'+formFieldsUrl+'display_content=Y&r_page='+(paginationOptions.pageNumber-1)); + $http.get('raptor.htm?action=chart.run&c_master='+widget.report_id +'&'+formFieldsUrl+'display_content=Y&r_page='+(paginationOptions.pageNumber-1)).then( + function(response) { + console.log(response.data); + $scope.showChart = true; + document.getElementById('chartiframe').contentWindow.document.write(response.data); + document.getElementById('chartiframe').contentWindow.document.close(); + }); + } else { + $scope.showChart = false; + } + } + if($scope.reportData.displayForm && $scope.reportData.formFieldList && $scope.reportData.formFieldList.length>0 && !$scope.urlParams.hideFormFields){ + $scope.showFormFields = true; + } else { + $scope.showFormFields = false; + } + }); + $rootScope.gridOptions = $scope.gridOptions; + $rootScope.gridHeight = $scope.gridHeight; + $rootScope.showdataContainer = true; + }; + + + + + + // set up result object + $scope.result = jQuery.extend(true, {}, widget); + + $scope.ok = function () { + $uibModalInstance.close($scope.result); + }; + + $scope.okay = function () { + console.log("$scope.okay!") + console.log($scope); + $scope.runReport(); +/* $uibModalInstance.close($scope.result);*/ + }; + + $scope.cancel = function () { + $uibModalInstance.dismiss('cancel'); + }; + }]);
\ No newline at end of file diff --git a/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/add-raptor-report-template.html b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/add-raptor-report-template.html new file mode 100644 index 00000000..00d6c41a --- /dev/null +++ b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/add-raptor-report-template.html @@ -0,0 +1,26 @@ +<div> + <div class="modal-header"> + <h3 class="modal-title"> Add a Raptor Report</h3> + </div> + + <div > + <form name="addRaptorReportForm" class="css-form" novalidate> + <div style="width: 100%;"> + <div style="width: 20%; margin-left: 50px;margin-top:28px; float: left; font-size: 15px;">Report Name: </div> + <div style="margin-top:20px;" class="form-field" att-select="raptorReportList" ng-model="selectedRaptorReport" placeholder="Select a Raptor Report" no-filter="true"></div> + + <form action=""> + <input name="radio" type="radio" ng-model="radioValue" att-radio="chart" title="chart" aria-label="chart radio"> chart + <input name="radio" type="radio" ng-model="radioValue" att-radio="data" title="data" aria-label="data radio"> data + </form> + </div> + + <div class="modal-footer"> + <a att-button btn-type="primary" ng-click="ok()">OK</a> + <a att-button btn-type="primary" ng-click="cancel()">Cancel</a> + </div> + + </form> + <br /> + </div> +</div>
\ No newline at end of file diff --git a/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/add-rcloud-notebook-template.html b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/add-rcloud-notebook-template.html new file mode 100644 index 00000000..239497c9 --- /dev/null +++ b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/add-rcloud-notebook-template.html @@ -0,0 +1,22 @@ +<div> + <div class="modal-header"> + <h3 class="modal-title"> Add a Raptor Report</h3> + </div> + + <div > + <form name="addRaptorReportForm" class="css-form" novalidate> + <div style="width: 100%;"> + <div style="margin-left: 50px;margin-top:28px; font-size: 15px;">RCloud Notebook URL: </div> +<!-- <div style="margin-top:20px;" class="form-field" att-select="raptorReportList" ng-model="selectedRaptorReport" placeholder="Select a Raptor Report" no-filter="true"></div> --> + <textarea style="margin-left: 50px; width:450px; height: 150px;" ng-model="rcloud_url" name="content"> + </textarea> + </div> + <div class="modal-footer"> + <a att-button btn-type="primary" ng-click="ok()">OK</a> + <a att-button btn-type="primary" ng-click="cancel()">Cancel</a> + </div> + + </form> + <br /> + </div> +</div>
\ No newline at end of file diff --git a/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/altDashboard.html b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/altDashboard.html new file mode 100644 index 00000000..189bccea --- /dev/null +++ b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/altDashboard.html @@ -0,0 +1,49 @@ +<div> + <div class="btn-toolbar" ng-if="!options.hideToolbar"> + <div class="btn-group" ng-if="!options.widgetButtons"> + <span class="dropdown" on-toggle="toggled(open)"> + <button type="button" class="btn btn-primary dropdown-toggle" ng-disabled="disabled"> + Button dropdown <span class="caret"></span> + </button> + <ul class="dropdown-menu" role="menu"> + <li ng-repeat="widget in widgetDefs"> + <a href="#" ng-click="addWidgetInternal($event, widget);" class="dropdown-toggle">{{widget.name}}</a> + </li> + </ul> + </span> + </div> + + <div class="btn-group" ng-if="options.widgetButtons"> + <button ng-repeat="widget in widgetDefs" + ng-click="addWidgetInternal($event, widget);" type="button" class="btn btn-primary"> + {{widget.name}} + </button> + </div> + + <button class="btn btn-warning" ng-click="resetWidgetsToDefault()">Default Widgets</button> + + <button ng-if="options.storage && options.explicitSave" ng-click="options.saveDashboard()" class="btn btn-success" ng-hide="!options.unsavedChangeCount">{{ !options.unsavedChangeCount ? "Alternative - No Changes" : "Save" }}</button> + + <button ng-click="clear();" ng-hide="!widgets.length" type="button" class="btn btn-info">Clear</button> + </div> + + <div ui-sortable="sortableOptions" ng-model="widgets" class="dashboard-widget-area"> + <div ng-repeat="widget in widgets" ng-style="widget.style" class="widget-container" widget> + <div class="widget panel panel-default"> + <div class="widget-header panel-heading"> + <h3 class="panel-title"> + <span class="widget-title" ng-dblclick="editTitle(widget)" ng-hide="widget.editingTitle">{{widget.title}}</span> + <form action="" class="widget-title" ng-show="widget.editingTitle" ng-submit="saveTitleEdit(widget)"> + <input type="text" ng-model="widget.title" class="form-control"> + </form> + <span class="label label-primary" ng-if="!options.hideWidgetName">{{widget.name}}</span> + <span ng-click="removeWidget(widget);" class="glyphicon glyphicon-remove icon-erase" ng-if="!options.hideWidgetClose"></span> + <span ng-click="openWidgetSettings(widget);" class="glyphicon glyphicon-cog icon-settings" ng-if="!options.hideWidgetSettings"></span> + </h3> + </div> + <div class="panel-body widget-content"></div> + <div class="widget-ew-resizer" ng-mousedown="grabResizer($event)"></div> + </div> + </div> + </div> +</div> diff --git a/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/dashboard.html b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/dashboard.html new file mode 100644 index 00000000..e891b565 --- /dev/null +++ b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/dashboard.html @@ -0,0 +1,74 @@ + +<div> + <div class="btn-toolbar" ng-if="!options.hideToolbar"> + <div class="btn-group" ng-if="!options.widgetButtons"> + + <span class="dropdown" on-toggle="toggled(open)"> + <!--<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown"> + Button dropdown<span class="caret"></span> + </button>--> + <ul class="dropdown-menu" role="menu"> + <li ng-repeat="widget in widgetDefs"> + <a href="#" ng-click="addWidgetInternal($event, widget);" class="dropdown-toggle"><span class="label label-primary">{{widget.name}}</span></a> + </li> + </ul> + </span> + </div> + + <div class="btn-group" ng-if="options.widgetButtons"> + <button ng-repeat="widget in widgetDefs" + ng-click="addWidgetInternal($event, widget);" type="button" class="btn btn-primary"> + {{widget.name}} + </button> + </div> + +<!-- <div style="float: left" class="form-field" att-select="reports" ng-model="report1" placeholder="Select a Report"></div> + <button class="btn btn-primary" ng-click="addReport(report1)">Add Raptor Report</button> --> + <button class="btn btn-primary" ng-click="popupAddReport()">+ Raptor Report</button> + +<!-- <div style = "float:left"> <input ng-model = "rcloud_url"> </div> + <button class="btn btn-primary" ng-click="addRCloudNotebook(rcloud_url)">Add R Cloud</button> --> + <button class="btn btn-primary" ng-click="popupAddRCloudNotebook()">+ RCloud Notebook</button> + +<!-- <button class="btn btn-warning" ng-click="resetWidgetsToDefault()">Default Widgets</button> --> + + <button ng-if="options.storage && options.explicitSave" ng-click="options.saveDashboard()" class="btn btn-success" ng-disabled="!options.unsavedChangeCount">{{ !options.unsavedChangeCount ? "All Saved" : "Save Changes (" + options.unsavedChangeCount + ")" }}</button> + + <button ng-click="clear();" type="button" class="btn btn-info">Clear</button> + +<!-- <button style="float:right" ng-click="clear();" type="button" class="btn btn-info">Save to Database</button> --> + </div> + + +<!-- + <div id="container"> + <div id="navi">navi</div> + <div id="infoi"> + <img src="https://appharbor.com/assets/images/stackoverflow-logo.png" height="20" width="32" />infoi + </div> +</div> + --> + + <div ui-sortable="sortableOptions" ng-model="widgets" class="dashboard-widget-area"> + <div ng-mouseover="hoverIn()" ng-mouseleave="hoverOut()" ng-repeat="widget in widgets" ng-style="widget.containerStyle" class="widget-container" widget> + <div class="widget panel panel-default"> + <div style="opacity: 0.8; background-color: #E5E5E5; border: #d3d3d3;" ng-show="hoverEdit" class="widget-header panel-heading"> + <img style="float:left; margin-right: 10px" src="static/fusion/images/att_angular_gridster/grips.png"> + <h3 class="panel-title"> + <span class="widget-title" ng-dblclick="editTitle(widget)" ng-hide="widget.editingTitle"></span> + <form action="" class="widget-title" ng-show="widget.editingTitle" ng-submit="saveTitleEdit(widget)"> + <input type="text" ng-model="widget.title" class="form-control"> + </form> + <span class="label label-primary" ng-if="!options.hideWidgetName">{{widget.name}}</span> + <span ng-click="removeWidget(widget);" class="glyphicon glyphicon-remove icon-erase" ng-if="!options.hideWidgetClose"></span> + <span ng-click="openWidgetSettings(widget);" class="glyphicon glyphicon-cog icon-settings" ng-if="!options.hideWidgetSettings"></span> + <span ng-click="widget.contentStyle.display = widget.contentStyle.display === 'none' ? 'block' : 'none'" class="glyphicon" ng-class="{'glyphicon-plus': widget.contentStyle.display === 'none', 'glyphicon-minus': widget.contentStyle.display !== 'none' }"></span> + </h3> + </div> + <div class="panel-body widget-content" ng-style="widget.contentStyle"></div> + <div class="widget-ew-resizer" ng-mousedown="grabResizer($event)"></div> + <div style="background-color:#f2f2f2" ng-if="widget.enableVerticalResize" class="widget-s-resizer" ng-mousedown="grabSouthResizer($event)"></div> + </div> + </div> + </div> +</div>
\ No newline at end of file diff --git a/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/dashboard.js b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/dashboard.js new file mode 100644 index 00000000..4062694e --- /dev/null +++ b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/dashboard.js @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2014 DataTorrent, Inc. 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. + */ +'use strict'; + +angular.module('ui.dashboard', ['ui.bootstrap', 'ui.sortable']); + +angular.module('ui.dashboard') + + .directive('dashboard', ['$http','WidgetModel', 'WidgetDefCollection', '$uibModal', 'DashboardState', '$log', function ($http, WidgetModel, WidgetDefCollection, $uibModal, DashboardState, $log) { + + return { + restrict: 'A', + templateUrl: function(element, attr) { + return attr.templateUrl ? attr.templateUrl : 'app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/dashboard.html'; + }, + scope: true, + + controller: ['$scope', '$attrs', function (scope, attrs) { + // default options + var defaults = { + stringifyStorage: true, + hideWidgetSettings: false, + hideWidgetClose: false, + settingsModalOptions: { + // templateUrl: 'app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/widget-settings-template.html', + templateUrl: 'app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/widget-settings-raptor-report-template.html', + // controller: 'WidgetSettingsCtrl' + controller: 'WidgetSettingsRaptorReportCtrl' + }, + onSettingsClose: function(result, widget) { // NOTE: dashboard scope is also passed as 3rd argument + jQuery.extend(true, widget, result); + }, + onSettingsDismiss: function(reason) { // NOTE: dashboard scope is also passed as 2nd argument + $log.info('widget settings were dismissed. Reason: ', reason); + } + }; + + scope.hoverEdit = false; + + scope.hoverIn = function(){ + this.hoverEdit = true; + }; + + scope.hoverOut = function(){ + this.hoverEdit = false; + }; + + // from dashboard="options" + scope.options = scope.$eval(attrs.dashboard); + + // Deep options + scope.options.settingsModalOptions = scope.options.settingsModalOptions || {}; + _.each(['settingsModalOptions'], function(key) { + // Ensure it exists on scope.options + scope.options[key] = scope.options[key] || {}; + // Set defaults + _.defaults(scope.options[key], defaults[key]); + }); + + // Shallow options + _.defaults(scope.options, defaults); + + // sortable options + var sortableDefaults = { + stop: function () { + scope.saveDashboard(); + }, + handle: '.widget-header', + distance: 5 + }; + scope.sortableOptions = angular.extend({}, sortableDefaults, scope.options.sortableOptions || {}); + + }], + link: function (scope) { + + // Save default widget config for reset + scope.defaultWidgets = scope.options.defaultWidgets; + + scope.widgetDefs = new WidgetDefCollection(scope.options.widgetDefinitions); + var count = 1; + + // Instantiate new instance of dashboard state + scope.dashboardState = new DashboardState( + scope.options.storage, + scope.options.storageId, + scope.options.storageHash, + scope.widgetDefs, + scope.options.stringifyStorage + ); + + /** + * Instantiates a new widget on the dashboard + * @param {Object} widgetToInstantiate The definition object of the widget to be instantiated + */ + scope.addWidget = function (widgetToInstantiate, doNotSave) { + + if (typeof widgetToInstantiate === 'string') { + widgetToInstantiate = { + name: widgetToInstantiate + }; + } + + var defaultWidgetDefinition = scope.widgetDefs.getByName(widgetToInstantiate.name); + if (!defaultWidgetDefinition) { + throw 'Widget ' + widgetToInstantiate.name + ' is not found.'; + } + + // Determine the title for the new widget + var title; + if (!widgetToInstantiate.title && !defaultWidgetDefinition.title) { + widgetToInstantiate.title = 'Widget ' + count++; + } + + // Instantiation + var widget = new WidgetModel(defaultWidgetDefinition, widgetToInstantiate); + + // Add to the widgets array + scope.widgets.push(widget); + if (!doNotSave) { + scope.saveDashboard(); + } + + return widget; + }; + + /** + * Removes a widget instance from the dashboard + * @param {Object} widget The widget instance object (not a definition object) + */ + scope.removeWidget = function (widget) { + scope.widgets.splice(_.indexOf(scope.widgets, widget), 1); + scope.saveDashboard(); + }; + + /** + * Opens a dialog for setting and changing widget properties + * @param {Object} widget The widget instance object + */ + scope.openWidgetSettings = function (widget) { +/* console.log('======= widgets ======='); + console.log(widget); + console.log('widget.report_id'); + console.log(widget.report_id); +*/ + if (widget.directive.includes("raptor-report")) { + var getFormFieldListUrl = "raptor.htm?action=report.run.container&c_master="+widget.report_id + "&refresh=Y"; + $http.get(getFormFieldListUrl).then( + function(res){ + widget.reportData = res.data; + }); + + // Set up $uibModal options + var options = _.defaults( + { scope: scope }, + widget.settingsModalOptions, + scope.options.settingsModalOptions); + +/* console.log('======= options ======='); + console.log(options); +*/ + // Ensure widget is resolved + options.resolve = { + widget: function () { + return widget; + } + }; + + // Create the modal + var modalInstance = $uibModal.open(options); + var onClose = widget.onSettingsClose || scope.options.onSettingsClose; + var onDismiss = widget.onSettingsDismiss || scope.options.onSettingsDismiss; + + // Set resolve and reject callbacks for the result promise + modalInstance.result.then( + function (result) { + + // Call the close callback + onClose(result, widget, scope); + + //AW Persist title change from options editor + scope.$emit('widgetChanged', widget); + }, + function (reason) { + + // Call the dismiss callback + onDismiss(reason, scope); + + } + ); + + } + + }; + + /** + * Remove all widget instances from dashboard + */ + scope.clear = function (doNotSave) { + scope.widgets = []; + if (doNotSave === true) { + return; + } + scope.saveDashboard(); + }; + + /** + * Used for preventing default on click event + * @param {Object} event A click event + * @param {Object} widgetDef A widget definition object + */ + scope.addWidgetInternal = function (event, widgetDef) { +// event.preventDefault(); + scope.addWidget(widgetDef); + }; + + /** + * Add report to dashboard + */ + scope.popupAddReport = function () { + var modalInstance = $uibModal.open({ + animation: scope.animationsEnabled, + templateUrl: 'app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/add-raptor-report-template.html', + size:'sm', + controller: ['$scope', '$uibModalInstance', '$http', function ($scope, $uibModalInstance, $http) { + $scope.radioValue="chart" + $http.get('raptor.htm?action=report.search.execute').then( + function(result){ + var data = result.data; + var report_id_name = []; + for (var i in data.rows[0]) { + report_id_name.push({index:i, value: data.rows[0][i][1].searchresultField.displayValue, title: data.rows[0][i][2].searchresultField.displayValue}) + } + $scope.raptorReportList = report_id_name; + }); + + $scope.ok = function() { + scope.addReport($scope.selectedRaptorReport,$scope.radioValue); + $uibModalInstance.close(); + }; + $scope.cancel = function() { + $uibModalInstance.dismiss(); + }; + }] + }); + modalInstance.result.then(function () { + $scope.$emit('raptorReportWidgetAdded'); + }, function () { + $log.info('Modal dismissed at: ' + new Date()); + }); + }; + + + scope.popupAddRCloudNotebook = function () { + var modalInstance = $uibModal.open({ + animation: scope.animationsEnabled, + templateUrl: 'app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/add-rcloud-notebook-template.html', + size:'sm', + controller: ['$scope', '$uibModalInstance', '$http', function ($scope, $uibModalInstance, $http) { + $scope.rcloud_url = "" + + $scope.ok = function() { + scope.addRCloudNotebook($scope.rcloud_url); + $uibModalInstance.close(); + }; + $scope.cancel = function() { + $uibModalInstance.dismiss(); + }; + }] + }); + modalInstance.result.then(function () { + $scope.$emit('raptorReportWidgetAdded'); + }, function () { + $log.info('Modal dismissed at: ' + new Date()); + }); + }; + + + scope.addReport = function (report1,radioValue) { + scope.report1 =report1 + var raptor_report_type = "raptor-report-chart" + if (radioValue ==='data') { + raptor_report_type = 'raptor-report-data' + } + console.log("report1") + console.log(report1); +// event.preventDefault(); + var newreport = {"title":report1.title,"name":raptor_report_type ,"style":{},"size":{"height":"350px","width":"40%"},"attrs":{"value":"randomValue"},"report_id":report1.value}; + scope.addWidget(newreport, true); + console.log("widgets"); + console.log(scope.widgets); + ++scope.options.unsavedChangeCount; + return false; + }; + + /** + * Add rcloud notebook to dashboard + */ + scope.addRCloudNotebook = function (rcloud_url) { + ++scope.options.unsavedChangeCount; + /* open a new prompt window */ + //event.preventDefault(); + var newreport = {"title":"R-Cloud","name":"r-cloud","style":{},"size":{"height":"450px","width":"40%"},"attrs":{"value":"randomValue"},"rcloud_url":rcloud_url}; +// console.log("newport"); + console.log(newreport) + scope.addWidget(newreport, true); + /* scope.addWidget("raptor-report");*/ + return false; + }; + + /** + * Uses dashboardState service to save state + */ + scope.saveDashboard = function (force) { + if (!scope.options.explicitSave) { + scope.dashboardState.save(scope.widgets); + } else { + if (!angular.isNumber(scope.options.unsavedChangeCount)) { + scope.options.unsavedChangeCount = 0; + } + if (force) { + scope.options.unsavedChangeCount = 0; + scope.dashboardState.save(scope.widgets); + + } else { + ++scope.options.unsavedChangeCount; + } + } + }; + + /** + * Wraps saveDashboard for external use. + */ + scope.externalSaveDashboard = function(force) { + if (angular.isDefined(force)) { + scope.saveDashboard(force); + } else { + scope.saveDashboard(true); + } + }; + + /** + * Clears current dash and instantiates widget definitions + * @param {Array} widgets Array of definition objects + */ + scope.loadWidgets = function (widgets) { + // AW dashboards are continuously saved today (no "save" button). + console.log("widgets") + scope.defaultWidgets = widgets; + widgets = + [ +// {"title":"DEMO Bar Chart","name":"raptor-report-chart","style":{},"size":{"height":"450px","width":"40%"},"attrs":{"value":"randomValue"},"report_id":"2"}, +// {"title":"Pie Chart","name":"raptor-report-data","style":{},"size":{"height":"450px","width":"40%"},"attrs":{"value":"randomValue"},"report_id":"5"}, +// {"title":"Pie Chart","name":"raptor-report-chart","style":{},"size":{"height":"450px","width":"40%"},"attrs":{"value":"randomValue"},"report_id":"5"} + ]; + console.log('widgets: '); + console.log(JSON.stringify(widgets)); + + scope.savedWidgetDefs = widgets; + scope.clear(true); + _.each(widgets, function (widgetDef) { + scope.addWidget(widgetDef, true); + }); + }; + + /** + * Resets widget instances to default config + * @return {[type]} [description] + */ + scope.resetWidgetsToDefault = function () { + scope.loadWidgets(scope.defaultWidgets); + scope.saveDashboard(); + }; + + // Set default widgets array + var savedWidgetDefs = scope.dashboardState.load(); + + // Success handler + function handleStateLoad(saved) { + scope.options.unsavedChangeCount = 0; + if (saved && saved.length) { + scope.loadWidgets(saved); + } else if (scope.defaultWidgets) { + scope.loadWidgets(scope.defaultWidgets); + } else { + scope.clear(true); + } + } + + if (angular.isArray(savedWidgetDefs)) { + handleStateLoad(savedWidgetDefs); + } else if (savedWidgetDefs && angular.isObject(savedWidgetDefs) && angular.isFunction(savedWidgetDefs.then)) { + savedWidgetDefs.then(handleStateLoad, handleStateLoad); + } else { + handleStateLoad(); + } + + // expose functionality externally + // functions are appended to the provided dashboard options + scope.options.addWidget = scope.addWidget; + scope.options.loadWidgets = scope.loadWidgets; + scope.options.saveDashboard = scope.externalSaveDashboard; + scope.options.removeWidget = scope.removeWidget; + scope.options.openWidgetSettings = scope.openWidgetSettings; + scope.options.clear = scope.clear; + scope.options.resetWidgetsToDefault = scope.resetWidgetsToDefault + + // save state + scope.$on('widgetChanged', function (event) { + event.stopPropagation(); + scope.saveDashboard(); + }); + } + }; + }]); diff --git a/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/dashboard.less b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/dashboard.less new file mode 100644 index 00000000..6b5b717f --- /dev/null +++ b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/dashboard.less @@ -0,0 +1,88 @@ +.dashboard-widget-area { + margin: 10px 0 30px; + min-height: 200px; +} + +.widget-container { + float:left; + display: inline-block; + width: 33%; + padding-bottom: 1em; +} + +.widget { + margin: 0 1em 0 0; + background-color: white; + border: 2px solid #444; + border-radius: 5px; + position: relative; + height: 100%; +} +.widget-header { + overflow: hidden; +} +.widget-header .label { + display: inline-block; + vertical-align: middle; +} +.widget-header .glyphicon { + cursor: pointer; + float: right; + opacity: 0.5; + margin-left: 5px; +} +.widget-header .glyphicon:hover { + opacity: 1; +} +.widget-header .widget-title { + vertical-align: middle; +} +.widget-header form.widget-title { + display: inline; +} + +.widget-header form.widget-title input.form-control { + width: auto; + display: inline-block; +} + +.widget-content { + overflow: hidden; +} + +.widget .widget-ew-resizer { + position: absolute; + width: 5px; + right: -2px; + height:100%; + top:0; + cursor: ew-resize; +} + +.widget .widget-s-resizer { + cursor: ns-resize; + height: 5px; + width: 100%; + bottom: -7px; + left: 0; +} + +.widget .widget-resizer-marquee { + box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5); + position: absolute; + top: 0; + left: 0; + z-index: 2; +} + +.remove-layout-icon { + vertical-align: text-top; + cursor: pointer; + opacity: 0.3; +} +.remove-layout-icon:hover { + opacity: 1; +} +.layout-title { + display: inline-block; +}
\ No newline at end of file diff --git a/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/dashboard.spec.js b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/dashboard.spec.js new file mode 100644 index 00000000..453de431 --- /dev/null +++ b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/dashboard.spec.js @@ -0,0 +1,878 @@ +/* + * Copyright (c) 2014 DataTorrent, Inc. 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. + */ + +'use strict'; + +describe('Directive: dashboard', function () { + + var scope, element, childScope, DashboardState, mockModal, modalOptions, $compile, $q, mockLog; + + // mock UI Sortable + beforeEach(function () { + angular.module('ui.sortable', []); + }); + + // load the directive's module + beforeEach(module('ui.dashboard', function($provide) { + mockModal = { + open: function(options) { + modalOptions = options; + } + }; + mockLog = { + info: function() { + + } + }; + $provide.value('$uibModal', mockModal); + $provide.value('$log', mockLog); + })); + + beforeEach(inject(function (_$compile_, $rootScope, _DashboardState_, _$q_) { + // services + scope = $rootScope.$new(); + $compile = _$compile_; + DashboardState = _DashboardState_; + $q = _$q_; + + // options + var widgetDefinitions = [ + { + name: 'wt-one', + template: '<div class="wt-one-value">{{2 + 2}}</div>' + }, + { + name: 'wt-two', + template: '<span class="wt-two-value">{{value}}</span>' + } + ]; + var defaultWidgets = _.clone(widgetDefinitions); + scope.dashboardOptions = { + widgetButtons: true, + widgetDefinitions: widgetDefinitions, + defaultWidgets: defaultWidgets, + sortableOptions: { + testProperty: 'foobar' + } + }; + scope.value = 10; + + // element setup + element = $compile('<div dashboard="dashboardOptions"></div>')(scope); + scope.$digest(); + childScope = element.scope(); + })); + + it('should have toolbar', function () { + var toolbar = element.find('.btn-toolbar'); + expect(toolbar.length).toEqual(1); + }); + + it('should have UI.Sortable directive', function () { + var widgetArea = element.find('.dashboard-widget-area'); + expect(widgetArea.attr('ui-sortable')).toBeDefined(); + }); + + it('should render widgets', function () { + var widgets = element.find('.widget'); + expect(widgets.length).toEqual(2); + }); + + it('should evaluate widget expressions', function () { + var divWidget = element.find('.wt-one-value'); + expect(divWidget.html()).toEqual('4'); + }); + + it('should evaluate scope expressions', function () { + var spanWidget = element.find('.wt-two-value'); + expect(spanWidget.html()).toEqual('10'); + }); + + it('should fill options with defaults', function() { + expect(scope.dashboardOptions.stringifyStorage).toEqual(true); + }); + + it('should not overwrite specified options with defaults', inject(function($compile) { + scope.dashboardOptions.stringifyStorage = false; + element = $compile('<div dashboard="dashboardOptions"></div>')(scope); + $compile(element)(scope); + scope.$digest(); + expect(scope.dashboardOptions.stringifyStorage).toEqual(false); + })); + + it('should be able to use a different dashboard template', inject(function($compile, $templateCache) { + $templateCache.put( + 'myCustomTemplate.html', + '<div>' + + '<div ui-sortable="sortableOptions" ng-model="widgets">' + + '<div ng-repeat="widget in widgets" ng-style="widget.style" class="widget-container custom-widget" widget>' + + '<h3 class="widget-header">' + + '{{widget.title}}' + + '<span ng-click="removeWidget(widget);" class="glyphicon glyphicon-remove icon-erase" ng-if="!options.hideWidgetClose"></span>' + + '<span ng-click="openWidgetSettings(widget);" class="glyphicon glyphicon-cog icon-settings" ng-if="!options.hideWidgetSettings"></span>' + + '</h3>' + + '<div class="widget-content"></div>' + + '<div class="widget-ew-resizer" ng-mousedown="grabResizer($event)"></div>' + + '</div>' + + '</div>' + + '</div>' + ); + var customElement = $compile('<div dashboard="dashboardOptions" template-url="myCustomTemplate.html"></div>')(scope); + scope.$digest(); + expect(customElement.find('.custom-widget').length).toEqual(2); + })); + + it('should set scope.widgets to an empty array if no defaultWidgets are specified', inject(function($compile) { + delete scope.dashboardOptions.defaultWidgets; + var element2 = $compile('<div dashboard="dashboardOptions"></div>')(scope); + scope.$digest(); + var childScope2 = element2.scope(); + expect(childScope2.widgets instanceof Array).toEqual(true); + })); + + it('should set options.unsavedChangeCount to 0 upon load', function() { + expect(scope.dashboardOptions.unsavedChangeCount).toEqual(0); + }); + + it('should not call saveDashboard on load', inject(function($compile) { + spyOn(DashboardState.prototype, 'save'); + var s = scope.$new(); + element = $compile('<div dashboard="dashboardOptions"></div>')(s); + scope.$digest(); + expect(DashboardState.prototype.save).not.toHaveBeenCalled(); + })); + + describe('the sortableOptions', function() { + + it('should exist', function() { + expect(typeof childScope.sortableOptions).toEqual('object'); + }); + + it('should be possible to be extendable from the dashboardOptions', function() { + expect(childScope.sortableOptions.testProperty).toEqual('foobar'); + }) + + it('should have a stop function that calls $scope.saveDashboard', function() { + expect(typeof childScope.sortableOptions.stop).toEqual('function'); + spyOn(childScope, 'saveDashboard'); + childScope.sortableOptions.stop(); + expect(childScope.saveDashboard).toHaveBeenCalled(); + }); + }); + + describe('the addWidget function', function() { + + var widgetCreated, widgetPassed, widgetDefault; + + beforeEach(function() { + childScope.widgets.push = function(w) { + widgetCreated = w; + } + }); + + it('should be a function', function() { + expect(typeof childScope.addWidget).toEqual('function'); + }); + + it('should throw if no default widgetDefinition was found', function() { + spyOn(childScope.widgetDefs, 'getByName').and.returnValue(false); + function fn () { + childScope.addWidget({ name: 'notReal' }); + } + expect(fn).toThrow(); + }); + + it('should look to the passed widgetToInstantiate object for the title before anything else', function() { + spyOn(childScope.widgetDefs, 'getByName').and.returnValue({ title: 'defaultTitle', name: 'A' }); + childScope.addWidget({ title: 'highestPrecedence', name: 'A' }); + expect(widgetCreated.title).toEqual('highestPrecedence'); + }); + + it('should use the defaultWidget\'s title second', function() { + spyOn(childScope.widgetDefs, 'getByName').and.returnValue({ title: 'defaultTitle', name: 'A' }); + childScope.addWidget({ name: 'A' }); + expect(widgetCreated.title).toEqual('defaultTitle'); + }); + + it('should call the saveDashboard method (internal)', function() { + spyOn(childScope.widgetDefs, 'getByName').and.returnValue({ title: 'defaultTitle', name: 'A' }); + spyOn(childScope, 'saveDashboard'); + childScope.addWidget({ name: 'A' }); + expect(childScope.saveDashboard).toHaveBeenCalled(); + }); + + it('should support passing just the widget name as a string', function() { + spyOn(childScope.widgetDefs, 'getByName').and.returnValue({ title: 'defaultTitle', name: 'A' }); + childScope.addWidget('A'); + expect(childScope.widgetDefs.getByName).toHaveBeenCalledWith('A'); + expect(widgetCreated.title).toEqual('defaultTitle'); + }); + + describe('@awashbrook Test Case', function() { + beforeEach(function() { + spyOn(childScope.widgetDefs, 'getByName').and.returnValue(widgetDefault = { + "name": "nvLineChartAlpha", + "directive": "nvd3-line-chart", + "dataAttrName": "data", + "attrs": { + "isArea": true, + "height": 400, + "showXAxis": true, + "showYAxis": true, + "xAxisTickFormat": "xAxisTickFormat()", + "interactive": true, + "useInteractiveGuideline": true, + "tooltips": true, + "showLegend": true, + "noData": "No data for YOU!", + "color": "colorFunction()", + "forcey": "[0,2]" + }, + "dataModelOptions": { + "params": { + "from": "-2h", + "until": "now" + } + }, + "style": { + "width": "400px" + }, + }); + childScope.addWidget(widgetPassed = { + "title": "Andy", + "name": "nvLineChartAlpha", + "style": { + "width": "400px" + }, + "dataModelOptions": { + "params": { + "from": "-1h", + "target": [ + "randomWalk(\"random Andy 1\")", + "randomWalk(\"random walk 2\")", + "randomWalk(\"random walk 3\")" + ] + } + }, + "attrs": { + "height": 400, + "showXAxis": true, + "showYAxis": true, + "xAxisTickFormat": "xAxisTickFormat()", + "interactive": false, + "useInteractiveGuideline": true, + "tooltips": true, + "showLegend": true, + "noData": "No data for YOU!", + "color": "colorFunction()", + "forcey": "[0,2]", + "data": "widgetData" + } + }); + }); + + it('should keep overrides from widgetPassed', function() { + expect(widgetCreated.attrs.interactive).toEqual(widgetPassed.attrs.interactive); + }); + + it('should fill in default attrs', function() { + expect(widgetCreated.attrs.isArea).toEqual(widgetDefault.attrs.isArea); + }); + + it('should override deep options in dataModelOptions', function() { + expect(widgetCreated.dataModelOptions.params.from).toEqual(widgetPassed.dataModelOptions.params.from); + }); + + it('should fill in deep default attrs', function() { + expect(widgetCreated.dataModelOptions.params.until).toEqual(widgetDefault.dataModelOptions.params.until); + }); + }); + + describe('the doNotSave parameter', function() { + + it('should prevent save from being called if set to true', function() { + spyOn(childScope.widgetDefs, 'getByName').and.returnValue({ title: 'defaultTitle', name: 'A' }); + spyOn(childScope, 'saveDashboard'); + childScope.addWidget({ name: 'A' }, true); + expect(childScope.saveDashboard).not.toHaveBeenCalled(); + }); + + }); + + }); + + describe('the removeWidget function', function() { + + it('should be a function', function() { + expect(typeof childScope.removeWidget).toEqual('function'); + }); + + it('should remove the provided widget from childScope.widgets array', function() { + var startingLength = childScope.widgets.length; + var expectedLength = startingLength - 1; + + var widgetToRemove = childScope.widgets[0]; + childScope.removeWidget(widgetToRemove); + + expect(childScope.widgets.length).toEqual(expectedLength); + expect(childScope.widgets.indexOf(widgetToRemove)).toEqual(-1); + }); + + it('should call saveDashboard', function() { + spyOn(childScope, 'saveDashboard'); + var widgetToRemove = childScope.widgets[0]; + childScope.removeWidget(widgetToRemove); + expect(childScope.saveDashboard).toHaveBeenCalled(); + }); + + }); + + describe('the saveDashboard function', function() { + + it('should be attached to the options object after initialization', function() { + expect(typeof scope.dashboardOptions.saveDashboard).toEqual('function'); + expect(scope.dashboardOptions.saveDashboard === childScope.externalSaveDashboard).toEqual(true); + }); + + it('should call scope.dashboardState.save when called internally if explicitSave is falsey', function() { + spyOn(childScope.dashboardState, 'save').and.returnValue(true); + childScope.saveDashboard(); + expect(childScope.dashboardState.save).toHaveBeenCalled(); + }); + + it('should not call scope.dashboardState.save when called internally if explicitSave is truthy', function() { + scope.dashboardOptions.explicitSave = true; + spyOn(childScope.dashboardState, 'save').and.returnValue(true); + childScope.saveDashboard(); + expect(childScope.dashboardState.save).not.toHaveBeenCalled(); + }); + + it('should call scope.dashboardState.save when called externally, no matter what explicitSave value is', function() { + spyOn(childScope.dashboardState, 'save').and.returnValue(true); + + scope.dashboardOptions.explicitSave = false; + scope.dashboardOptions.saveDashboard(); + expect(childScope.dashboardState.save.calls.count()).toEqual(1); + + scope.dashboardOptions.explicitSave = true; + scope.dashboardOptions.saveDashboard(); + expect(childScope.dashboardState.save.calls.count()).toEqual(2); + }); + + it('should keep a count of unsaved changes as unsavedChangeCount', function() { + scope.dashboardOptions.explicitSave = true; + spyOn(childScope.dashboardState, 'save').and.returnValue(true); + childScope.saveDashboard(); + expect(scope.dashboardOptions.unsavedChangeCount).toEqual(1); + childScope.saveDashboard(); + childScope.saveDashboard(); + expect(scope.dashboardOptions.unsavedChangeCount).toEqual(3); + }); + + it('should reset the cound of unsaved changes if a successful force save occurs', function() { + scope.dashboardOptions.explicitSave = true; + spyOn(childScope.dashboardState, 'save').and.returnValue(true); + + childScope.saveDashboard(); + childScope.saveDashboard(); + childScope.saveDashboard(); + + childScope.saveDashboard(true); + + expect(scope.dashboardOptions.unsavedChangeCount).toEqual(0); + }); + + }); + + describe('the loadWidgets function', function() { + + it('should be a function', function() { + expect(typeof childScope.loadWidgets).toEqual('function'); + }); + + it('should set savedWidgetDefs on scope as passed array', function() { + var widgets = []; + childScope.loadWidgets(widgets); + expect(childScope.savedWidgetDefs === widgets).toEqual(true); + }); + + it('should call clear on the scope with true as the only argument', function() { + spyOn(childScope, 'clear'); + childScope.loadWidgets([]); + expect(childScope.clear).toHaveBeenCalled(); + expect(childScope.clear.calls.argsFor(0)).toEqual([true]); + }); + + it('should call addWidget for each widget in the array', function() { + spyOn(childScope, 'addWidget').and.returnValue(null); + var widgets = [{},{},{}]; + childScope.loadWidgets(widgets); + expect(childScope.addWidget.calls.count()).toEqual(3); + }); + + it('should call addWidget for each widget with true as the second parameter (doNotSave)', function() { + spyOn(childScope, 'addWidget').and.returnValue(null); + var widgets = [{},{},{}]; + childScope.loadWidgets(widgets); + expect(childScope.addWidget.calls.argsFor(0)).toEqual( [ widgets[0], true] ); + expect(childScope.addWidget.calls.argsFor(1)).toEqual( [ widgets[1], true] ); + expect(childScope.addWidget.calls.argsFor(2)).toEqual( [ widgets[2], true] ); + }); + + }); + + describe('the clear function', function() { + + it('should set the scope to an empty array', function() { + childScope.clear(); + expect(childScope.widgets).toEqual([]); + }); + + it('should not call saveDashboard if first arg is true', function() { + spyOn(childScope, 'saveDashboard'); + childScope.clear(true); + expect(childScope.saveDashboard).not.toHaveBeenCalled(); + }); + + it('should call saveDashboard if first arg is not true', function() { + spyOn(childScope, 'saveDashboard'); + childScope.clear(); + expect(childScope.saveDashboard).toHaveBeenCalled(); + }); + + }); + + describe('the openWidgetSettings function', function() { + + it('should be a function', function() { + expect(typeof childScope.openWidgetSettings).toEqual('function'); + }); + + it('should call $uibModal.open with default options', function() { + var widget = {}; + spyOn(mockModal, 'open').and.returnValue({ + result: { then: function(fn) {} } + }); + childScope.openWidgetSettings(widget); + expect(mockModal.open).toHaveBeenCalled(); + }); + + it('should have widget in the resolve object', function() { + var widget = {}; + var dfr = $q.defer(); + spyOn(mockModal, 'open').and.callFake(function(options) { + modalOptions = options; + return { + result: dfr.promise + }; + }); + childScope.openWidgetSettings(widget); + expect(modalOptions.resolve.widget() === widget).toEqual(true); + }); + + it('should set the templateUrl in modal options to the default ("app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/widget-settings-template.html")', function() { + var widget = {}; + var dfr = $q.defer(); + spyOn(mockModal, 'open').and.callFake(function(options) { + modalOptions = options; + return { + result: dfr.promise + }; + }); + childScope.openWidgetSettings(widget); + expect(modalOptions.templateUrl).toEqual('app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/widget-settings-template.html'); + }); + + it('should set the templateUrl in modal options to scope.options.settingsModalOptions.templateUrl', function() { + var other; + scope.dashboardOptions.settingsModalOptions = { + templateUrl: other = 'some/other/url.html' + }; + var widget = {}; + var dfr = $q.defer(); + spyOn(mockModal, 'open').and.callFake(function(options) { + modalOptions = options; + return { + result: dfr.promise + }; + }); + childScope.openWidgetSettings(widget); + expect(modalOptions.templateUrl).toEqual(other); + }); + + it('should set the templateUrl in modal options to widget.settingsModalOptions.templateUrl, if present', function() { + var expected; + var widget = { + settingsModalOptions: { + templateUrl: expected = 'specific/template.html' + } + }; + var dfr = $q.defer(); + spyOn(mockModal, 'open').and.callFake(function(options) { + modalOptions = options; + return { + result: dfr.promise + }; + }); + childScope.openWidgetSettings(widget); + expect(modalOptions.templateUrl).toEqual(expected); + }); + + it('should set the controller in modal options to the default ("WidgetSettingsCtrl")', function() { + var widget = {}; + var dfr = $q.defer(); + spyOn(mockModal, 'open').and.callFake(function(options) { + modalOptions = options; + return { + result: dfr.promise + }; + }); + childScope.openWidgetSettings(widget); + expect(modalOptions.controller).toEqual('WidgetSettingsCtrl'); + }); + + it('should set the controller in modal options to the default ("WidgetSettingsCtrl"), even when settingsModalOptions is supplied in options', inject(function($rootScope) { + + scope = $rootScope.$new(); + + // options + var widgetDefinitions = [ + { + name: 'wt-one', + template: '<div class="wt-one-value">{{2 + 2}}</div>' + }, + { + name: 'wt-two', + template: '<span class="wt-two-value">{{value}}</span>' + } + ]; + var defaultWidgets = _.clone(widgetDefinitions); + scope.dashboardOptions = { + widgetButtons: true, + widgetDefinitions: widgetDefinitions, + defaultWidgets: defaultWidgets, + sortableOptions: { + testProperty: 'foobar' + }, + settingsModalOptions: { + backdrop: false + } + }; + scope.value = 10; + + var dfr = $q.defer(); + spyOn(mockModal, 'open').and.callFake(function(options) { + modalOptions = options; + return { + result: dfr.promise + }; + }); + + // element setup + element = $compile('<div dashboard="dashboardOptions"></div>')(scope); + scope.$digest(); + childScope = element.scope(); + + childScope.openWidgetSettings({}); + expect(modalOptions.controller).toEqual('WidgetSettingsCtrl'); + + })); + + it('should set the controller in modal options to the default ("WidgetSettingsCtrl"), even when settingsModalOptions is supplied in widget', inject(function($rootScope) { + + scope = $rootScope.$new(); + + // options + var widgetDefinitions = [ + { + name: 'wt-one', + template: '<div class="wt-one-value">{{2 + 2}}</div>' + }, + { + name: 'wt-two', + template: '<span class="wt-two-value">{{value}}</span>' + } + ]; + var defaultWidgets = _.clone(widgetDefinitions); + scope.dashboardOptions = { + widgetButtons: true, + widgetDefinitions: widgetDefinitions, + defaultWidgets: defaultWidgets, + sortableOptions: { + testProperty: 'foobar' + }, + settingsModalOptions: { + backdrop: false + } + }; + scope.value = 10; + + var dfr = $q.defer(); + spyOn(mockModal, 'open').and.callFake(function(options) { + modalOptions = options; + return { + result: dfr.promise + }; + }); + + // element setup + element = $compile('<div dashboard="dashboardOptions"></div>')(scope); + scope.$digest(); + childScope = element.scope(); + + childScope.openWidgetSettings({ + settingsModalOptions: { + templateUrl: 'custom/widget/template.html' + } + }); + expect(modalOptions.controller).toEqual('WidgetSettingsCtrl'); + expect(modalOptions.backdrop).toEqual(false); + expect(modalOptions.templateUrl).toEqual('custom/widget/template.html'); + + })); + + it('should set the controller to scope.options.settingsModalOptions.controller if provided', function() { + scope.dashboardOptions.settingsModalOptions = {}; + var expected = scope.dashboardOptions.settingsModalOptions.controller = 'MyCustomCtrl'; + var widget = {}; + var dfr = $q.defer(); + spyOn(mockModal, 'open').and.callFake(function(options) { + modalOptions = options; + return { + result: dfr.promise + }; + }); + childScope.openWidgetSettings(widget); + expect(modalOptions.controller).toEqual(expected); + }); + + it('should set the controller to widget.settingsModalOptions.controller if provided', function() { + var expected; + var widget = { + settingsModalOptions: { + controller: expected = 'MyWidgetCtrl' + } + }; + var dfr = $q.defer(); + spyOn(mockModal, 'open').and.callFake(function(options) { + modalOptions = options; + return { + result: dfr.promise + }; + }); + childScope.openWidgetSettings(widget); + expect(modalOptions.controller).toEqual(expected); + }); + + it('should pass in other modal options set in scope.options.settingsModalOptions', function() { + scope.dashboardOptions.settingsModalOptions = { + keyboard: false, + windowClass: 'my-extra-class' + }; + var widget = {}; + var dfr = $q.defer(); + spyOn(mockModal, 'open').and.callFake(function(options) { + modalOptions = options; + return { + result: dfr.promise + }; + }); + childScope.openWidgetSettings(widget); + expect(modalOptions.keyboard).toEqual(false); + expect(modalOptions.windowClass).toEqual('my-extra-class'); + }); + + it('should pass in other modal options set in widget.settingsModalOptions', function() { + scope.dashboardOptions.settingsModalOptions = { + keyboard: false, + windowClass: 'my-extra-class' + }; + var widget = { + settingsModalOptions: { + keyboard: true, + size: 'sm' + } + }; + var dfr = $q.defer(); + spyOn(mockModal, 'open').and.callFake(function(options) { + modalOptions = options; + return { + result: dfr.promise + }; + }); + childScope.openWidgetSettings(widget); + expect(modalOptions.keyboard).toEqual(true); + expect(modalOptions.size).toEqual('sm'); + expect(modalOptions.windowClass).toEqual('my-extra-class'); + }); + + it('should emit a "widgetChanged" event on the childScope when the modal promise is called', function(done) { + var widget = {}; + var result = {}; + var dfr = $q.defer(); + spyOn(mockModal, 'open').and.callFake(function(options) { + modalOptions = options; + return { + result: dfr.promise + }; + }); + spyOn(childScope.options, 'onSettingsClose'); + childScope.openWidgetSettings(widget); + childScope.$on('widgetChanged', done); + dfr.resolve(result, widget); + childScope.$digest(); + }); + + it('should call scope.options.onSettingsClose when the modal promise is resolved by default', function() { + var widget = {}; + var result = {}; + var dfr = $q.defer(); + spyOn(mockModal, 'open').and.callFake(function(options) { + modalOptions = options; + return { + result: dfr.promise + }; + }); + spyOn(childScope.options, 'onSettingsClose'); + childScope.openWidgetSettings(widget); + dfr.resolve(result); + childScope.$digest(); + expect(scope.dashboardOptions.onSettingsClose).toHaveBeenCalledWith(result, widget, childScope); + }); + + it('should call scope.options.onSettingsDismiss when the modal promise is rejected by default', function() { + var widget = {}; + var result = {}; + var dfr = $q.defer(); + spyOn(mockModal, 'open').and.callFake(function(options) { + modalOptions = options; + return { + result: dfr.promise + }; + }); + spyOn(childScope.options, 'onSettingsDismiss'); + childScope.openWidgetSettings(widget); + dfr.reject('Testing failure'); + childScope.$digest(); + expect(scope.dashboardOptions.onSettingsDismiss).toHaveBeenCalledWith('Testing failure', childScope); + }); + + it('should call widget.onSettingsClose if provided when the modal promise is resolved', function() { + var widget = { + onSettingsClose: function(result, widget, scope) { + + } + }; + var result = {}; + var dfr = $q.defer(); + spyOn(widget, 'onSettingsClose'); + spyOn(mockModal, 'open').and.callFake(function(options) { + modalOptions = options; + return { + result: dfr.promise + }; + }); + spyOn(childScope.options, 'onSettingsClose'); + childScope.openWidgetSettings(widget); + dfr.resolve(result); + childScope.$digest(); + expect(scope.dashboardOptions.onSettingsClose).not.toHaveBeenCalled(); + expect(widget.onSettingsClose).toHaveBeenCalledWith(result, widget, childScope); + }); + + it('should call widget.onSettingsDismiss if provided when the modal promise is rejected', function() { + var widget = { + onSettingsDismiss: function(result, widget, scope) { + + } + }; + var result = {}; + var dfr = $q.defer(); + spyOn(widget, 'onSettingsDismiss'); + spyOn(mockModal, 'open').and.callFake(function(options) { + modalOptions = options; + return { + result: dfr.promise + }; + }); + spyOn(childScope.options, 'onSettingsDismiss'); + childScope.openWidgetSettings(widget); + dfr.reject('Testing failure'); + childScope.$digest(); + expect(scope.dashboardOptions.onSettingsDismiss).not.toHaveBeenCalled(); + expect(widget.onSettingsDismiss).toHaveBeenCalledWith('Testing failure', childScope); + }); + + }); + + describe('the default onSettingsClose callback', function() { + + var onSettingsClose; + + beforeEach(function() { + onSettingsClose = childScope.options.onSettingsClose; + }); + + it('should exist', function() { + expect(typeof onSettingsClose).toEqual('function'); + }); + + it('should deep extend widget with result', function() { + var result = { + title: 'andy', + style: { + 'float': 'left' + } + }; + var widget = { + title: 'scott', + style: { + width: '100px' + } + }; + onSettingsClose(result, widget, {}); + expect(widget).toEqual({ + title: 'andy', + style: { + width: '100px', + 'float': 'left' + } + }); + }); + + }); + + describe('the default onSettingsDismiss callback', function() { + + var onSettingsDismiss; + + beforeEach(function() { + onSettingsDismiss = childScope.options.onSettingsDismiss; + }); + + it('should exist', function() { + expect(typeof onSettingsDismiss).toEqual('function'); + }); + + it('should call $log.info with the reason', function() { + spyOn(mockLog, 'info'); + onSettingsDismiss('dismiss reason'); + expect(mockLog.info).toHaveBeenCalled(); + }); + + }); + +}); diff --git a/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/widget-settings-raptor-report-template.html b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/widget-settings-raptor-report-template.html new file mode 100644 index 00000000..7a533c3f --- /dev/null +++ b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/widget-settings-raptor-report-template.html @@ -0,0 +1,58 @@ +<div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="cancel()">×</button> + <h3>Widget Options <small>{{widget.title}}</small></h3> +</div> + +<div class="modal-body"> + <form name="form" novalidate class="form-horizontal"> +<!-- <div class="form-group"> + <label for="widgetTitle" class="col-sm-2 control-label">Title</label> + <div style="margin-left:120px" class="col-sm-10"> + <input type="text" class="form-control" name="widgetTitle" ng-model="result.title"> + </div> + </div> --> + +<!-- <div>{{showFormFieldIds}}</div> +<div>{{formFieldSelectedValues}}</div> +<div>{{JSON.strigify(widget.reportData.formFieldList)}}</div> + --> +<form ng-show="true" class="row section-row" style="margin: 10px"> + <form-builder ng-form-fields="reportData.formFieldList" ng-show-field-id="showFormFieldIds" ng-num-form-cols="reportData.numFormCols" ng-model="formFieldSelectedValues" ng-trigger-method="triggerOtherFormFields"></form-builder> +</form> + +<!-- <div ng-repeat="formfield in widget.reportData.formFieldList"> + <div class="form-group"> + <label for="widgetTitle" class="col-sm-2 control-label">{{formfield.fieldDisplayName}}:</label> + <div style="margin-left:120px" class="col-sm-10"> + <input type="text" class="form-control" name="widgetTitle" ng-model="formfield.title"> + </div> + </div> + </div> --> +<!-- <div ng-repeat="(formfield_key,formfield_value) in widget.reportData.formFieldList[0]" class="form-group"> + <label for="widgetTitle" class="col-sm-2 control-label">{{formfield_key}}</label> + <div style="margin-left:120px" class="col-sm-10"> + <input type="text" class="form-control" name="widgetTitle" ng-model="formfield_value"> + </div> + </div> --> + + + <div ng-if="widget.settingsModalOptions.partialTemplateUrl" + ng-include="widget.settingsModalOptions.partialTemplateUrl"></div> + +<!-- + <div ng-show="true" id="grid1" ui-grid="gridOptions" ui-grid-pagination ui-grid-pinning ui-grid-resize-columns class="grid" style="height: {{gridHeight}}"> + <div class="no-rows" ng-show="!gridOptions.data.length"> + <div class="msg"> + <span>{{widget.reportData.message}}</span> + </div> + </div> + </div> + --> + </form> + +</div> + +<div class="modal-footer"> + <button type="button" class="btn btn-default" ng-click="cancel()">Cancel</button> + <button type="button" class="btn btn-primary" ng-click="ok()">OK</button> +</div>
\ No newline at end of file diff --git a/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/widget-settings-template.html b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/widget-settings-template.html new file mode 100644 index 00000000..a57d4366 --- /dev/null +++ b/ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/view-models/reportdashboard-page/src/components/directives/dashboard/widget-settings-template.html @@ -0,0 +1,22 @@ +<div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="cancel()">×</button> + <h3>Widget Options <small>{{widget.title}}</small></h3> +</div> + +<div class="modal-body"> + <form name="form" novalidate class="form-horizontal"> + <div class="form-group"> + <label for="widgetTitle" class="col-sm-2 control-label">Title</label> + <div class="col-sm-10"> + <input type="text" class="form-control" name="widgetTitle" ng-model="result.title"> + </div> + </div> + <div ng-if="widget.settingsModalOptions.partialTemplateUrl" + ng-include="widget.settingsModalOptions.partialTemplateUrl"></div> + </form> +</div> + +<div class="modal-footer"> + <button type="button" class="btn btn-default" ng-click="cancel()">Cancel</button> + <button type="button" class="btn btn-primary" ng-click="ok()">OK</button> +</div>
\ No newline at end of file |