diff options
Diffstat (limited to 'ecomp-portal-FE/client/app/views/functionalMenu')
8 files changed, 1269 insertions, 0 deletions
diff --git a/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.controller.js b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.controller.js new file mode 100644 index 00000000..0d27d868 --- /dev/null +++ b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.controller.js @@ -0,0 +1,384 @@ +/*- + * ================================================================================ + * eCOMP Portal + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property + * ================================================================================ + * 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'; +(function () { + class MenuDetailsModalCtrl { + constructor($scope, $log, functionalMenuService, errorMessageByCode, ECOMP_URL_REGEX,$rootScope,confirmBoxService) { + let newMenuModel = { + name: null, + menuId: null, + parentMenuId: null, + url: null + }; + + let getAvailableRoles = (appid) => { + this.isSaving = true; + if (appid != null) { + $log.debug("MenuDetailsModalCtrl::getAvailableRoles: About to call getManagedRolesMenu"); + functionalMenuService.getManagedRolesMenu(appid).then(rolesObj => { + $log.debug("MenuDetailsModalCtrl::getAvailableRoles: Roles returned = " + JSON.stringify(rolesObj)) + this.availableRoles = rolesObj; + this.preSelectedRoles = {roles:[]}; + + if(($scope.ngDialogData.source=='edit') && this.isMidLevelMenuItem()){ + this.preSelectedRoles = {roles:[]}; + }else if(!angular.isUndefined(this.menuItem.menuDetails) && + $scope.ngDialogData.source=='edit' && this.isLeafMenuItem() && + this.menuItem.menuDetails.appid!=appid) { + this.preSelectedRoles = {roles:[]}; + }else{ + if((!angular.isUndefined(this.menuItem.menuDetails)) && + (!angular.isUndefined(this.menuItem.menuDetails.roles))){ + $log.debug('menuDetails.roles: ' + this.menuItem.menuDetails.roles); + for(var i=0; i<this.menuItem.menuDetails.roles.length; i++){ + var role = {"roleId":this.menuItem.menuDetails.roles[i]}; + $log.debug('MenuDetailsModalCtrl::getAvailableRoles: adding role to preselected: ' + i + ': ' + JSON.stringify(role)); + this.preSelectedRoles.roles.push(role); + } + } + } + $rootScope.$broadcast('availableRolesReady'); + this.isSaving = false; + }).catch(err => { + $log.error("MenuDetailsModalCtrl::getAvailableRoles: error: " + err); + }); + } else { + $log.debug("MenuDetailsModalCtrl::getAvailableRoles: appid was null"); + } + }; + + let getAvailableApps = () => { + functionalMenuService.getAvailableApplications().then(apps => { + $log.debug("MenuDetailsModalCtrl::getAvailableApps: Apps returned = " + JSON.stringify(apps)) + this.availableApps = apps; + if (angular.isDefined(this.selectedApp) && angular.isDefined(this.selectedApp.index)) { + for (var i = 0; i < apps.length; i++) { + if (apps[i].index === this.selectedApp.index) { + $log.debug("MenuDetailsModalCtrl::getAvailableApps: found app with index: " + this.selectedApp.index); + $log.debug("MenuDetailsModalCtrl::getAvailableApps: setting isDisabled to: " + !apps[i].enabled); + this.selectedApp.isDisabled = !apps[i].enabled; + break; + } + } + $log.debug("didn't find index: " + this.selectedApp.index); + } + })['catch'](function (err) { + $log.error("MenuDetailsModalCtrl::getAvailableApps: getAvailableApps error: " + err); + }).finally(()=>{ + this.isSaving = false; + }); + }; + + let init = () => { + $log.info('MenuDetailsModalCtrl::init'); + this.saveOrContinueBtnText = "Save"; + this.isSaving = false; + this.displayRoles = $scope.ngDialogData.source=='view' ? true : false; + this.formEditable = $scope.ngDialogData.source=='view' ? false : true; + this.selectedRole = []; + this.availableRoles = []; + this.menuItem = _.clone($scope.ngDialogData.menuItem); + $log.info('MenuDetailsModalCtrl::getAvailableApps: Within init, about to check menuDetails for defined'); + if(!angular.isUndefined(this.menuItem.menuDetails) && + ($scope.ngDialogData.source=='view' || + ($scope.ngDialogData.source=='edit') && this.isLeafMenuItem() )){ + + $log.debug("MenuDetailsModalCtrl::init: menuItem: "); + $log.debug('MenuDetailsModalCtrl::init: ',this.menuItem); + this.menuItem.menu.url = this.menuItem.menuDetails.url; + this.selectedApp={}; + this.selectedApp.index = this.menuItem.menuDetails.appid; + getAvailableRoles(this.selectedApp.index); + + } + + if($scope.ngDialogData.source=='view' || $scope.ngDialogData.source=='edit'){ + this.menutitle = this.menuItem.menu.name; + this.menuLocation = this.isParentMenuItem() ? this.menuItem.menu.name : this.menuItem.menu.parent.name; + }else{ + this.menutitle = ''; + this.menuLocation = this.menuItem.menu.name; + } + getAvailableApps(); + $log.debug("MenuDetailsModalCtrl::init: Menu details: " + JSON.stringify(this.menuItem.menuDetails)); + }; + + + this.ECOMP_URL_REGEX = ECOMP_URL_REGEX; + + this.conflictMessages = {}; + this.scrollApi = {}; + let handleConflictErrors = err => { + if(!err.data){ + return; + } + if(!err.data.length){ + err.data = [err.data] + } + $log.debug('MenuDetailsModalCtrl::handleConflictErrors: err.data = ' + JSON.stringify(err.data)); + _.forEach(err.data, item => { + _.forEach(item.fields, field => { + this.conflictMessages[field.name] = errorMessageByCode[item.errorCode]; + $log.debug('MenuDetailsModalCtrl::handleConflictErrors: fieldName = ' + field.name); + $scope.functionalMenuForm[field.name].$setValidity('conflict', false); + watchOnce[field.name](); + }); + }); + this.scrollApi.scrollTop(); + }; + + let resetConflict = fieldName => { + delete this.conflictMessages[fieldName]; + $log.debug('MenuDetailsModalCtrl::resetConflict: $setValidity(true) = ' + fieldName); + if($scope.functionalMenuForm[fieldName]){ + $scope.functionalMenuForm[fieldName].$setValidity('conflict', true); + } + }; + + let watchOnce = { + text: () => { + let unregisterName = $scope.$watch('functionalMenuDetails.menutitle', (newVal, oldVal) => { + if(newVal.toLowerCase() !== oldVal.toLowerCase()){ + resetConflict('text'); + unregisterName(); + } + }); + }, + url: () => { + let unregisterUrl = $scope.$watch('functionalMenuDetails.menuItem.menu.url', (newVal, oldVal) => { + if(newVal.toLowerCase() !== oldVal.toLowerCase()){ + resetConflict('url'); + unregisterUrl(); + } + }); + } + }; + + //*************************** + + this.isLeafMenuItem = () => { + return this.menuItem.menu.children.length>0 ? false : true; + }; + + this.isMidLevelMenuItem = () => { + return this.menuItem.menu.parentMenuId!=null && this.menuItem.menu.children.length>0 ? true : false; + }; + + this.isParentMenuItem = () => { + return this.menuItem.menu.parentMenuId!=null ? false : true; + }; + + this.updateSelectedApp = (appItem) => { + if (!appItem) { + return; + } + $log.debug('MenuDetailsModalCtrl::updateSelectedApp: drop down app item = ' + JSON.stringify(appItem.index)); + $log.debug("MenuDetailsModalCtrl::updateSelectedApp: appItem in updateSelectedApp: "); + $log.debug('MenuDetailsModalCtrl::updateSelectedApp: ',appItem); + this.selectedApp.isDisabled = ! appItem.enabled; + $log.debug("MenuDetailsModalCtrl::updateSelectedApp: isDisabled: "+this.selectedApp.isDisabled); + getAvailableRoles(appItem.index); + }; + + this.continue = () => { + this.displayRoles = true; + this.formEditable = false; + }; + + this.saveChanges = () => { + + if(!!this.menuItem.menu.url && (angular.isUndefined(this.selectedApp) || !this.selectedApp.index>0)) { + confirmBoxService.showInformation('Please select the appropriate app, or remove the url').then(isConfirmed => {}); + return; + }else if(!this.menuItem.menu.url && !angular.isUndefined(this.selectedApp) && this.selectedApp.index>0){ + confirmBoxService.showInformation('Please enter url, or select "No Application"').then(isConfirmed => {}); + return; + }else if(!this.menutitle){ + confirmBoxService.showInformation('Please enter the Menu title').then(isConfirmed => {}); + return; + } + + this.isSaving = true; + var activeMenuItem = {}; + + if ($scope.ngDialogData.source == 'edit') { + $log.debug('MenuDetailsModalCtrl::saveChanges: Will be saving an edit menu item'); + activeMenuItem = { + menuId:this.menuItem.menu.menuId, + column:this.menuItem.menu.column, + text:this.menutitle, + parentMenuId:this.menuItem.menu.parentMenuId, + url:this.menuItem.menu.url, + appid: angular.isUndefined(this.selectedApp) ? null:this.selectedApp.index, + roles:this.selectedRole + }; + if (!activeMenuItem.appid && !activeMenuItem.url) { + activeMenuItem.roles = null; + } + functionalMenuService.saveEditedMenuItem(activeMenuItem) + .then(() => { + $log.debug('MenuDetailsModalCtrl::saveChanges: Menu Item saved'); + $scope.closeThisDialog(true); + }).catch(err => { + if(err.status === 409){ + handleConflictErrors(err); + } + $log.error('MenuDetailsModalCtrl::saveChanges: error - ',err); + }).finally(()=>{ + this.isSaving = false; + }); + + $log.debug("MenuDetailsModalCtrl::saveChanges: Edit Menu output will be: " + JSON.stringify(activeMenuItem)); + } else { + $log.debug('MenuDetailsModalCtrl::saveChanges: Will be saving a New menu item'); + var newMenuItem = { + menuId:null, + column:this.menuItem.menu.column, + text:this.menutitle, + parentMenuId:this.menuItem.menu.menuId, + url:this.menuItem.menu.url, + appid: angular.isUndefined(this.selectedApp) ? null:this.selectedApp.index, + roles:this.selectedRole + }; + + $log.debug("MenuDetailsModalCtrl::saveChanges: New Menu output will be: " + JSON.stringify(newMenuItem)); + functionalMenuService.saveMenuItem(newMenuItem) + .then(() => { + $log.debug('MenuDetailsModalCtrl::saveChanges: Menu Item saved'); + $scope.closeThisDialog(true); + }).catch(err => { + if(err.status === 409){//Conflict + handleConflictErrors(err); + } + $log.error('MenuDetailsModalCtrl::saveChanges error: ', err); + }).finally(()=>{ + this.isSaving = false; + }); + + } + }; + + init(); + + $scope.$on('$stateChangeStart', e => { + e.preventDefault(); + }); + } + } + MenuDetailsModalCtrl.$inject = ['$scope', '$log', 'functionalMenuService', 'errorMessageByCode', 'ECOMP_URL_REGEX','$rootScope','confirmBoxService']; + angular.module('ecompApp').controller('MenuDetailsModalCtrl', MenuDetailsModalCtrl); + + angular.module('ecompApp').directive('dropdownMultiselect', ['functionalMenuService',function(){ + return { + restrict: 'E', + scope: { + model: '=', + options: '=', + populated_roles: '=preSelected', + dropdownTitle: '@', + source: '=' + }, + template: "<div class='btn-group' data-ng-class='{open: open}'>" + + "<button class='btn btn-medium'>{{dropdownTitle}}</button>" + + "<button class='btn dropdown-toggle' data-ng-click='open=!open;openDropDown()'><span class='caret'></span></button>" + + "<ul class='dropdown-menu dropdown-menu-medium' aria-labelledby='dropdownMenu'>" + + "<li data-ng-repeat='option in options'> <input ng-disabled='setDisable(source)' type='checkbox' data-ng-change='setSelectedItem(option.roleId)' ng-model='selectedItems[option.roleId]'>{{option.rolename}}</li>" + + "</ul>" + + "</div>", + controller: function ($scope) { + $scope.selectedItems = {}; + $scope.checkAll = false; + $scope.$on('availableRolesReady', function() { + init(); + }); + + function init() { + console.log('dropdownMultiselect init'); + $scope.dropdownTitle = $scope.source =='view' ? 'View Roles' : 'Select Roles'; + console.log('$scope.populated_roles = ' + $scope.populated_roles); + } + + $scope.$watch('populated_roles', function(){ + if ($scope.populated_roles && $scope.populated_roles.length>0) { + for (var i = 0; i < $scope.populated_roles.length; i++) { + $scope.model.push($scope.populated_roles[i].roleId); + $scope.selectedItems[$scope.populated_roles[i].roleId] = true; + } + if ($scope.populated_roles.length == $scope.options.length) { + $scope.checkAll = true; + } + }else{ + deselectAll(); + } + }); + + $scope.openDropDown = function () { + + }; + + $scope.checkAllClicked = function () { + if ($scope.checkAll) { + selectAll(); + } else { + deselectAll(); + } + }; + + function selectAll() { + $scope.model = []; + $scope.selectedItems = {}; + angular.forEach($scope.options, function (option) { + $scope.model.push(option.roleId); + }); + angular.forEach($scope.model, function (id) { + $scope.selectedItems[id] = true; + }); + console.log($scope.model); + }; + + function deselectAll() { + $scope.model = []; + $scope.selectedItems = {}; + console.log($scope.model); + }; + + $scope.setSelectedItem = function (id) { + var filteredArray = []; + if ($scope.selectedItems[id] == true) { + $scope.model.push(id); + } else { + filteredArray = $scope.model.filter(function (value) { + return value != id; + }); + $scope.model = filteredArray; + $scope.checkAll = false; + } + console.log(filteredArray); + return false; + }; + + $scope.setDisable = function(source){ + return source =='view' ? true : false; + } + } + } + }]); + +})(); diff --git a/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.delete.modal.html b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.delete.modal.html new file mode 100644 index 00000000..7157886b --- /dev/null +++ b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.delete.modal.html @@ -0,0 +1,35 @@ +<!-- + ================================================================================ + eCOMP Portal + ================================================================================ + Copyright (C) 2017 AT&T Intellectual Property + ================================================================================ + 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. + ================================================================================ + --> +<div class="functionalMenu-details-modal"> + <div class="title">Delete Menu Item</div> + <div class="functionalMenu-properties-main" scroll-top="functionalMenuDetails.scrollApi"> + <form name="functionalMenuForm" novalidate> + <div class="confirmation-message-wrap"> + <div class="confirmation-message" ng-bind="confirmBox.message"></div> + </div> + </form> + </div> + <div class="dialog-control"> + <span class="ecomp-save-spinner" ng-show="functionalMenuDetails.isSaving"></span> + <div id='menu-details-next-button' class="next-button" + ng-class="{disabled: functionalMenuForm.$invalid}" ng-click="functionalMenuDetails.saveChanges()">Delete</div> + <div class="cancel-button" ng-click="closeThisDialog()">Cancel</div> + </div> +</div> diff --git a/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.modal.html b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.modal.html new file mode 100644 index 00000000..58588ce5 --- /dev/null +++ b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.modal.html @@ -0,0 +1,106 @@ +<!-- + ================================================================================ + eCOMP Portal + ================================================================================ + Copyright (C) 2017 AT&T Intellectual Property + ================================================================================ + 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. + ================================================================================ + --> +<div class="functionalMenu-details-modal"> + <div class="title">{{ngDialogData.title}}</div> + <div class="functionalMenu-properties-main" scroll-top="functionalMenuDetails.scrollApi"> + <form name="functionalMenuForm"> + <div class="item"> + <div class="item-label">Parent</div> + <input id="input-parent" readonly="readonly" class="input-field" + value="{{functionalMenuDetails.menuLocation}}" type="text" name="menuItem" required/> + </div> + <div class="item"> + <div class="item-label">Title</div> + <input id="input-title" ng-readonly="!functionalMenuDetails.formEditable ? 'checked':'' " + placeholder="Enter text" class="input-field" ng-model="functionalMenuDetails.menutitle" type="text" name="text"/> + <div id="div-error-conflict" class="error-container" ng-show="functionalMenuDetails.conflictMessages.text"> + <small id="msg-error-conflict" id="functionalMenuDetails-input-title-conflict" + class="err-message" ng-bind="functionalMenuDetails.conflictMessages.text"></small> + </div> + </div> + <div class="item"> + <div class="left-item"> + <div class="item-label">URL</div> + <input id="input-url" ng-readonly="!functionalMenuDetails.formEditable ? 'checked':'' " + placeholder="http://" class="input-field" ng-model="functionalMenuDetails.menuItem.menu.url" type="url" name="url"/> + <span id="error-url-conflict" class="err-message" ng-show="functionalMenuForm.url.$error.url"> Not valid URL!</span> + </div> + <div class="right-item"> + <div class="item-label">App</div> + <div class="custom-select-wrap" ng-readonly="checked"> + <select id="select-app" class="select-field" + ng-model="functionalMenuDetails.selectedApp" + ng-change="functionalMenuDetails.updateSelectedApp(functionalMenuDetails.selectedApp);" + ng-options="app.title for app in functionalMenuDetails.availableApps track by app.index" + ng-disabled="!functionalMenuDetails.availableApps || !functionalMenuDetails.availableApps.length + || !functionalMenuDetails.formEditable" + name="app" + required> + <option value="" >No Application</option> + </select> + </div> + </div> + </div> + <div class="item" ng-show="functionalMenuDetails.displayRoles==true"> + <div class="item-label">Roles</div> + <dropdown-multiselect id="dropdown-roles" dropdown-title="Select Roles" + pre-selected="functionalMenuDetails.preSelectedRoles.roles" + model="functionalMenuDetails.selectedRole" + options="functionalMenuDetails.availableRoles" source="ngDialogData.source"> + </dropdown-multiselect> + </div> + <div ng-show="functionalMenuDetails.selectedApp && functionalMenuDetails.selectedApp.isDisabled" class="err-message">Application is disabled</div> + </form> + </div> + <div class="dialog-control"> + <div ng-if="ngDialogData.source!='view'"> + <span class="ecomp-save-spinner" ng-show="functionalMenuDetails.isSaving"></span> + <span ng-if="ngDialogData.source=='edit' && functionalMenuDetails.isLeafMenuItem()"> + <button class="save-button" id="add-menu-button-save" + ng-show="!functionalMenuDetails.menuItem.menu.url || + !(functionalMenuDetails.selectedApp.index>0) || + functionalMenuDetails.displayRoles" + ng-disabled="!functionalMenuForm.text.$valid" + ng-click="functionalMenuDetails.saveChanges()">Save</button> + <button class="save-button" id="add-menu-button-continue" + ng-show="!!functionalMenuDetails.menuItem.menu.url && + functionalMenuDetails.selectedApp.index>0 && + functionalMenuDetails.menutitle && + !functionalMenuDetails.displayRoles" + ng-disabled="!functionalMenuForm.url.$valid" ng-click="functionalMenuDetails.continue()">Continue</button> + </span> + <span ng-if="ngDialogData.source=='add' || (ngDialogData.source=='edit' && !functionalMenuDetails.isLeafMenuItem())"> + <button id="button-save-add" + class="save-button" ng-show="!functionalMenuDetails.menuItem.menu.url || !(functionalMenuDetails.selectedApp.index>0) + || functionalMenuDetails.selectedRole.length>0 || !functionalMenuDetails.menutitle" ng-disabled="!functionalMenuForm.text.$valid || !functionalMenuDetails.menutitle" + ng-click="functionalMenuDetails.saveChanges()">Save</button> + <button id="button-save-continue" class="save-button" + ng-show="!!functionalMenuDetails.menuItem.menu.url && functionalMenuDetails.selectedApp.index>0 + && functionalMenuDetails.menutitle + && !functionalMenuDetails.selectedRole.length>0" ng-disabled="!functionalMenuForm.url.$valid" + ng-click="functionalMenuDetails.continue()">Continue</button> + </span> + <button id="button-cancel-close-dialog" class="cancel-button" ng-click="closeThisDialog()">Cancel</button> + </div> + <div ng-if="ngDialogData.source=='view'"> + <div id="div-close-dialog" class="cancel-button" ng-click="closeThisDialog()">Close</div> + </div> + </div> +</div> diff --git a/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/modal-details.modal.less b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/modal-details.modal.less new file mode 100644 index 00000000..c322f453 --- /dev/null +++ b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/modal-details.modal.less @@ -0,0 +1,103 @@ +/*- + * ================================================================================ + * eCOMP Portal + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property + * ================================================================================ + * 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. + * ================================================================================ + */ + .functionalMenu-details-modal { + height: 430px; + + .title { + .n18r; + border-bottom: @a 3px solid; + + } + + .btn-medium{ + width:216px; + } + .dropdown-menu-medium{ + width:236px; + max-height: 200px; + overflow-y: auto; + } + + .functionalMenu-properties-main { + padding: 16px; + height: 306px; + overflow-y: visible; + + .item{ + position: relative; + margin-bottom: 18px; + + .input-field{ + .custom-input-field; + width: 100%; + &.url{ + width: 78%; + display: inline-block; + } + } + + .select-field { + .custom-select-field; + } + + .item-label{ + .o14r; + } + + .right-item{ + position: relative; + display: inline-block; + width: 48%; + float: right; + } + .left-item{ + display: inline-block; + width: 48%; + } + + .url-validation-button{ + .btn-blue; + width: 20%; + display: inline-block; + float: right; + } + + .error-container{ + position: absolute; + width: 220px; + display: block; + height: 12px; + line-height: 12px; + + .err-message{ + color: red; + font-size: 9px; + } + .valid-message{ + color: green; + font-size: 9px; + } + } + + } + + } + +} diff --git a/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.controller.js b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.controller.js new file mode 100644 index 00000000..d17c4ab8 --- /dev/null +++ b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.controller.js @@ -0,0 +1,331 @@ +/*- + * ================================================================================ + * eCOMP Portal + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property + * ================================================================================ + * 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'; +(function () { + class FunctionalMenuCtrl { + constructor($log, functionalMenuService, $scope,ngDialog, confirmBoxService) { + $log.info('FunctionalMenuCtrl init'); + + $scope.invokeDialog = () => { + alert("click dialog"); + }; + + this.regenerateFunctionalMenuAncestors = () => { + functionalMenuService.regenerateFunctionalMenuAncestors().then(res => { + $log.debug("FunctionalMenuCtrl:regenerateFunctionalMenuAncestors::returned from regenerateFunctionalMenuAncestors API call"); + confirmBoxService.showInformation('You have successfully regenerated the menu.').then(isConfirmed => { + }); + })['catch'](function (err) { + $log.error("FunctionalMenuCtrl:regenerateFunctionalMenuAncestors:: error: " + err); + confirmBoxService.showInformation('There was an error while regenerating the menu.').then(isConfirmed => { + }); + }); + }; + + let getFunctionalMenu = () => { + this.isLoadingTable = true; + functionalMenuService.getManagedFunctionalMenu().then(res => { + + let actualData=[]; + + for(let i = 0; i < res.length; i++){ + res[i].children=[]; + res[i].label=res[i].text; + res[i].id=res[i].text; + + } + + for(let i = 0; i < res.length; i++){ + + let parentId=res[i].menuId; + for(let j = 0; j < res.length; j++){ + let childId=res[j].parentMenuId; + if(parentId==childId){ + res[i].children.push(res[j]); + + } + } + } + + res.sort(function(a, b) { + return a.column-b.column; + }) + + for(let i = 0; i < res.length; i++){ + res[i].children.sort(function(a, b){ + return a.column-b.column; + }) + } + + for(let i = 0; i < res.length; i++){ + let parentId=res[i].parentMenuId; + if(parentId==null){ + actualData.push(res[i]); + } + } + + $scope.treedata = actualData; + + }).catch(err => { + $log.error('FunctionalMenuCtrl:getFunctionalMenu:: error ',err); + }).finally(()=> { + this.isLoadingTable = false; + }); + + }; + + + let init = () => { + this.isLoadingTable = false; + this.functionalMenu = []; + getFunctionalMenu(); + this.searchString = ''; + }; + + this.filterByDropdownValue = item => { + if(this.filterByApp.value === ''){ + return true; + } + return item.appName === this.filterByApp.value; + }; + + let getDialogTitle = (source) => { + switch (source) { + case 'edit': + return "Functional Menu - Edit"; + case 'view': + return "Functional Menu - View"; + case 'add': + return "Functional Menu - Add"; + default: + return "Functional Menu"; + } + } + + $scope.reloadTreeStructure = (selectedItem,source) => { + getFunctionalMenu(); + }; + $scope.openMenuDetailsModal = (selectedItem,source) => { + let data = null; + let selectedMenuDetails = null; + console.log('selectedItem: ', selectedItem); + + functionalMenuService.getMenuDetails(selectedItem.menuId) + .then(function( resp ){ + selectedMenuDetails = resp; + $log.info('FunctionalMenuCtrl::openMenuDetailsModal: getMenuDetails: ', resp ); + + if(selectedItem){ + data = { + menuItem: {menu: _.clone(selectedItem),menuDetails:_.clone(selectedMenuDetails)}, + source: source, + title: getDialogTitle(source) + } + } + ngDialog.open({ + templateUrl: 'app/views/functionalMenu/functionalMenu-dialog/menu-details.modal.html', + controller: 'MenuDetailsModalCtrl', + controllerAs: 'functionalMenuDetails', + data: data + }).closePromise.then(needUpdate => { + if(needUpdate.value === true){ + $log.debug('FunctionalMenuCtrl::openMenuDetailsModal: updating table data...'); + if(source=="edit") + init(); + } + }); + }); + }; + + + $scope.createNewMenuItem = (selectedItem,source) => { + + if(selectedItem != null && selectedItem.getLevel() >= 4){ + confirmBoxService.showInformation('You are not allowed to have a menu item at a level greater than 4.').then(isConfirmed => { + + }); + return ; + } + + let data = null; + let selectedMenuDetails = null; + functionalMenuService.getMenuDetails(selectedItem.menuId) + .then(function( resp ){ + selectedMenuDetails = resp; + + if((selectedItem.children==null || !selectedItem.children.length>0) && + (!!selectedMenuDetails.url || !!selectedMenuDetails.appid || !!selectedMenuDetails.roles)){ + confirmBoxService.showInformation('Warning: the child menu item "' + selectedItem.name + '" is already configured with an application. You can create a new mid-level menu item, and move this item under it.').then(isConfirmed => { + return; + }); + }else{ + if(selectedItem){ + data = { + menuItem: {menu: _.clone(selectedItem)}, + source:source, + title: getDialogTitle(source) + } + } + + ngDialog.open({ + templateUrl: 'app/views/functionalMenu/functionalMenu-dialog/menu-details.modal.html', + controller: 'MenuDetailsModalCtrl', + controllerAs: 'functionalMenuDetails', + data: data + }).closePromise.then(needUpdate => { + if(needUpdate.value === true){ + $log.debug('FunctionalMenuCtrl::getMenuDetails: updating table data...'); + init(); + } + }); + } + }); + }; + + $scope.deleteMenuItem = (selectedItem,source) => { + $log.info('FunctionalMenuCtrl:deleteMenuItem:: delete selectedItem: ', selectedItem); + + if(selectedItem.children!=null && selectedItem.children.length>0){ + confirmBoxService.showInformation('You are not allowed to delete a menu item that has children. You can only delete leaf menu items.').then(isConfirmed => { + + }); + }else{ + confirmBoxService.deleteItem(selectedItem.name).then(isConfirmed => { + if(isConfirmed){ + $log.info('FunctionalMenuCtrl:deleteMenuItem:: Deleting Menu Item :: name: '+selectedItem.name+'; menuId: '+selectedItem.menuId); + $log.info('FunctionalMenuCtrl:deleteMenuItem:: selectedItem: ', selectedItem); + + functionalMenuService.deleteMenuItem(selectedItem.menuId).then(() => { + $log.info('FunctionalMenuCtrl:deleteMenuItem:: Removed Menu Item :: '+selectedItem.name); + init(); + }).catch(err => { + $log.error(err); + }); + } + }).catch(err => { + $log.error(err); + }); + } + }; + + init(); + } + } + FunctionalMenuCtrl.$inject = ['$log', 'functionalMenuService','$scope', 'ngDialog', 'confirmBoxService']; + angular.module('ecompApp').controller('FunctionalMenuCtrl', FunctionalMenuCtrl); + + angular.module('ecompApp').directive('jqTree', ['functionalMenuService','$log','confirmBoxService',function(functionalMenuService,$log,confirmBoxService){ + return { + templateUrl: 'jqtree-tmpl.html', + link: function(scope, el, attrs){ + + var $jqTree = el.find('#jqTree').tree({ + data: scope.treedata, + autoOpen: false, + dragAndDrop: true, + onCreateLi: function(node, $li) { + $li.attr('id', node.id.replace(/\s+/g,"_")); + } + }); + + el.find('#jqTree').bind('tree.move', function(event){ + event.preventDefault(); + console.log('moved_node', event.move_info.moved_node); + console.log('target_node', event.move_info.target_node); + console.log('position', event.move_info.position); + console.log('previous_parent', event.move_info.previous_parent); + + + + if(event.move_info.target_node != null && + ((event.move_info.position == 'after' && event.move_info.target_node.getLevel() > 4) || + (event.move_info.position == 'inside' && event.move_info.target_node.getLevel() > 3))){ + confirmBoxService.showInformation('You are not allowed to have a menu item at a level greater than 4.').then(isConfirmed => { + + }); + return ; + } + + var confMsg = 'Are you sure you want to move "'+event.move_info.moved_node.name+'" ?'; + if ((event.move_info.position == "inside") && (event.move_info.target_node.url != "")) { + confMsg = 'Warning: You are moving "'+event.move_info.moved_node.name+'" under "'+event.move_info.target_node.name+'", which has application information associated with it. This will cause all the application information from "'+event.move_info.target_node.name+'" to be deleted.'; + } + confirmBoxService.moveMenuItem(confMsg).then(isConfirmed => { + if(isConfirmed){ + var new_column = event.move_info.target_node.column; + var old_column = event.move_info.moved_node.column; + if ((event.move_info.moved_node.parentMenuId != + event.move_info.target_node.parentMenuId) || + (new_column < old_column) + ) { + new_column += 1; + } + var activeMenuItem = { + menuId:event.move_info.moved_node.menuId, + column:new_column, + text:"", + parentMenuId:event.move_info.target_node.parentMenuId, + url:"", + appid: null, + roles:null + }; + + if (event.move_info.position == "inside") { + console.log("special case: target_node is parent"); + activeMenuItem.column = 1; + activeMenuItem.parentMenuId = event.move_info.target_node.menuId; + } + + functionalMenuService.saveEditedMenuItem(activeMenuItem) + .then(() => { + $log.debug(' Menu Item moved'); + scope.reloadTreeStructure(); + }).catch(err => { + $log.error(err); + }).finally(()=>{ + }); + } + }).catch(err => { + $log.error(err); + }); + }); + + + $jqTree.jqTreeContextMenu(el.find('ul.dropdown-menu'), { + "view": function (node) {scope.openMenuDetailsModal(node,'view'); }, + "edit": function (node) {scope.openMenuDetailsModal(node,'edit'); }, + "delete": function (node) { scope.deleteMenuItem(node,'delete') }, + "add": function (node) { scope.createNewMenuItem(node,'add') } + }); + + scope.$watch('treedata', function(oldValue, newValue){ + if(oldValue !== newValue){ + console.log('FunctionalMenuCtrl:: Tree value has changed in some way'); + $jqTree.tree('loadData', scope.treedata); + $jqTree.tree('reload', function() { + console.log('FunctionalMenuCtrl:: Tree is reloaded'); + }); + } + }) + } + } + }]); + +})(); diff --git a/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.less b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.less new file mode 100644 index 00000000..24a91287 --- /dev/null +++ b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.less @@ -0,0 +1,70 @@ +/*- + * ================================================================================ + * eCOMP Portal + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property + * ================================================================================ + * 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. + * ================================================================================ + */ + .functional-admin-page-main{ + .bg_w; + position: @page-main-position; + top: @page-main-top; + left: @page-main-left; + right: @page-main-right; + bottom: @page-main-bottom; + padding-top: @padding-top; + overflow-y: @page-main-overflow-y; + padding-left: @padding-left-side; + .u16r; + + .functional-admin-container { + .content_justify; + position: relative; + padding: 0 0 32px; + width: 1170px; + + .functional-admin-home-title { + .a24r; + padding-bottom: 20px; + .content_justify; + } + .tree{ + } + .functional-admin-button-container { + padding-top: 10px; + .btn-blue{ + height: 35px; + width: 140px; + } + } + } + .error-text { + width: 1170px; + margin: auto; + padding: 20px; + left: 20px; + font-weight: bold; + font-size: 16px; + text-align: left; + color: @err; + background-color: @u; + + .error-help { + color: @o; + font-weight: normal; + } + } + +}
\ No newline at end of file diff --git a/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.tpl.html b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.tpl.html new file mode 100644 index 00000000..a04cfe4c --- /dev/null +++ b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.tpl.html @@ -0,0 +1,48 @@ +<!-- + ================================================================================ + eCOMP Portal + ================================================================================ + Copyright (C) 2017 AT&T Intellectual Property + ================================================================================ + 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. + ================================================================================ + --> +<div class="w-ecomp-main"> + <div class="w-ecomp-main-container"> + <div class="functional-admin-page-main" id="contentId"> + <div class="functional-admin-container"> + <div id="functional-admin-home-title" class="functional-admin-home-title">Edit Functional Menu</div> + <div id="tree1"> + <div id="Service_Creation"></div> + </div> + <div id="jq-tree-div" jq-tree class="tree"></div> + <script type="text/ng-template" id="jqtree-tmpl.html"> + <div id="jqTree"></div> + <ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"> + <li id="functional-menu-view-li"><a id="functional-menu-view-href" ng-href="#view"><i class="ion-eye"></i> View</a></li> + <li class="divider"></li> + <li id="functional-menu-add-li"><a id="functional-menu-add-href" ng-href="#add"><i class="ion-plus-round"></i> Add</a></li> + <li class="divider"></li> + <li id="functional-menu-edit-li"><a id="functional-menu-edit-href" ng-href="#edit"><i class="ion-edit"></i> Edit</a></li> + <li class="divider"></li> + <li id="functional-menu-delete-li"><a id="functional-menu-delete-href" ng-href="#delete"><i class="ion-trash-b"></i> Delete</a></li> + </ul> + </script> + <div class="functional-admin-button-container"> + <button class="btn-blue" ng-click="functionalMenu.regenerateFunctionalMenuAncestors()">Regenerate Menu</button> + <span class="n16r">Click when you are done with your changes</span> + </div> + </div> + </div> + </div> +</div> diff --git a/ecomp-portal-FE/client/app/views/functionalMenu/jqTreeContextMenu.js b/ecomp-portal-FE/client/app/views/functionalMenu/jqTreeContextMenu.js new file mode 100644 index 00000000..21e8454d --- /dev/null +++ b/ecomp-portal-FE/client/app/views/functionalMenu/jqTreeContextMenu.js @@ -0,0 +1,192 @@ +/*- + * ================================================================================ + * eCOMP Portal + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ================================================================================ + */ +(function ($) { + if (!$.fn.tree) { + throw "Error jqTree is not loaded."; + } + + $.fn.jqTreeContextMenu = function (menuElement, callbacks) { + + var self = this; + var $el = this; + + var $menuEl = menuElement; + + var nodeToDisabledMenuItems = {}; + + $menuEl.hide(); + + $el.bind("contextmenu", function (e) { + e.preventDefault(); + return false; + }); + + $el.bind('tree.contextmenu', function (event) { + var x = event.click_event.pageX; + var y = event.click_event.pageY; + var yPadding = 5; + var xPadding = 5; + var menuHeight = $menuEl.height(); + var menuWidth = $menuEl.width(); + var windowHeight = $(window).height(); + var windowWidth = $(window).width(); + + if (menuHeight + y + yPadding > windowHeight) { + y = y - menuHeight; + } + if (menuWidth + x + xPadding > windowWidth) { + x = x - menuWidth; + } + + if (Object.keys(nodeToDisabledMenuItems).length > 0) { + if (event.node.name in nodeToDisabledMenuItems) { + var nodeName = event.node.name; + var items = nodeToDisabledMenuItems[nodeName]; + if (items.length === 0) { + $menuEl.find('li').addClass('disabled'); + $menuEl.find('li > a').unbind('click'); + } else { + $menuEl.find('li > a').each(function () { + $(this).closest('li').removeClass('disabled'); + var hrefValue = $(this).attr('href'); + var value = hrefValue.slice(hrefValue.indexOf("#") + 1, hrefValue.length) + if ($.inArray(value, items) > -1) { + $(this).closest('li').addClass('disabled'); + $(this).unbind('click'); + } + }); + } + } else { + $menuEl.find('li.disabled').removeClass('disabled'); + } + } + + $menuEl.show(); + + $menuEl.offset({ left: x, top: y }); + + var dismissContextMenu = function () { + $(document).unbind('click.jqtreecontextmenu'); + $el.unbind('tree.click.jqtreecontextmenu'); + $menuEl.hide(); + } + + $(document).bind('click.jqtreecontextmenu', function () { + dismissContextMenu(); + }); + + $el.bind('tree.click.jqtreecontextmenu', function (e) { + dismissContextMenu(); + }); + + var selectedNode = $el.tree('getSelectedNode'); + if (selectedNode !== event.node) { + $el.tree('selectNode', event.node); + } + + var menuItems = $menuEl.find('li:not(.disabled) a'); + if (menuItems.length !== 0) { + menuItems.unbind('click'); + menuItems.click(function (e) { + e.stopImmediatePropagation(); + dismissContextMenu(); + var hrefAnchor = e.currentTarget.attributes.href.nodeValue; + var funcKey = hrefAnchor.slice(hrefAnchor.indexOf("#") + 1, hrefAnchor.length) + var callbackFn = callbacks[funcKey]; + if (callbackFn) { + callbackFn(event.node); + } + return false; + }); + } + }); + + this.disable = function () { + if (arguments.length === 0) { + $menuEl.find('li:not(.disabled)').addClass('disabled'); + $menuEl.find('li a').unbind('click'); + nodeToDisabledMenuItems = {}; + } else if (arguments.length === 1) { + var items = arguments[0]; + if (typeof items !== 'object') { + return; + } + $menuEl.find('li > a').each(function () { + var hrefValue = $(this).attr('href'); + var value = hrefValue.slice(hrefValue.indexOf("#") + 1, hrefValue.length) + if ($.inArray(value, items) > -1) { + $(this).closest('li').addClass('disabled'); + $(this).unbind('click'); + } + }); + nodeToDisabledMenuItems = {}; + } else if (arguments.length === 2) { + var nodeName = arguments[0]; + var items = arguments[1]; + nodeToDisabledMenuItems[nodeName] = items; + } + }; + + this.enable = function () { + if (arguments.length === 0) { + $menuEl.find('li.disabled').removeClass('disabled'); + nodeToDisabledMenuItems = {}; + } else if (arguments.length === 1) { + var items = arguments[0]; + if (typeof items !== 'object') { + return; + } + + $menuEl.find('li > a').each(function () { + var hrefValue = $(this).attr('href'); + var value = hrefValue.slice(hrefValue.indexOf("#") + 1, hrefValue.length) + if ($.inArray(value, items) > -1) { + $(this).closest('li').removeClass('disabled'); + } + }); + + nodeToDisabledMenuItems = {}; + } else if (arguments.length === 2) { + var nodeName = arguments[0]; + var items = arguments[1]; + if (items.length === 0) { + delete nodeToDisabledMenuItems[nodeName]; + } else { + var disabledItems = nodeToDisabledMenuItems[nodeName]; + for (var i = 0; i < items.length; i++) { + var idx = disabledItems.indexOf(items[i]); + if (idx > -1) { + disabledItems.splice(idx, 1); + } + } + if (disabledItems.length === 0) { + delete nodeToDisabledMenuItems[nodeName]; + } else { + nodeToDisabledMenuItems[nodeName] = disabledItems; + } + } + if (Object.keys(nodeToDisabledMenuItems).length === 0) { + $menuEl.find('li.disabled').removeClass('disabled'); + } + } + }; + return this; + }; +} (jQuery)); |