// $Id: controller.js 32761 2015-11-02 11:50:21Z schaap $ var gridControllerMod = angular.module('GridControllerMod', ['ui.grid', 'ui.grid.edit', 'ui.grid.selection', 'ui.grid.cellNav', 'ui.grid.resizeColumns', 'ui.grid.autoResize']); gridControllerMod.controller('GridController', ['$scope', 'dataService', 'uiGridConstants', function($scope, dataService, uiGridConstants) { $scope.dataService = dataService; $scope.columns = [ { field: 'name', enableCellEdit: false, width: '15%' }, { field: 'project_name', displayName:'Project', enableCellEdit: false, cellTemplate:'<a target="_blank" href="https://lofar.astron.nl/mom3/user/project/setUpMom2ObjectDetails.do?view=generalinfo&mom2ObjectId={{row.entity.project_mom2object_id}}">{{row.entity[col.field]}}</a>', width: '12%', filter: { type: uiGridConstants.filter.SELECT, selectOptions: [] } }, { field: 'starttime', displayName: 'Start', width: '11%', type: 'date', enableCellEdit: false, enableCellEditOnFocus: false, cellTemplate:'<div style=\'text-align:left\'>{{row.entity[col.field] | date:\'yyyy-MM-dd HH:mm:ss\'}}</div>', sort: { direction: uiGridConstants.ASC } }, { field: 'endtime', displayName: 'End', width: '11%', type: 'date', enableCellEdit: false, enableCellEditOnFocus: false, cellTemplate:'<div style=\'text-align:left\'>{{row.entity[col.field] | date:\'yyyy-MM-dd HH:mm:ss\'}}</div>' }, { field: 'duration', displayName: 'Duration', width: '6%', enableFiltering: false, enableCellEdit: false, enableCellEditOnFocus: false, cellTemplate:'<div style=\'text-align:left\'>{{row.entity[col.field] | secondsToHHmmss}}</div>' }, { field: 'status', enableCellEdit: true, width: '6%', filter: { condition: uiGridConstants.filter.EXACT, type: uiGridConstants.filter.SELECT, selectOptions: [] }, editableCellTemplate: 'ui-grid/dropdownEditor', editDropdownOptionsArray: [], cellClass: function(grid, row, col, rowRenderIndex, colRenderIndex) { var value = grid.getCellValue(row,col); return "grid-status-" + value; } }, { field: 'type', enableCellEdit: false, width: '6%', filter: { condition: uiGridConstants.filter.EXACT, type: uiGridConstants.filter.SELECT, selectOptions: [] } }, { field: 'mom_object_group_id', displayName: 'Group', enableCellEdit: false, cellTemplate:'<a target="_blank" href="https://lofar.astron.nl/mom3/user/project/setUpMom2ObjectDetails.do?view=generalinfo&mom2ObjectId={{row.entity.mom_object_group_mom2object_id}}">{{row.entity.mom_object_group_name}} {{row.entity.mom_object_group_id}}</a>', width: '13%', filter: { condition: uiGridConstants.filter.EXACT, type: uiGridConstants.filter.SELECT, selectOptions: [] } }, { field: 'mom_id', displayName: 'MoM ID', enableCellEdit: false, cellTemplate:'<a target="_blank" href="https://lofar.astron.nl/mom3/user/project/setUpMom2ObjectDetails.do?view=generalinfo&mom2ObjectId={{row.entity.mom2object_id}}">{{row.entity[col.field]}}</a>', width: '6%' }, { field: 'otdb_id', displayName: 'SAS ID', enableCellEdit: false, width: '6%' }, { field: 'id', displayName: 'RADB ID', enableCellEdit: false, cellTemplate:'<a target="_blank" href="tasks/{{row.entity.id}}.html">{{row.entity[col.field]}}</a>', width: '6%' }]; $scope.gridOptions = { enableGridMenu: false, enableSorting: true, enableFiltering: true, enableCellEdit: false, enableColumnResize: true, enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER, enableRowSelection: true, enableRowHeaderSelection: true, enableFullRowSelection: false, modifierKeysToMultiSelect: true, multiSelect:true, enableSelectionBatchEvent:false, gridMenuShowHideColumns: false, columnDefs: $scope.columns, data: [], // rowTemplate: "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.uid\" ui-grid-one-bind-id-grid=\"rowRenderIndex + '-' + col.uid + '-cell'\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" role=\"{{col.isRowHeader ? 'rowheader' : 'gridcell'}}\" ui-grid-cell></div>" rowTemplate: "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.uid\" ui-grid-one-bind-id-grid=\"rowRenderIndex + '-' + col.uid + '-cell'\" class=\"ui-grid-cell\" ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" role=\"{{col.isRowHeader ? 'rowheader' : 'gridcell'}}\" ui-grid-cell context-menu>", onRegisterApi: function(gridApi){ $scope.gridApi = gridApi; $scope.gridApi.core.on.rowsRendered($scope, function() { //on.rowsRendered is called whenever the data/filtering of the grid changed //update the filteredTasks in the dataService from the resulting new grid rows $scope.$evalAsync(function() { var taskDict = $scope.dataService.taskDict; $scope.dataService.filteredTasks = []; var rows = $scope.gridApi.grid.rows; var numRows = rows.length; for(var i = 0; i < numRows; i++) { var row = rows[i]; if(row.visible) { var task_id = row.entity.id; var task = taskDict[task_id]; if(task) { $scope.dataService.filteredTasks.push(task); } row.setSelected($scope.dataService.selected_task_ids.indexOf(task_id) != -1); } } $scope.dataService.filteredTaskDict = $scope.dataService.toIdBasedDict($scope.dataService.filteredTasks); $scope.dataService.filteredTaskChangeCntr++; }); }); gridApi.edit.on.afterCellEdit($scope,function(rowEntity, colDef, newValue, oldValue){ var task = $scope.dataService.taskDict[rowEntity.id]; var newTask = { id: task.id, status: task.status }; $scope.dataService.putTask(newTask); }); gridApi.selection.on.rowSelectionChanged($scope,function(row){ if(row.entity.id) { if(row.isSelected) { $scope.dataService.addSelectedTaskId(row.entity.id); } else if(!row.isSelected) { $scope.dataService.removeSelectedTaskId(row.entity.id); } } }); } }; function fillColumFilterSelectOptions(options, columnDef) { var columnSelectOptions = []; if(options) { for(var i = 0; i < options.length; i++) { var option = options[i]; if(option.hasOwnProperty('value') && option.hasOwnProperty('label')) { columnSelectOptions.push({ value: option.value, label: option.label }) } else { columnSelectOptions.push({ value: option, label: option }) } } } columnDef.filter.selectOptions = columnSelectOptions; }; function populateList() { if('tasks' in $scope.dataService && $scope.dataService.tasks.length > 0) { var viewFrom = $scope.dataService.viewTimeSpan.from; var viewTo = $scope.dataService.viewTimeSpan.to; $scope.dataService.filteredTasks = []; var gridTasks = []; for(var task of $scope.dataService.tasks) { if(task.endtime >= viewFrom && task.starttime <= viewTo) { $scope.dataService.filteredTasks.push(task); var gridTask = { id: task.id, name: task.name, project_name: task.project_name, mom_id: task.mom_id, otdb_id: task.otdb_id, starttime: task.starttime, endtime: task.endtime, duration: task.duration, status: task.status, type: task.type, project_mom2object_id: task.project_mom2object_id, mom2object_id: task.mom2object_id, mom_object_group_id: task.mom_object_group_id, mom_object_group_name: task.mom_object_group_name, mom_object_group_mom2object_id: task.mom_object_group_mom2object_id }; gridTasks.push(gridTask); } } $scope.gridOptions.data = gridTasks; } else $scope.gridOptions.data = [] $scope.$evalAsync(fillProjectsColumFilterSelectOptions) $scope.$evalAsync(fillGroupsColumFilterSelectOptions); }; function jumpToSelectedTaskRows() { var rowIndices = dataService.selected_task_ids.map(function(t_id) { return $scope.gridOptions.data.findIndex(function(row) {return row.id == t_id; } ); }); rowIndices = rowIndices.filter(function(idx) {return idx > -1;}).sort(); for(var rowIndex of rowIndices) { $scope.gridApi.core.scrollTo($scope.gridOptions.data[rowIndex], null); } }; function onSelectedTaskIdsChanged() { var selected_task_ids = $scope.dataService.selected_task_ids; var rows = $scope.gridApi.grid.rows; for(var row of rows) { row.setSelected(selected_task_ids.indexOf(row.entity.id) != -1); } $scope.$evalAsync(jumpToSelectedTaskRows); }; $scope.$watch('dataService.taskChangeCntr', function() { $scope.$evalAsync(populateList); }); $scope.$watch('dataService.viewTimeSpan', function() { $scope.$evalAsync(populateList); $scope.$evalAsync(jumpToSelectedTaskRows); }, true); $scope.$watch('dataService.initialLoadComplete', function() { $scope.$evalAsync(function() { taskstatustypenames = $scope.dataService.taskstatustypes.map(function(x) { return x.name; }); fillColumFilterSelectOptions(taskstatustypenames, $scope.columns[5]); $scope.columns[6].editDropdownOptionsArray = $scope.dataService.taskstatustypes.map(function(x) { return {id:x.name, value:x.name}; }); tasktypenames = $scope.dataService.tasktypes.map(function(x) { return x.name; }); fillColumFilterSelectOptions(tasktypenames, $scope.columns[6]); fillProjectsColumFilterSelectOptions(); }); }); function fillProjectsColumFilterSelectOptions() { var projectNames = []; var momProjectsDict = $scope.dataService.momProjectsDict; var tasks = $scope.dataService.tasks; //get unique projectIds from tasks var task_project_ids = tasks.map(function(t) { return t.project_mom_id; }); task_project_ids = task_project_ids.filter(function(value, index, arr) { return arr.indexOf(value) == index;}) for(var project_id of task_project_ids) { if(momProjectsDict.hasOwnProperty(project_id)) { var projectName = momProjectsDict[project_id].name; if(!(projectName in projectNames)) { projectNames.push(projectName); } } } projectNames.sort(); fillColumFilterSelectOptions(projectNames, $scope.columns[1]); }; function fillGroupsColumFilterSelectOptions() { var tasks = $scope.dataService.tasks; //get unique groupNames from tasks var groupNamesAndIds = tasks.map(function(t) { return { name: t.mom_object_group_name, id: t.mom_object_group_id }; }); groupNamesAndIds = groupNamesAndIds.filter(function(value, index, arr) { return arr.indexOf(value) == index;}) groupNamesAndIds.sort(); var groupSelectOptions = groupNamesAndIds.map(function(obj) { return { value: obj.id, label: obj.name + ' ' + obj.id }; }); fillColumFilterSelectOptions(groupSelectOptions, $scope.columns[7]); }; $scope.$watch('dataService.selected_task_ids', onSelectedTaskIdsChanged, true);} ]); gridControllerMod.directive('contextMenu', ['$document', '$window', function($document, $window) { return { restrict: 'A', scope: { }, link: function($scope, $element, $attrs) { function handleContextMenuEvent(event) { //pragmatic 'hard-coded' way of getting the dataService and the rowEntity via scope tree. var dataService = $scope.$parent.$parent.$parent.$parent.$parent.$parent.$parent.$parent.dataService; var cleanupCtrl = $scope.$parent.$parent.$parent.$parent.$parent.$parent.$parent.$parent.$parent.cleanupCtrl; var rowEntity = $scope.$parent.$parent.$parent.row.entity; if(!dataService || !rowEntity) return true; var taskId = rowEntity.id; var task = dataService.taskDict[taskId]; if(!task) return true; if(!dataService.isTaskIdSelected(taskId)) { dataService.setSelectedTaskId(taskId); } var docElement = angular.element($document); //search for already existing contextmenu element while($document.find('#grid-context-menu').length) { //found, remove it, so we can create a fresh one $document.find('#grid-context-menu')[0].remove(); //unbind document close event handlers docElement.unbind('click', closeContextMenu); docElement.unbind('contextmenu', closeContextMenu); } //create contextmenu element //with list of menu items, //each with it's own action var contextmenuElement = angular.element('<div id="grid-context-menu"></div>'); var ulElement = angular.element('<ul class="dropdown-menu" role="menu" style="left:' + event.clientX + 'px; top:' + event.clientY + 'px; z-index: 100000; display:block;"></ul>'); contextmenuElement.append(ulElement); var liElement = angular.element('<li><a href="#">Select group</a></li>'); ulElement.append(liElement); liElement.on('click', function() { closeContextMenu(); dataService.selectTasksInSameGroup(task); }); if(task.type == 'observation' && dataService.config.inspection_plots_base_url) { var liElement = angular.element('<li><a href="#">Inspection Plots</a></li>'); ulElement.append(liElement); liElement.on('click', function() { closeContextMenu(); var tasks = dataService.selected_task_ids.map(function(t_id) { return dataService.taskDict[t_id]; }); for(var t of tasks) { if(t) { var url = dataService.config.inspection_plots_base_url + '/' + t.otdb_id; $window.open(url, '_blank'); } } }); } var liContent = dataService.selected_task_ids.length == 1 ? '<li><a href="#">Show disk usage</a></li>' : '<li><a href="#" style="color:#aaaaaa">Show disk usage</a></li>' var liElement = angular.element(liContent); ulElement.append(liElement); if(dataService.selected_task_ids.length == 1) { liElement.on('click', function() { closeContextMenu(); cleanupCtrl.showTaskDiskUsage(task); }); } var liElement = angular.element('<li><a href="#">Delete data</a></li>'); ulElement.append(liElement); liElement.on('click', function() { closeContextMenu(); cleanupCtrl.deleteSelectedTasksDataWithConfirmation(); }); var closeContextMenu = function(cme) { contextmenuElement.remove(); //unbind document close event handlers docElement.unbind('click', closeContextMenu); docElement.unbind('contextmenu', closeContextMenu); }; //click anywhere to remove the contextmenu docElement.bind('click', closeContextMenu); docElement.bind('contextmenu', closeContextMenu); //add contextmenu to body var body = $document.find('body'); body.append(contextmenuElement); //prevent bubbling event upwards return false; } $element.bind('contextmenu', handleContextMenuEvent); $scope.$on('$destroy', function() { $element.unbind('contextmenu', handleContextMenuEvent); }); } }; }]);