From 69ece2bc0fde7500aa03584addf0e8d292ffdbe6 Mon Sep 17 00:00:00 2001
From: jaden <noreply@example.com>
Date: Fri, 9 Jun 2017 16:30:16 +0200
Subject: [PATCH] move plot management to panel header, better styling

---
 .../static/experiments/js/utils.js            |  32 ++++--
 .../app/directives/edit/addItemsMenu.js       |  13 ++-
 .../reports/app/directives/edit/plotItem.js   |  64 ++++++++++-
 .../reports/app/directives/view/plotItem.js   |  82 +++++++++++++-
 .../reports/app/services/plotService.js       | 107 +++++++++++-------
 beat/web/reports/static/reports/css/style.css |   2 +-
 6 files changed, 229 insertions(+), 71 deletions(-)

diff --git a/beat/web/experiments/static/experiments/js/utils.js b/beat/web/experiments/static/experiments/js/utils.js
index a27fb8994..7e3de93ba 100644
--- a/beat/web/experiments/static/experiments/js/utils.js
+++ b/beat/web/experiments/static/experiments/js/utils.js
@@ -111,11 +111,16 @@ beat.experiments.utils.displayPlot = function(
 				container.appendChild(table_element);
 
 				var tr = document.createElement('tr');
-				table_element.appendChild(tr);
-
 				var td = document.createElement('td');
-				td.appendChild(plotter_selector);
-				tr.appendChild(td);
+
+				console.log(value);
+				if(!value.report_number){
+					table_element.appendChild(tr);
+
+					var td = document.createElement('td');
+					td.appendChild(plotter_selector);
+					tr.appendChild(td);
+				}
 
 				// adds image place holder
 				var img = document.createElement('img');
@@ -169,11 +174,16 @@ beat.experiments.utils.displayPlot = function(
 		container.appendChild(table_element);
 
 		var tr = document.createElement('tr');
-		table_element.appendChild(tr);
-
 		var td = document.createElement('td');
-		td.appendChild(plotter_selector);
-		tr.appendChild(td);
+
+		console.log(value);
+		if(!value.report_number){
+			table_element.appendChild(tr);
+
+			var td = document.createElement('td');
+			td.appendChild(plotter_selector);
+			tr.appendChild(td);
+		}
 
 		$.ajaxSetup({
 			beforeSend: function(xhr, settings) {
@@ -195,9 +205,9 @@ beat.experiments.utils.displayPlot = function(
 
 						var td_title = document.createElement('td');
 						td_title.className = 'td_title';
-						const title_h2 = document.createElement('h2');
-						title_h2.textContent = _data.legend;
-						td_title.appendChild(title_h2);
+						const title_h3 = document.createElement('h3');
+						title_h3.textContent = _data.legend;
+						td_title.appendChild(title_h3);
 						tr_title.appendChild(td_title);
 					}
 					// adds image place holder
diff --git a/beat/web/reports/static/reports/app/directives/edit/addItemsMenu.js b/beat/web/reports/static/reports/app/directives/edit/addItemsMenu.js
index fdf783d97..e551dc117 100644
--- a/beat/web/reports/static/reports/app/directives/edit/addItemsMenu.js
+++ b/beat/web/reports/static/reports/app/directives/edit/addItemsMenu.js
@@ -26,7 +26,7 @@
  * 	the button group for adding report items (plot, table, text) to a group
  */
 angular.module('reportApp')
-.directive("groupAddItemsMenu", ['ExperimentsService', 'GroupsService', function(ExperimentsService, GroupsService){
+.directive("groupAddItemsMenu", ['ExperimentsService', 'GroupsService', 'PlotService', function(ExperimentsService, GroupsService, PlotService){
 	return {
 		scope: {
 			group: '='
@@ -89,9 +89,16 @@ angular.module('reportApp')
 				let content = {
 					itemName: `${plot.label}`,
 					name: plot.label,
-					type: plot.type
+					type: plot.type,
+					merged: true,
+					savedPlotter: '',
+					savedConfig: ''
 				};
 
+				content.savedPlotter = PlotService.getPlotter(content).name;
+				content.savedConfig = PlotService.getPlotterConfig(content).name;
+				console.log(content);
+
 				scope.group.addReportItem(id, content);
 			};
 
@@ -142,5 +149,5 @@ angular.module('reportApp')
 	</button>
 </div>
 `
-	}
+	};
 }]);
diff --git a/beat/web/reports/static/reports/app/directives/edit/plotItem.js b/beat/web/reports/static/reports/app/directives/edit/plotItem.js
index 2209328d4..614a6999e 100644
--- a/beat/web/reports/static/reports/app/directives/edit/plotItem.js
+++ b/beat/web/reports/static/reports/app/directives/edit/plotItem.js
@@ -66,7 +66,7 @@ angular.module('reportApp')
 					// redo the render
 					if(el && el.childNodes.length > 0){
 						el.innerHTML = '';
-						PlotService.addPlot(scope.group, scope.itemId, scope.renderDivId, updatePlotConfig);
+						return PlotService.addPlot(scope.group, scope.itemId, scope.renderDivId, updatePlotConfig);
 					}
 				};
 
@@ -90,6 +90,21 @@ angular.module('reportApp')
 				() => JSON.stringify(scope.group._aliases),
 				updatePlot
 			);
+
+			// if the user selected different plotter or config, rerender
+			scope.$watch(
+				() => `${scope.content.savedPlotter}|${scope.content.savedConfig}`,
+				updatePlot
+			);
+
+			scope.toggleMerged = () => {
+				scope.content.merged = !scope.content.merged;
+				updatePlot();
+			};
+
+			scope.getPlotter = () => PlotService.getPlotter(scope.content);
+			scope.getPossiblePlotters = () => PlotService.plotters.filter(p => p.dataformat === scope.content.type).map(p => p.name);
+			scope.getPossibleConfigs = () => PlotService.getPossibleConfigs(scope.getPlotter());
 		},
 		template: `
 <div id="{{domId}}-heading" class="panel-heading" role="tab">
@@ -117,11 +132,48 @@ angular.module('reportApp')
 				<i class='fa fa-arrows fa-lg'></i>
 			</span>
 		</div>
-		<download-link
-			dom-id='{{ domId }}'
-			group='group'
-			item-id='itemId'>
-		</download-link>
+		<div class='btn-group' role='group'>
+			<download-link
+				class='btn-group'
+				dom-id='{{ domId }}'
+				group='group'
+				item-id='itemId'>
+			</download-link>
+			<button ng-if='group.experiments.length > 1' class='btn btn-default' ng-click='toggleMerged()'>
+				<span ng-if='content.merged'><i class='fa fa-expand'></i> Expand</span>
+				<span ng-if='!content.merged'><i class='fa fa-compress'></i> Merge</span>
+			</button>
+			<div class='btn-group' role='group'>
+				<button
+					ng-class='{disabled: getPossiblePlotters().length === 1}'
+					class='btn btn-default dropdown-toggle'
+					type="button"
+					data-toggle="dropdown"
+					aria-haspopup="true"
+					aria-expanded="false">
+					Plotter: {{ content.savedPlotter }}
+					<span class="caret"></span>
+				</button>
+				<ul class="dropdown-menu">
+					<li ng-click='content.savedPlotter = p' ng-repeat='p in getPossiblePlotters()'><a>{{ p }}</a></li>
+				</ul>
+			</div>
+			<div class='btn-group' role='group'>
+				<button
+					ng-class='{disabled: getPossibleConfigs().length === 1}'
+					class='btn btn-default dropdown-toggle'
+					type="button"
+					data-toggle="dropdown"
+					aria-haspopup="true"
+					aria-expanded="false">
+					Config: {{ content.savedConfig }}
+					<span class="caret"></span>
+				</button>
+				<ul class="dropdown-menu">
+					<li ng-click='content.savedConfig = c' ng-repeat='c in getPossibleConfigs()'><a>{{ c }}</a></li>
+				</ul>
+			</div>
+		</div>
 	</h4>
 </div>
 <div id="collapse-{{domId}}"
diff --git a/beat/web/reports/static/reports/app/directives/view/plotItem.js b/beat/web/reports/static/reports/app/directives/view/plotItem.js
index efb9d6d08..41766da6b 100644
--- a/beat/web/reports/static/reports/app/directives/view/plotItem.js
+++ b/beat/web/reports/static/reports/app/directives/view/plotItem.js
@@ -54,6 +54,39 @@ angular.module('reportApp')
 			$timeout(function() {
 				PlotService.addPlot(scope.group, scope.itemId, scope.renderDivId, updatePlotConfig);
 			});
+
+			let plotTimer;
+
+			const updatePlot = () => {
+				clearTimeout(plotTimer);
+
+				const queueUpdate = () => {
+					let el = document.querySelector(`#${scope.renderDivId}`);
+					// if the container is rendered and it already has had a render,
+					// redo the render
+					if(el && el.childNodes.length > 0){
+						el.innerHTML = '';
+						return PlotService.addPlot(scope.group, scope.itemId, scope.renderDivId, updatePlotConfig);
+					}
+				};
+
+				plotTimer = setTimeout(queueUpdate, 1000);
+			};
+
+			// if the user selected different plotter or config, rerender
+			scope.$watch(
+				() => `${scope.content.savedPlotter}|${scope.content.savedConfig}`,
+				updatePlot
+			);
+
+			scope.toggleMerged = () => {
+				scope.content.merged = !scope.content.merged;
+				updatePlot();
+			};
+
+			scope.getPlotter = () => PlotService.getPlotter(scope.content);
+			scope.getPossiblePlotters = () => PlotService.plotters.filter(p => p.dataformat === scope.content.type).map(p => p.name);
+			scope.getPossibleConfigs = () => PlotService.getPossibleConfigs(scope.getPlotter());
 		},
 		template: `
 <div id="{{domId}}-heading" class="panel-heading" role="tab">
@@ -66,13 +99,50 @@ angular.module('reportApp')
 			href="#collapse-{{domId}}"
 			aria-expanded="true"
 			aria-controls="collapse-{{domId}}">
-			{{ content.itemName }}&nbsp;
 		</a>
-		<download-link
-			dom-id='{{ domId }}'
-			group='group'
-			item-id='itemId'>
-		</download-link>
+		{{ content.itemName }}
+		<div class='btn-group' role='group'>
+			<download-link
+				class='btn-group'
+				dom-id='{{ domId }}'
+				group='group'
+				item-id='itemId'>
+			</download-link>
+			<button ng-if='group.experiments.length > 1' class='btn btn-default' ng-click='toggleMerged()'>
+				<span ng-if='content.merged'><i class='fa fa-expand'></i> Expand</span>
+				<span ng-if='!content.merged'><i class='fa fa-compress'></i> Merge</span>
+			</button>
+			<div class='btn-group' role='group'>
+				<button
+					ng-class='{disabled: getPossiblePlotters().length === 1}'
+					class='btn btn-default dropdown-toggle'
+					type="button"
+					data-toggle="dropdown"
+					aria-haspopup="true"
+					aria-expanded="false">
+					Plotter: {{ content.savedPlotter }}
+					<span class="caret"></span>
+				</button>
+				<ul class="dropdown-menu">
+					<li ng-click='content.savedPlotter = p' ng-repeat='p in getPossiblePlotters()'><a>{{ p }}</a></li>
+				</ul>
+			</div>
+			<div class='btn-group' role='group'>
+				<button
+					ng-class='{disabled: getPossibleConfigs().length === 1}'
+					class='btn btn-default dropdown-toggle'
+					type="button"
+					data-toggle="dropdown"
+					aria-haspopup="true"
+					aria-expanded="false">
+					Config: {{ content.savedConfig }}
+					<span class="caret"></span>
+				</button>
+				<ul class="dropdown-menu">
+					<li ng-click='content.savedConfig = c' ng-repeat='c in getPossibleConfigs()'><a>{{ c }}</a></li>
+				</ul>
+			</div>
+		</div>
 	</h4>
 </div>
 <div id="collapse-{{domId}}"
diff --git a/beat/web/reports/static/reports/app/services/plotService.js b/beat/web/reports/static/reports/app/services/plotService.js
index a80aa1d78..1422448a7 100644
--- a/beat/web/reports/static/reports/app/services/plotService.js
+++ b/beat/web/reports/static/reports/app/services/plotService.js
@@ -31,13 +31,13 @@
  * 	- Rendering
  */
 angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlService){
-	const ps = {};
-
-	// these are provided by ReportService
-	let plotters;
-	let defaultPlotters;
-	let plotterParameters;
-	let reportNumber;
+	const ps = {
+		// these are provided by ReportService
+		plotters: [],
+		defaultPlotters: [],
+		plotterParameters: [],
+		reportNumber: undefined
+	};
 
 	// this 'queue' idea is the solution to trying to load plots before we receive all the data
 	// from the server that we need (report info, exp info, etc.).
@@ -46,29 +46,53 @@ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlSe
 	const queue = [];
 	let noQueueNeeded = false;
 
-	// constructs the payload to send to the server
-	const constructPlotInfo = (group, itemId) => {
-		console.log(group);
-		const content = group.reportItems.find(i => i.id === itemId).content;
+	const getDefaults = (plotType) => ps.defaultPlotters.find(p => p.dataformat === plotType);
 
+	// data to be used in to interact with the plot
+	// users can change the plotter used if theres more than 1 available for that
+	// plot type
+	const getPossiblePlotters = (itemContent) =>
+		ps.plotters.filter(p => p.dataformat === itemContent.type).map(p => p.name);
+
+	// users can choose which params to use if more than 1 available
+	// for that plotter
+	const getPossibleConfigs = (plotter) =>
+		ps.plotterParameters.filter(pp => plotter.id === pp.plotter).map(pp => pp.name);
+
+	const getPlotter = (itemContent) => {
+		const savedPlotterName = itemContent.savedPlotter;
 		// defaults obj, in case we're using defaults
-		const defaults = defaultPlotters.find(p => p.dataformat === content.type);
-		if (!defaults) {
-			console.log(`No default plotter found for content type ${JSON.stringify(content.type)} out of:`);
-			console.log(defaultPlotters);
-		}
+		const defaults = getDefaults(itemContent.type);
 
 		// a plot obj can have different plotters,
-		let plotter = plotters.find(p => p.name === content.savedPlotter) || plotters.find(p => p.name === defaults.plotter);
+		const plotter = ps.plotters.find(p => p.name === itemContent.savedPlotter) ||
+			ps.plotters.find(p => p.name === defaults.plotter);
+
+		return plotter;
+	};
 
-		// which can each have different configurations (plotter parameter instances)
-		let config = plotterParameters.find(pp => pp.name === content.savedConfig) || plotterParameters.find(pp => pp.name === defaults.parameter);
+	const getPlotterConfig = (itemContent) => {
+		// defaults obj, in case we're using defaults
+		const defaults = getDefaults(itemContent.type);
+
+		// each plotter obj can each have different configurations (plotter parameter instances)
+		const config = ps.plotterParameters.find(pp => pp.name === itemContent.savedConfig) ||
+			ps.plotterParameters.find(pp => pp.name === defaults.parameter);
+
+		return config;
+	};
+
+	// constructs the payload to send to the server
+	const constructPlotInfo = (group, itemId) => {
+		const content = group.reportItems.find(i => i.id === itemId).content;
+		const plotter = getPlotter(content);
+		const config = getPlotterConfig(content);
 
-		if(!content || !defaults || !plotter || !config){
+		if(!content || !plotter || !config){
 			console.error(`plotter info not found: content: ${content} defaults: ${defaults} plotter: ${plotter} config: ${config}`);
-			console.log(plotters);
-			console.log(defaultPlotters);
-			console.log(plotterParameters);
+			console.log(ps.plotters);
+			console.log(ps.defaultPlotters);
+			console.log(ps.plotterParameters);
 			return;
 		}
 
@@ -83,7 +107,7 @@ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlSe
 
 		// the data to be sent to the server
 		const requestData = {
-			report_number: reportNumber,
+			report_number: ps.reportNumber,
 			// exps in the group
 			experiment: group.experiments,
 			// group's analyzer
@@ -101,29 +125,17 @@ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlSe
 			merged: content.merged === undefined ? true : content.merged
 		};
 
-		// data to be used in to interact with the plot
-		// users can change the plotter used if theres more than 1 available for that
-		// plot type
-		const possiblePlotters = plotters
-		.filter(p => p.dataformat === content.type)
-		.map(p => p.name)
-		;
-
-		// users can choose which params to use if more than 1 available
-		// for that plotter
-		const possibleParameters = plotterParameters
-		.filter(pp => plotter.id === pp.plotter)
-		.map(pp => pp.name)
-		;
+		const possiblePlotters = getPossiblePlotters(content);
+		const possibleConfigs = getPossibleConfigs(plotter);
 
 		console.log(`Request data:`);
 		console.log(requestData);
 		console.log(`possible plotters:`);
 		console.log(possiblePlotters);
 		console.log(`possible parameters:`);
-		console.log(possibleParameters);
+		console.log(possibleConfigs);
 
-		const returnStruct = [requestData, possiblePlotters, possibleParameters];
+		const returnStruct = [requestData, possiblePlotters, possibleConfigs];
 
 		return returnStruct;
 	};
@@ -204,10 +216,10 @@ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlSe
 	// processes the queue and sets the plotService state such that we dont need to use
 	// the queue after this
 	ps.processQueue = (rsPlotters, rsDefaultPlotters, rsPlotterParameters, rsReportNumber) => {
-		plotters = rsPlotters;
-		defaultPlotters = rsDefaultPlotters;
-		plotterParameters = rsPlotterParameters;
-		reportNumber = rsReportNumber;
+		rsPlotters.forEach(p => ps.plotters.push(p));
+		rsDefaultPlotters.forEach(dp => ps.defaultPlotters.push(dp));
+		rsPlotterParameters.forEach(pp => ps.plotterParameters.push(pp));
+		ps.reportNumber = rsReportNumber;
 
 		noQueueNeeded = true;
 		const promises = queue.map(q => processItem(...q));
@@ -223,5 +235,12 @@ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlSe
 	// args: group, itemId, contentType
 	ps.downloadPlot = (...args) => processDownload(...args);
 
+	ps.getPlotter = getPlotter;
+	ps.getPlotterConfig = getPlotterConfig;
+	ps.getPossiblePlotters = getPossiblePlotters;
+	ps.getPossibleConfigs = getPossibleConfigs;
+
+	console.log(ps);
+
 	return ps;
 }]);
diff --git a/beat/web/reports/static/reports/css/style.css b/beat/web/reports/static/reports/css/style.css
index 0440251a9..8bbdc3678 100644
--- a/beat/web/reports/static/reports/css/style.css
+++ b/beat/web/reports/static/reports/css/style.css
@@ -211,7 +211,7 @@ div.report_commands div.report_buttons_bloc .publish_report:hover
     border-color: #4f85bb;
 }
 
-.td_title > h2 {
+.td_title > h3 {
     margin-left: 20px;
     margin-bottom: 0;
 }
-- 
GitLab