Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
gridcontroller.js 24.80 KiB
// $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: '12%'
    },
    { 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%',
        type: 'number',
        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_id}} {{row.entity.mom_object_group_name}}</a>',
        width: '12%',
        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%'
    },
    { field: 'cluster',
        displayName: 'cluster',
        enableCellEdit: false,
        width: '6%',
        filter: {
            condition: uiGridConstants.filter.EXACT,
            type: uiGridConstants.filter.SELECT,
            selectOptions: []
        },
        cellClass: function(grid, row, col, rowRenderIndex, colRenderIndex) {
            var value = grid.getCellValue(row,col);
            return "grid-cluster-" + value;
        }
    }];
    $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.core.getVisibleRows(grid);
                    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++;

                    if($scope.dataService.filteredTasks.length == 0) {
                        var otdb_col = $scope.gridApi.grid.columns.find(function(c) {return c.field == 'otdb_id'; });
                        if(otdb_col && otdb_col.filters.length && otdb_col.filters[0].hasOwnProperty('term')) {
                            var otdb_id = otdb_col.filters[0].term;
                            $scope.$parent.$parent.loadTaskByOTDBIdSelectAndJumpIntoView(otdb_id).then(function() {
                                otdb_col.filters[0].term = null;
                            });
                        } else {
                            var mom_col = $scope.gridApi.grid.columns.find(function(c) {return c.field == 'mom_id'; });

                            if(mom_col && mom_col.filters.length && mom_col.filters[0].hasOwnProperty('term')) {
                                var mom_id = mom_col.filters[0].term;
                                $scope.$parent.$parent.loadTaskByMoMIdSelectAndJumpIntoView(mom_id).then(function(task) {
                                    if(task) {
                                        mom_col.filters[0].term = null;
                                    } else {
                                        //getting the task by mom_id did not find a task
                                        //maybe the entered id was a mom group_id?
                                        //let's try to loadTasksByMoMGroupIdSelectAndJumpIntoView
                                        $scope.$parent.$parent.loadTasksByMoMGroupIdSelectAndJumpIntoView(mom_id).then(function(tasks) {
                                            mom_col.filters[0].term = null;
                                        });
                                    }
                                });
                            }
                        }
                    }
                });
            });

            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,
                        cluster: task.cluster
                    };
                    gridTasks.push(gridTask);
                }
            }

            $scope.gridOptions.data = gridTasks;
        } else
            $scope.gridOptions.data = []

        fillProjectsColumFilterSelectOptions()
        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);
        }

        //find out if we have selected all tasks in a single mom group
        var selected_tasks = $scope.dataService.selected_task_ids.map(function(t_id) { return $scope.dataService.taskDict[t_id]; }).filter(function(t) { return t != undefined;});

        if(selected_tasks && selected_tasks.length > 1) {
            var selected_task_group_ids = selected_tasks.map(function(t) { return t.mom_object_group_id; });
            selected_task_group_ids = selected_task_group_ids.unique();

            if(selected_task_group_ids.length == 1) {
                //we have selected tasks in a single mom group
                //find out if we have selected all tasks within this mom group
                var mom_object_group_id = selected_task_group_ids[0];
                var all_group_tasks = $scope.dataService.tasks.filter(function(t) { return t.mom_object_group_id == mom_object_group_id; });

                if(all_group_tasks.length == selected_tasks.length) {
                    //we have selected all tasks in a single mom group
                    //apply filter on group column to see only tasks within this group
                    var group_col = $scope.gridApi.grid.columns.find(function(c) {return c.field == 'mom_object_group_id'; });
                    if(group_col) {
                        var mom_object_group_name = all_group_tasks[0].mom_object_group_name;
                        var label = mom_object_group_id + ' ' + mom_object_group_name;

                        var groupSelectOptions = [ { value: mom_object_group_id, label: label} ];
                        fillColumFilterSelectOptions(groupSelectOptions, $scope.columns[7]);

                        group_col.filters[0].term = mom_object_group_id;
                    }
                }
            }
        }


        $scope.$evalAsync(jumpToSelectedTaskRows);
    };

    $scope.$watch('dataService.taskChangeCntr', function() { $scope.$evalAsync(populateList); });
    $scope.$watch('dataService.claimChangeCntr', function() { $scope.$evalAsync(populateList); });
    $scope.$watch('dataService.viewTimeSpan', function() {
        $scope.$evalAsync(populateList);
        $scope.$evalAsync(jumpToSelectedTaskRows);
    }, true);

    $scope.$watch('dataService.filteredTaskChangeCntr', function() {
        $scope.$evalAsync(function() {
            fillStatusColumFilterSelectOptions();
            fillTypeColumFilterSelectOptions();
            fillProjectsColumFilterSelectOptions();
            fillGroupsColumFilterSelectOptions();
        });
    });

    $scope.$watch('dataService.initialLoadComplete', function() {
        $scope.$evalAsync(function() {
            fillStatusColumFilterSelectOptions();
            fillTypeColumFilterSelectOptions();
            fillProjectsColumFilterSelectOptions();
            fillGroupsColumFilterSelectOptions();
            fillColumFilterSelectOptions(['CEP2', 'CEP4'], $scope.columns[11]);
        });
    });

    function fillProjectsColumFilterSelectOptions() {
        var projectNames = [];
        var momProjectsDict = $scope.dataService.momProjectsDict;
        var tasks = $scope.dataService.filteredTasks;

        var project_col = $scope.gridApi.grid.columns.find(function(c) {return c.field == 'project_name'; });
        if(project_col && project_col.filters.length && project_col.filters[0].term) {
            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.unique();

        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 fillStatusColumFilterSelectOptions() {
        var tasks = $scope.dataService.filteredTasks;

        var status_col = $scope.gridApi.grid.columns.find(function(c) {return c.field == 'status'; });
        if(status_col && status_col.filters.length && status_col.filters[0].term) {
            tasks = $scope.dataService.tasks;
        }

        //get unique statuses from tasks
        var task_statuses = tasks.map(function(t) { return t.status; });
        task_statuses = task_statuses.unique();

        task_statuses.sort();
        fillColumFilterSelectOptions(task_statuses, $scope.columns[5]);
    };

    function fillTypeColumFilterSelectOptions() {
        var tasks = $scope.dataService.filteredTasks;

        var type_col = $scope.gridApi.grid.columns.find(function(c) {return c.field == 'type'; });
        if(type_col && type_col.filters.length && type_col.filters[0].term) {
            tasks = $scope.dataService.tasks;
        }

        //get unique types from tasks
        var task_types = tasks.map(function(t) { return t.type; });
        task_types = task_types.unique();

        task_types.sort();
        fillColumFilterSelectOptions(task_types, $scope.columns[6]);
    };

    function fillGroupsColumFilterSelectOptions() {
        if($scope.columns[7].filter.term) {
            return;
        }

        var tasks = $scope.dataService.filteredTasks;

        //get unique groupNames from tasks
        var groupId2Name = {};
        var groupIds = [];

        for(var task of tasks) {
            if(task.mom_object_group_id) {
                if(!groupId2Name.hasOwnProperty(task.mom_object_group_id)) {
                    groupId2Name[task.mom_object_group_id] = task.mom_object_group_name;
                    groupIds.push(task.mom_object_group_id);
                }
            }
        }

        var groupSelectOptions = groupIds.map(function(gid) { return { value: gid, label: gid + ' ' + groupId2Name[gid]}; });
        groupSelectOptions.sort(function(a,b) { return a.value - b.value; });

        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 selected_tasks = dataService.selected_task_ids.map(function(t_id) { return dataService.taskDict[t_id]; });
            var selected_cep4_tasks = selected_tasks.filter(function(t) {
                var task_claims = dataService.resourceClaims.filter(function(rc) { return rc.task_id == t.id;});
                return task_claims.length > 0;
            });

//                             var liElement = angular.element('<li><a href="#">Copy Task</a></li>');
//                             ulElement.append(liElement);
//                             liElement.on('click', function() {
//                                 closeContextMenu();
//                                 //TODO: remove link to dataService in this generic plugin
//                                 dataService.copyTask(task);
//                             });

            var liElement = angular.element('<li><a href="#">Select group</a></li>');
            ulElement.append(liElement);
            liElement.on('click', function() {
                closeContextMenu();
                var dataCtrlScope = $scope.$parent.$parent.$parent.$parent.$parent.$parent.$parent.$parent.$parent.$parent;
                dataCtrlScope.loadTasksByMoMGroupIdSelectAndJumpIntoView(task.mom_object_group_id);
            });

            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();
                    for(var t of selected_tasks) {
                        if(t) {
                            var url = dataService.config.inspection_plots_base_url + '/' + t.otdb_id;
                            $window.open(url, '_blank');
                        }
                    }
                });
            }

            var liContent = selected_cep4_tasks.length == selected_tasks.length ? '<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(selected_cep4_tasks.length == selected_tasks.length) {
                liElement.on('click', function() {
                    closeContextMenu();
                    cleanupCtrl.showTaskDiskUsage(task);
                });
            }

            var completed_selected_cep4_tasks = selected_cep4_tasks.filter(function(t) { return t.status == 'finished' || t.status == 'aborted'; });

            var liContent = completed_selected_cep4_tasks.length == selected_tasks.length ? '<li><a href="#">Delete data</a></li>' : '<li><a href="#" style="color:#aaaaaa">Delete data</a></li>'
            var liElement = angular.element(liContent);
            ulElement.append(liElement);
            if(completed_selected_cep4_tasks.length == selected_tasks.length) {
                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);
        });
      }
    };
  }]);