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 @@ ...@@ -25,9 +25,33 @@
* provides access to the groups data to Django templates, * provides access to the groups data to Django templates,
* used for handling the removal of experiments from the report * 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; 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.expNamesToRemove = [];
vm.toggleExpName = (expName) => { vm.toggleExpName = (expName) => {
let idx = vm.expNamesToRemove.indexOf(expName); let idx = vm.expNamesToRemove.indexOf(expName);
......
...@@ -61,6 +61,16 @@ angular.module('reportApp') ...@@ -61,6 +61,16 @@ angular.module('reportApp')
scope.deleteExpFromReport = (expName) => { scope.deleteExpFromReport = (expName) => {
ExperimentsService.deleteExperiment(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: ` template: `
<div id='{{ domId }}' class='panel panel-default'> <div id='{{ domId }}' class='panel panel-default'>
...@@ -85,6 +95,7 @@ angular.module('reportApp') ...@@ -85,6 +95,7 @@ angular.module('reportApp')
<table ng-if='expNames.length > 0' class="table table-striped table-hover"> <table ng-if='expNames.length > 0' class="table table-striped table-hover">
<thead> <thead>
<tr> <tr>
<th ng-if='!isViewmode()'></th>
<th ng-if='!isViewmode()'></th> <th ng-if='!isViewmode()'></th>
<th ng-if='isViewmode() && groups.length == 1'>Alias</th> <th ng-if='isViewmode() && groups.length == 1'>Alias</th>
<th>Experiment</th> <th>Experiment</th>
...@@ -107,6 +118,14 @@ angular.module('reportApp') ...@@ -107,6 +118,14 @@ angular.module('reportApp')
</span> </span>
</div> </div>
</td> </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'> <td ng-if='isViewmode() && groups.length == 1'>
<span ng-if='groups[0].experiments.includes(expName)'> <span ng-if='groups[0].experiments.includes(expName)'>
{{ groups[0].aliases[expName] }} {{ groups[0].aliases[expName] }}
......
...@@ -26,25 +26,36 @@ ...@@ -26,25 +26,36 @@
* Displays a modal for locking the current report. * Displays a modal for locking the current report.
*/ */
angular.module('reportApp') angular.module('reportApp')
.directive("reportLock", ['ReportService', 'ErrorService', function(ReportService, ErrorService){ .directive("reportLock", ['ReportService', 'ErrorService', 'GroupsService', 'ExperimentsService', function(ReportService, ErrorService, GroupsService, ExperimentsService){
return { return {
scope: { scope: {
saveReport: '=saveReport',
}, },
restrict: 'E', restrict: 'E',
link: function(scope, el){ 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 // sends the request to lock the report
scope.lockReport = () => { scope.lockReport = () => {
return ReportService.lockReport() return scope.saveReport()
.then(() => { .then(() => ReportService.lockReport())
window.location.reload(); .then(() => {window.location.reload();})
})
.catch(e => { .catch(e => {
ErrorService.logError(e, `Could not lock the report.`); ErrorService.logError(e, `Could not lock the report.`);
}); });
} }
}, },
template: ` 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> <b-title>
Lock Report Lock Report
</b-title> </b-title>
...@@ -54,6 +65,16 @@ angular.module('reportApp') ...@@ -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> <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> </b-content>
</bootstrap-modal> </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') ...@@ -29,31 +29,11 @@ angular.module('reportApp')
.directive("reportSave", ['GroupsService', 'ReportService', 'reportFactory', 'ErrorService', 'ExperimentsService', function(GroupsService, ReportService, reportFactory, ErrorService, ExperimentsService){ .directive("reportSave", ['GroupsService', 'ReportService', 'reportFactory', 'ErrorService', 'ExperimentsService', function(GroupsService, ReportService, reportFactory, ErrorService, ExperimentsService){
return { return {
restrict: 'A', restrict: 'A',
link: function(scope, el){ scope: {
saveReport: '=saveReport',
const saveReport = () => { },
// save the serialized group data... link: function(scope, el, attrs){
// the rest of the state is reconstructed from it and the URL el.bind('click', scope.saveReport);
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);
}, },
}; };
}]); }]);
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
{% load report_tags %} {% load report_tags %}
{% with object.get_status_display as status %} {% 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 %} {% if display_count %}
<!-- Experiment count, works for all --> <!-- Experiment count, works for all -->
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
{% if display_count %} {% 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> <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 %} {% 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'> <span class="btn btn-default" data-toggle='modal' data-target='#lockReportModal'>
<a class="btn-report" data-toggle="tooltip" data-placement="bottom" title="Lock"> <a class="btn-report" data-toggle="tooltip" data-placement="bottom" title="Lock">
<i class="fa fa-lock fa-lg"></i> <i class="fa fa-lock fa-lg"></i>
...@@ -65,7 +65,7 @@ ...@@ -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> <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' %} {% if not display_count and status == 'Editable' %}
<report-lock></report-lock> <report-lock save-report='vm.saveReport'></report-lock>
{% endif %} {% endif %}
{% if not display_count and status == 'Locked' %} {% 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