Commit b379a2d8 authored by Jaden's avatar Jaden

[reports][js] dont let reports be locked with unused exps

Adds a flag to the experiments table to indicate which experiments
need to be added to a group.
Also changes the Lock Button functionality:
- will save report before locking it
- if the report has experiments that aren't in a group,
  the report wont lock and will instead show a modal asking the
  user to either add all exps to a group or remove them.

Closes #529
parent f081e48c
Pipeline #31450 passed with stage
in 14 minutes and 40 seconds
......@@ -25,9 +25,33 @@
* provides access to the groups data to Django templates,
* used for handling the removal of experiments from the report
*/
angular.module('reportApp').controller('GroupsController', ['$http', 'UrlService', function ($http, UrlService){
angular.module('reportApp').controller('GroupsController',
['$scope', '$http', 'UrlService', 'GroupsService', 'ReportService', 'reportFactory', 'ErrorService', 'ExperimentsService',
function (scope, $http, UrlService, GroupsService, ReportService, reportFactory, ErrorService, ExperimentsService){
let vm = this;
vm.saveReport = () => {
// save the serialized group data...
// the rest of the state is reconstructed from it and the URL
let saveData = {
content: {
'groups': GroupsService.serializeGroups()
}
};
return reportFactory.removeExperiments(ExperimentsService.cachedDeletedExperiments)
.then(() => reportFactory.updateReport(ReportService.author, ReportService.name, saveData, ''))
.then(() => {
const lastEditedEl = document.querySelector('.lastEdited');
lastEditedEl.classList.remove('lastEditedAnimating');
void lastEditedEl.offsetWidth;
lastEditedEl.classList.add('lastEditedAnimating');
})
.catch(e => {
ErrorService.logError(e, `Could not save the report.`);
});
};
vm.expNamesToRemove = [];
vm.toggleExpName = (expName) => {
let idx = vm.expNamesToRemove.indexOf(expName);
......
......@@ -61,6 +61,16 @@ angular.module('reportApp')
scope.deleteExpFromReport = (expName) => {
ExperimentsService.deleteExperiment(expName);
};
const getUnusedExperiments = (expNames, groups) => {
const usedExps = Array.from(new Set([].concat.apply([], groups.map(g => g.experiments))));
const unusedExps = expNames.filter(n => !usedExps.includes(n));
scope.unusedExps = unusedExps;
};
scope.$watchCollection('expNames', (names) => {getUnusedExperiments(names, scope.groups);});
scope.$watch('groups', (gs) => {getUnusedExperiments(scope.expNames, gs);}, true);
getUnusedExperiments(scope.expNames, scope.groups);
},
template: `
<div id='{{ domId }}' class='panel panel-default'>
......@@ -85,6 +95,7 @@ angular.module('reportApp')
<table ng-if='expNames.length > 0' class="table table-striped table-hover">
<thead>
<tr>
<th ng-if='!isViewmode()'></th>
<th ng-if='!isViewmode()'></th>
<th ng-if='isViewmode() && groups.length == 1'>Alias</th>
<th>Experiment</th>
......@@ -107,6 +118,14 @@ angular.module('reportApp')
</span>
</div>
</td>
<td ng-if='!isViewmode()'>
<span
ng-if='unusedExps.includes(expName)'
style='cursor: help;'
title="Experiment needs to be added to a group">
<i class="fa fa-flag fa-lg text-warning"></i>
</span>
</td>
<td ng-if='isViewmode() && groups.length == 1'>
<span ng-if='groups[0].experiments.includes(expName)'>
{{ groups[0].aliases[expName] }}
......
......@@ -26,25 +26,36 @@
* Displays a modal for locking the current report.
*/
angular.module('reportApp')
.directive("reportLock", ['ReportService', 'ErrorService', function(ReportService, ErrorService){
.directive("reportLock", ['ReportService', 'ErrorService', 'GroupsService', 'ExperimentsService', function(ReportService, ErrorService, GroupsService, ExperimentsService){
return {
scope: {
saveReport: '=saveReport',
},
restrict: 'E',
link: function(scope, el){
scope.expNames = ExperimentsService.experimentNames;
scope.groups = GroupsService.groups;
const calcUnusedExperiments = () => {
const usedExps = Array.from(new Set([].concat.apply([], scope.groups.map(g => g.experiments))));
const unusedExps = scope.expNames.filter(n => !usedExps.includes(n));
scope.unusedExps = unusedExps.length !== 0;
};
scope.$watchCollection('expNames', (names) => {calcUnusedExperiments();});
scope.$watch('groups', () => {calcUnusedExperiments();}, true);
// sends the request to lock the report
scope.lockReport = () => {
return ReportService.lockReport()
.then(() => {
window.location.reload();
})
return scope.saveReport()
.then(() => ReportService.lockReport())
.then(() => {window.location.reload();})
.catch(e => {
ErrorService.logError(e, `Could not lock the report.`);
});
}
},
template: `
<bootstrap-modal dom-id='lockReportModal' button-submit-text='Lock' button-submit-func='lockReport'>
<div>
<bootstrap-modal dom-id='lockReportModal' button-submit-text='Lock' button-submit-func='lockReport' ng-if='!unusedExps'>
<b-title>
Lock Report
</b-title>
......@@ -54,6 +65,16 @@ angular.module('reportApp')
<p>In order to do lock your report, your experiments will be locked as well, if they are not already (they will not be able to be edited or deleted).</p>
</b-content>
</bootstrap-modal>
<bootstrap-modal dom-id='lockReportModal' ng-if='unusedExps'>
<b-title>
Lock Report
</b-title>
<b-content>
<p>There are experiments that haven't been added to a group.</p>
<p>Please make sure every experiment is in a group, or remove experiments from the report that aren't needed.</p>
</b-content>
</bootstrap-modal>
</div>
`
};
}]);
......@@ -29,31 +29,11 @@ angular.module('reportApp')
.directive("reportSave", ['GroupsService', 'ReportService', 'reportFactory', 'ErrorService', 'ExperimentsService', function(GroupsService, ReportService, reportFactory, ErrorService, ExperimentsService){
return {
restrict: 'A',
link: function(scope, el){
const saveReport = () => {
// save the serialized group data...
// the rest of the state is reconstructed from it and the URL
let saveData = {
content: {
'groups': GroupsService.serializeGroups()
}
};
return reportFactory.removeExperiments(ExperimentsService.cachedDeletedExperiments)
.then(() => reportFactory.updateReport(ReportService.author, ReportService.name, saveData, ''))
.then(() => {
const lastEditedEl = document.querySelector('.lastEdited');
lastEditedEl.classList.remove('lastEditedAnimating');
void lastEditedEl.offsetWidth;
lastEditedEl.classList.add('lastEditedAnimating');
})
.catch(e => {
ErrorService.logError(e, `Could not save the report.`);
});
};
el.bind('click', saveReport);
scope: {
saveReport: '=saveReport',
},
link: function(scope, el, attrs){
el.bind('click', scope.saveReport);
},
};
}]);
......@@ -22,7 +22,7 @@
{% load report_tags %}
{% with object.get_status_display as status %}
<div class="btn-group btn-group-sm action-buttons pull-right">
<div class="btn-group btn-group-sm action-buttons pull-right" ng-controller='GroupsController as vm'>
{% if display_count %}
<!-- Experiment count, works for all -->
......@@ -39,7 +39,7 @@
{% if display_count %}
<a class="btn btn-default btn-edit" href="{{ object.get_author_absolute_url }}" data-toggle="tooltip" data-placement="bottom" title="Edit"><i class="fa fa-edit fa-lg"></i></a>
{% else %}
<a id="save-button" class="btn btn-default btn-save" data-toggle="tooltip" data-placement="bottom" title="Save" report-save><i class="fa fa-floppy-o fa-lg"></i></a>
<a id="save-button" class="btn btn-default btn-save" data-toggle="tooltip" data-placement="bottom" title="Save" report-save save-report='vm.saveReport'><i class="fa fa-floppy-o fa-lg"></i></a>
<span class="btn btn-default" data-toggle='modal' data-target='#lockReportModal'>
<a class="btn-report" data-toggle="tooltip" data-placement="bottom" title="Lock">
<i class="fa fa-lock fa-lg"></i>
......@@ -65,7 +65,7 @@
<a class="btn btn-default btn-view" href="{{ object.get_absolute_url }}" data-toggle="tooltip" data-placement="bottom" title="Review"><i class="fa fa-arrow-circle-right fa-lg"></i></a>
{% if not display_count and status == 'Editable' %}
<report-lock></report-lock>
<report-lock save-report='vm.saveReport'></report-lock>
{% endif %}
{% if not display_count and status == 'Locked' %}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment