diff --git a/beat/web/reports/static/reports/app/directives/bootstrapModal.js b/beat/web/reports/static/reports/app/directives/bootstrapModal.js
new file mode 100644
index 0000000000000000000000000000000000000000..6692f51a013e7a507f86b61578b176b3c6f8a15d
--- /dev/null
+++ b/beat/web/reports/static/reports/app/directives/bootstrapModal.js
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/
+ * Contact: beat.support@idiap.ch
+ *
+ * This file is part of the beat.web module of the BEAT platform.
+ *
+ * Commercial License Usage
+ * Licensees holding valid commercial BEAT licenses may use this file in
+ * accordance with the terms contained in a written agreement between you
+ * and Idiap. For further information contact tto@idiap.ch
+ *
+ * Alternatively, this file may be used under the terms of the GNU Affero
+ * Public License version 3 as published by the Free Software and appearing
+ * in the file LICENSE.AGPL included in the packaging of this file.
+ * The BEAT platform is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the GNU Affero Public License along
+ * with the BEAT platform. If not, see http://www.gnu.org/licenses/.
+ */
+
+/*
+ * bootstrapModal
+ * Desc:
+ * 	represents a modal from Bootstrap 3
+ */
+angular.module('reportApp')
+.directive("bootstrapModal", [function(){
+	return {
+		scope: {
+			domId: '@',
+			buttonCancelFunc: '&',
+			buttonSubmitFunc: '&',
+			buttonCancelText: '@',
+			buttonSubmitText: '@'
+		},
+		link: function(scope){
+			console.log(scope);
+		},
+		transclude: {
+			'title': '?bTitle',
+			'content': '?bContent',
+			'footer': '?bFooter'
+		},
+		template: `
+<div class="modal fade" id="{{ domId }}" tabindex="-1" role="dialog" aria-labelledby="reportModalLabel">
+	<div class="modal-dialog" role="document">
+		<div class="modal-content">
+			<div class="modal-header">
+				<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+				<h4 class="modal-title" id="reportModalLabel" ng-transclude='title'>Modal Title</h4>
+			</div>
+			<div class="modal-body" ng-transclude='content'>
+				Content
+			</div>
+			<div class="modal-footer" ng-transclude='footer'>
+				<button ng-click='buttonCancelFunc && buttonCancelFunc()()' type="button" class="btn btn-default" data-dismiss="modal">
+					Cancel
+				</button>
+				<button ng-if='buttonSubmitText' ng-click='buttonSubmitFunc && buttonSubmitFunc()()' type="button" class="btn btn-primary" data-dismiss="modal">
+					{{ buttonSubmitText }}
+				</button>
+			</div>
+		</div>
+	</div>
+</div>
+`
+	};
+}]);
diff --git a/beat/web/reports/static/reports/app/directives/lockReport.js b/beat/web/reports/static/reports/app/directives/lock.js
similarity index 53%
rename from beat/web/reports/static/reports/app/directives/lockReport.js
rename to beat/web/reports/static/reports/app/directives/lock.js
index 9d02f4eebda3681be7489ab6b94357ee9901d2dc..ad02cd8d8da14362bb1e18e6338f9ccadfe553f7 100644
--- a/beat/web/reports/static/reports/app/directives/lockReport.js
+++ b/beat/web/reports/static/reports/app/directives/lock.js
@@ -20,14 +20,32 @@
  * with the BEAT platform. If not, see http://www.gnu.org/licenses/.
  */
 
-//Directive for opening smart_selector list on "Add a report item" button click that displays options
-angular.module('reportApp').directive("lockreport", function($compile){
-	return function(scope, element, attrs){
-		//add new report item
-		element.bind("click", function(){
-			beat.ui.report.lock_report('report_lock', scope);
-		});
+/*
+ * reportLock
+ * Desc:
+ * 	Displays a modal for locking the current report.
+ */
+angular.module('reportApp')
+.directive("reportLock", ['ReportService', function(ReportService){
+	return {
+		scope: {
+		},
+		restrict: 'E',
+		link: function(scope, el){
+			// sends the request to lock the report
+			scope.lockReport = ReportService.lockReport;
+		},
+		template: `
+<bootstrap-modal dom-id='lockReportModal' button-submit-text='Lock' button-submit-func='lockReport'>
+	<b-title>
+		Lock Report
+	</b-title>
+	<b-content>
+        <p>Locking your report is the first step for publication.</p>
+        <p>Your report will not be editable anymore.</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>
+</bootstrap-modal>
+`
 	};
-});
-
-
+}]);
diff --git a/beat/web/reports/static/reports/app/directives/publish.js b/beat/web/reports/static/reports/app/directives/publish.js
new file mode 100644
index 0000000000000000000000000000000000000000..4d20ca09b15c785b26f0093e322eae2a68d8d9ae
--- /dev/null
+++ b/beat/web/reports/static/reports/app/directives/publish.js
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/
+ * Contact: beat.support@idiap.ch
+ *
+ * This file is part of the beat.web module of the BEAT platform.
+ *
+ * Commercial License Usage
+ * Licensees holding valid commercial BEAT licenses may use this file in
+ * accordance with the terms contained in a written agreement between you
+ * and Idiap. For further information contact tto@idiap.ch
+ *
+ * Alternatively, this file may be used under the terms of the GNU Affero
+ * Public License version 3 as published by the Free Software and appearing
+ * in the file LICENSE.AGPL included in the packaging of this file.
+ * The BEAT platform is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the GNU Affero Public License along
+ * with the BEAT platform. If not, see http://www.gnu.org/licenses/.
+ */
+
+/*
+ * reportPublish
+ * Desc:
+ * 	Displays a modal for publishing the current report.
+ * 	It also lets the user select which algorithms will be made
+ * 	Visible or Public.
+ */
+angular.module('reportApp')
+.directive("reportPublish", ['reportFactory', 'ReportService', '$timeout', function(reportFactory, ReportService, $timeout){
+	return {
+		scope: {
+		},
+		restrict: 'E',
+		link: function(scope, el){
+			scope.algorithms = [];
+			scope.radios = {};
+
+			// sets up the data for the modal and opens it
+			scope.buildPublishModal = () => {
+				return reportFactory.publishReportAlgorithms(ReportService.author, ReportService.name, '')
+				.then(res => {
+					// rm past data
+					scope.algorithms.splice(0, scope.algorithms.length);
+					Object.keys(scope.radios).forEach(k => delete scope.radios[k]);
+
+					// init new data
+					res.data.forEach(a => scope.algorithms.push(a));
+					scope.algorithms.forEach(a => { scope.radios[a] = ''; });
+				})
+				.catch(error => {
+					console.error(error);
+				})
+				;
+			};
+
+			$timeout(() => $('#publishReportModal').on('show.bs.modal', function(e){ return scope.buildPublishModal(); }), 0);
+
+			// sends the request to publish the report, along with the algs chosen to be OS
+			scope.publishReport = () => {
+				const openSourceAlgs = Object.entries(scope.radios)
+				.filter(([alg, val]) => val === 'openSource')
+				.map(([alg, val]) => alg);
+
+				const data = JSON.stringify({
+					visible_algorithms: openSourceAlgs
+				});
+
+				return ReportService.publishReport(openSourceAlgs);
+			};
+		},
+		template: `
+<bootstrap-modal dom-id='publishReportModal' button-submit-text='Publish' button-submit-func='publishReport'>
+	<b-title>
+		Publish Report
+	</b-title>
+	<b-content>
+		<p>Publishing your report will make it accessible to anyone. Your report will not be editable anymore.</p>
+		<div ng-if='algorithms.length > 0'>
+			<p>The following algorithms will become public.
+			They can either be <i>Visible</i> (no-one else can see inside the algorithm, but others can still use it) or <i>Open-Source</i> (the entire algorithm is visible as well as useable).
+			Choose which algorithms will be Visible, and which will be Open-Source:</p>
+			<form>
+			<table class='table table-striped'>
+				<thead>
+					<tr>
+						<td>Visible</td>
+						<td>Open-Source</td>
+						<td>Algorithm</td>
+					</tr>
+				</thead>
+				<tbody>
+					<tr ng-repeat='alg in algorithms'>
+						<td><input type='radio' name='{{ alg }}' ng-model='radios[alg]' value='visible'></td>
+						<td><input type='radio' name='{{ alg }}' ng-model='radios[alg]' value='openSource' checked></td>
+						<td>{{ alg }}</td>
+					</tr>
+				</tbody>
+			</table>
+			</form>
+		</div>
+	</b-content>
+</bootstrap-modal>
+`
+	};
+}]);
diff --git a/beat/web/reports/static/reports/app/directives/publishReport.js b/beat/web/reports/static/reports/app/directives/publishReport.js
deleted file mode 100644
index 2595699e5dd5d1c0e88624a39f73e3c265d89d2e..0000000000000000000000000000000000000000
--- a/beat/web/reports/static/reports/app/directives/publishReport.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/
- * Contact: beat.support@idiap.ch
- *
- * This file is part of the beat.web module of the BEAT platform.
- *
- * Commercial License Usage
- * Licensees holding valid commercial BEAT licenses may use this file in
- * accordance with the terms contained in a written agreement between you
- * and Idiap. For further information contact tto@idiap.ch
- *
- * Alternatively, this file may be used under the terms of the GNU Affero
- * Public License version 3 as published by the Free Software and appearing
- * in the file LICENSE.AGPL included in the packaging of this file.
- * The BEAT platform is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the GNU Affero Public License along
- * with the BEAT platform. If not, see http://www.gnu.org/licenses/.
- */
-
-//Directive for opening smart_selector list on "Add a report item" button click that displays options
-angular.module('reportApp').directive("publishreport", function($compile){
-	return function(scope, element, attrs){
-		//add new report item
-		element.bind("click", function(){
-			scope.reportFactory.publishReportAlgorithms(scope.user, scope.report_id, scope.url_prefix)
-			.success(function (reportData){
-				beat.ui.report.publish_report('report_publish', scope, reportData);
-			})
-			.error(function (error){
-				scope.status = 'Unable to publish report data: ' + error;
-				$(".explanation_text").hide();
-				$("#report_publish .warnings").hide();
-				$("#report_publish .errors").show();
-				if(error.detail != undefined)
-					scope.status = 'Unable to publish report data: ' + error.detail;
-				$("#report_publish .errors .errorslist").append(scope.status);
-				$("#button-report_publish-cancel").hide();
-			});
-		});
-	};
-});
-
diff --git a/beat/web/reports/static/reports/app/directives/saveReportItems.js b/beat/web/reports/static/reports/app/directives/save.js
similarity index 60%
rename from beat/web/reports/static/reports/app/directives/saveReportItems.js
rename to beat/web/reports/static/reports/app/directives/save.js
index 772b85c0a49ea12e99366b6cbb62d0d1bfaf9214..0a2a40c5378f3c27920e70ce63cd28f0e13fbe5e 100644
--- a/beat/web/reports/static/reports/app/directives/saveReportItems.js
+++ b/beat/web/reports/static/reports/app/directives/save.js
@@ -20,22 +20,31 @@
  * with the BEAT platform. If not, see http://www.gnu.org/licenses/.
  */
 
-// Saves the report
-angular.module('reportApp').directive("savereportitems", ['$compile', 'GroupsService', function($compile, GroupsService){
-	return function(scope, element, attrs){
-		//add new report item
-		element.bind("click", function(){
-			//call set report content from factory
-			let mydict = {};
-			mydict["content"] = {
-				'groups': GroupsService.serializeGroups()
+/*
+ * reportSave
+ * Desc:
+ * 	saves the current report
+ */
+angular.module('reportApp')
+.directive("reportSave", ['GroupsService', 'ReportService', 'reportFactory', function(GroupsService, ReportService, reportFactory){
+	return {
+		scope: {
+		},
+		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.updateReport(ReportService.author, ReportService.name, saveData, '')
 			};
 
-			scope.reportFactory.updateReport(scope.user, scope.report_id, mydict, scope.url_prefix)
-			.error(function (error){
-			});
-		});
+			el.bind('click', saveReport);
+		},
 	};
 }]);
-
-
diff --git a/beat/web/reports/static/reports/app/services/modalService.js b/beat/web/reports/static/reports/app/services/modalService.js
new file mode 100644
index 0000000000000000000000000000000000000000..5781da240664bc1591525254c1044bb8542d4daf
--- /dev/null
+++ b/beat/web/reports/static/reports/app/services/modalService.js
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/
+ * Contact: beat.support@idiap.ch
+ *
+ * This file is part of the beat.web module of the BEAT platform.
+ *
+ * Commercial License Usage
+ * Licensees holding valid commercial BEAT licenses may use this file in
+ * accordance with the terms contained in a written agreement between you
+ * and Idiap. For further information contact tto@idiap.ch
+ *
+ * Alternatively, this file may be used under the terms of the GNU Affero
+ * Public License version 3 as published by the Free Software and appearing
+ * in the file LICENSE.AGPL included in the packaging of this file.
+ * The BEAT platform is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the GNU Affero Public License along
+ * with the BEAT platform. If not, see http://www.gnu.org/licenses/.
+ */
+
+/*
+ * ModalService
+ * Desc:
+ * 	Manages the "global" reports app modal (content, etc.)
+ */
+angular.module('reportApp').factory('ModalService', [function(){
+	const ms = {
+		_title: '',
+		_content: '',
+		_buttonCancelText: '',
+		_buttonCancelFunc: () => {},
+		_buttonSubmitText: null,
+		_buttonSubmitFunc: () => {},
+		_modalId: 'reportModal'
+	};
+
+	// activates the modal, with an optional shortcut for specifying title & content text
+	ms.activateModal = (title, content) => {
+		if(ms._modalId.length > 0){
+			ms.setModalData(title, content);
+			return $(`#${ms._modalId}`).modal();
+		} else {
+
+		}
+	};
+
+	// sets the modal title & content
+	ms.setModalData = (titleStr, contentStr) => {
+		ms._title = titleStr || ms._title;
+		ms._content = contentStr || ms._content;
+	};
+
+	// sets the cancel button text & action
+	ms.setModalCancelData = (text, func) => {
+		ms._buttonCancelText = text && text.length > 0 ? text : 'Close';
+		ms._buttonCancelFunc = func ? func : () => {};
+	};
+
+	// sets the submit button text & action
+	ms.setModalSubmitData = (text, func) => {
+		ms._buttonSubmitText = text && text.length > 0 ? text : null;
+		ms._buttonSubmitFunc = func ? func : () => {};
+	};
+
+	return ms;
+}]);
diff --git a/beat/web/reports/static/reports/app/services/reportService.js b/beat/web/reports/static/reports/app/services/reportService.js
index 95934697f8c9ca2cc833bfcf594dd14466e06c3f..eb81818fc528442c479376540a80b4aa8117f52f 100644
--- a/beat/web/reports/static/reports/app/services/reportService.js
+++ b/beat/web/reports/static/reports/app/services/reportService.js
@@ -33,7 +33,8 @@ angular.module('reportApp').factory('ReportService', ['GroupsService', 'plotterF
 	rs.isOwner = undefined;
 	rs.status = undefined;
 	rs.number = undefined;
-	rs.user = undefined;
+	rs.author = undefined;
+	rs.name = undefined;
 
 	rs.plotters = [];
 	rs.defaultPlotters = [];
@@ -49,7 +50,8 @@ angular.module('reportApp').factory('ReportService', ['GroupsService', 'plotterF
 		rs.isOwner = report.is_owner;
 		rs.status = report.status;
 		rs.number = report.number;
-		rs.user = report.user;
+		rs.author = report.author;
+		rs.name = report.name.split('/').length > 1 ? report.name.split('/')[1] : null;
 
 		// start up our GroupsService
 		GroupsService.loadGroups(report.content.groups);
@@ -107,6 +109,35 @@ angular.module('reportApp').factory('ReportService', ['GroupsService', 'plotterF
 		}
 	};
 
+	// publish the report
+	rs.publishReport = (openSourceAlgs) => {
+		return reportFactory.publishReport(
+			'',
+			ReportService.author,
+			ReportService.name,
+			openSourceAlgs.length && openSourceAlgs.length > 0 ? data : undefined
+		)
+		.catch(error => {
+			console.error(`Failed to publish report: ${error}`);
+			throw error;
+		});
+		;
+	};
+
+	// lock the report
+	rs.lockReport = () => {
+		return reportFactory.lockReport(
+			rs.author,
+			rs.name,
+			''
+		)
+		.catch(error => {
+			console.error(`Failed to lock report: ${error}`);
+			throw error;
+		});
+		;
+	};
+
 	rs.fetchReport()
 	.catch(e => console.error(e));
 
diff --git a/beat/web/reports/templates/reports/panels/actions.html b/beat/web/reports/templates/reports/panels/actions.html
index 2994f3698cc8e69171b75bb46bf80d47e8042a73..823d722c81f164b3b71c2af04373e4465555447a 100644
--- a/beat/web/reports/templates/reports/panels/actions.html
+++ b/beat/web/reports/templates/reports/panels/actions.html
@@ -1,21 +1,21 @@
 {% comment %}
  * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/
  * Contact: beat.support@idiap.ch
- * 
+ *
  * This file is part of the beat.web module of the BEAT platform.
- * 
+ *
  * Commercial License Usage
  * Licensees holding valid commercial BEAT licenses may use this file in
  * accordance with the terms contained in a written agreement between you
  * and Idiap. For further information contact tto@idiap.ch
- * 
+ *
  * Alternatively, this file may be used under the terms of the GNU Affero
  * Public License version 3 as published by the Free Software and appearing
  * in the file LICENSE.AGPL included in the packaging of this file.
  * The BEAT platform is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  * or FITNESS FOR A PARTICULAR PURPOSE.
- * 
+ *
  * You should have received a copy of the GNU Affero Public License along
  * with the BEAT platform. If not, see http://www.gnu.org/licenses/.
 {% endcomment %}
@@ -39,12 +39,20 @@
   {% 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" savereportitems><i class="fa fa-floppy-o fa-lg"></i></a>
-  <a class="btn btn-default btn-report" data-toggle="tooltip" data-placement="bottom" title="Lock" lockreport><i class="fa fa-lock fa-lg"></i></a>
+  <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>
+  <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>
+	  </a>
+  </span>
   {% endif %}
 
   {% elif status == 'Locked' and not display_count %}
-  <a class="btn btn-default btn-report" data-toggle="tooltip" data-placement="bottom" title="Publish" publishreport><i class="fa fa-globe fa-lg"></i></a>
+  <span  class="btn btn-default" data-toggle='modal' data-target='#publishReportModal'>
+	  <a class="btn-report" data-toggle="tooltip" data-placement="bottom" title="Publish">
+		  <i class="fa fa-globe fa-lg"></i>
+	  </a>
+  </span>
   {% endif %}
 
   {% endifequal %}
@@ -56,6 +64,15 @@
 
   <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>
+  {% endif %}
+
+  {% if not display_count and status == 'Locked' %}
+  <report-publish></report-publish>
+  {% endif %}
+
+
 </div>
 
 {% endwith %}
diff --git a/beat/web/reports/templates/reports/report.html b/beat/web/reports/templates/reports/report.html
index 2206a2548c350ff6146981436b77b718b9dac987..8d35c16a0b5878e4e9f9ccff91a78e40f6d06472 100644
--- a/beat/web/reports/templates/reports/report.html
+++ b/beat/web/reports/templates/reports/report.html
@@ -55,7 +55,7 @@
     <script src="{% fingerprint "datatables/media/js/dataTables.bootstrap.min.js" %}" type="text/javascript" charset="utf-8"></script>
 
     <!-- Use Google's CDN for angular-js with a local fallback -->
-    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
+    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
     <script>window.angular || document.write('<script src="{% fingerprint "angular/angular.min.js" %}"><\/script>');</script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.8/angular-filter.min.js"></script>
     <script src="{% fingerprint "angular-ui-router/release/angular-ui-router.min.js" %}" type="text/javascript" charset="utf-8"></script>
@@ -90,16 +90,17 @@
     <script src="{% fingerprint "reports/app/services/urlService.js" %}" type="text/javascript" charset="utf-8"></script>
     <script src="{% fingerprint "reports/app/services/reportService.js" %}" type="text/javascript" charset="utf-8"></script>
     <script src="{% fingerprint "reports/app/services/plotService.js" %}" type="text/javascript" charset="utf-8"></script>
+    <script src="{% fingerprint "reports/app/services/modalService.js" %}" type="text/javascript" charset="utf-8"></script>
 
     <!-- directives -->
-    <!-- old -->
-    <script src="{% fingerprint "reports/app/directives/lockReport.js" %}" type="text/javascript" charset="utf-8"></script>
-    <script src="{% fingerprint "reports/app/directives/publishReport.js" %}" type="text/javascript" charset="utf-8"></script>
-    <script src="{% fingerprint "reports/app/directives/saveReportItems.js" %}" type="text/javascript" charset="utf-8"></script>
 
     <!-- new -->
     <script src="{% fingerprint "reports/app/directives/tableItem.js" %}" type="text/javascript" charset="utf-8"></script>
     <script src="{% fingerprint "reports/app/directives/downloadLink.js" %}" type="text/javascript" charset="utf-8"></script>
+    <script src="{% fingerprint "reports/app/directives/bootstrapModal.js" %}" type="text/javascript" charset="utf-8"></script>
+    <script src="{% fingerprint "reports/app/directives/publish.js" %}" type="text/javascript" charset="utf-8"></script>
+    <script src="{% fingerprint "reports/app/directives/lock.js" %}" type="text/javascript" charset="utf-8"></script>
+    <script src="{% fingerprint "reports/app/directives/save.js" %}" type="text/javascript" charset="utf-8"></script>
 
     <!-- edit view -->
     {% if not report_number and report.get_status_display == 'Editable' and owner %}
@@ -141,10 +142,10 @@
 
 	{% if report %}
 	<div id="title" class="row">
-		<div class="{% if owner %}col-sm-9 vertical-center{% else %}col-sm-12{% endif %}"{% if owner %} onmouseover="expand_breadcrumb(this, 9, 3);" onmouseout="reset_breadcrumb(this, 9, 3);"{% endif %}>
+		<div class="{% if show_actionbar %}col-sm-9 vertical-center{% else %}col-sm-12{% endif %}"{% if show_actionbar %} onmouseover="expand_breadcrumb(this, 9, 3);" onmouseout="reset_breadcrumb(this, 9, 3);"{% endif %}>
 			{% report_breadcrumb report %}
 			<!-- Note: keep no space between divs here! -->
-			</div>{% if owner %}<div class="col-sm-3 vertical-center">
+			</div>{% if show_actionbar %}<div class="col-sm-3 vertical-center">
 			{% report_actions report False %}
 		</div>{% endif %}
 
diff --git a/beat/web/reports/views.py b/beat/web/reports/views.py
index 46f5be2ad123d13993896fc7ef106e22897172ac..0a778fea71f2d522d8e806deeba0575bc139df71 100644
--- a/beat/web/reports/views.py
+++ b/beat/web/reports/views.py
@@ -41,20 +41,28 @@ from .models import Report
 
 import simplejson as json
 
+# Permissions for viewing a report is complicated:
+# - 'E' indicates permissions to view the editable version of the report (usually accessed by author and report name)
+# - 'V' indicates permissions to view the view-only version of the report (usually accessed by report number)
+# - 'R' indicates that the user will be redirected from the editable version to the view-only version (but not given a 404)
+# | *Report State* X *User Type*           | Editable | Locked | Published |
+# | -------------------------------------: | :------: | :----: | :-------: |
+# | Report Author                          | E, V     | R, V   | R, V      |
+# | BEAT User                              | V        | V      | V         |
+# | Anonymous                              |          | V      | V         |
+# | Public (Published) Reports List Reader |          |        | V         |
+
+def show_actionbar(request, report):
+    correct_status = report.status == 'E' or report.status == 'L'
+    correct_user = request.user == report.author
+    is_admin = request.user.is_staff
+
+    return (correct_status and correct_user) or is_admin
+
 
 #------------------------------------------------
 
 
-# Permissions for viewing a report is complicated:
-# 'E' means that the specific type of user may view the editable mode
-# of the report when the report is in the specified state.
-# 'V' is the same, but for the view-only mode
-# REPORT STATE:       | Editable  | Locked    | Published |
-# USER:               -------------------------------------
-# Author              | E, V      | V         | V         |
-# BEAT User           | V         | V         | V         |
-# Anon                |           | V         | V         |
-# Public Reports List |           |           | V         |
 def by_number(request, number):
     # get the query from the DB
     obj = get_object_or_404(Report, number=int(number))
@@ -71,6 +79,7 @@ def by_number(request, number):
                 'owner': False,
                 'report': obj,
                 'USE_HTTPS_GRAVATAR': settings.USE_HTTPS_GRAVATAR,
+                'show_actionbar': show_actionbar(request, obj)
                 },
             context_instance=RequestContext(request))
 
@@ -104,6 +113,7 @@ def for_author(request, author_name, report_name):
                     'owner'       : (request.user == obj.author),
                     'report'      : obj,
                     'USE_HTTPS_GRAVATAR': settings.USE_HTTPS_GRAVATAR,
+                    'show_actionbar': show_actionbar(request, obj)
                     },
                 context_instance=RequestContext(request))
 
diff --git a/buildout.cfg b/buildout.cfg
index 66779e63e8f3295a8f75a1dac31154c0be540f8b..fa09ef7eb197b9136577b295c1a278c2ea4c4692 100644
--- a/buildout.cfg
+++ b/buildout.cfg
@@ -97,7 +97,7 @@ recipe = bob.buildout:scripts
 [docker_images]
 recipe = collective.recipe.cmd
 cmds = ./src/beat.core/buildout_pull_images.sh
-uninstall_cmds = 
+uninstall_cmds =
 on_install = true
 on_update = true
 
@@ -138,7 +138,7 @@ packages = jquery#~1.11.3
            spectrum#~1.7.1
            https://github.com/joshaven/string_score.git#~0.1.22
            chosen-bootstrap#~1.1.0
-           angularjs#~1.4.5
+           angularjs#~1.6.4
            angular-ui-router#~0.2.15
            chartjs#~1.0.2
            underscore#~1.8.3