From 541d0f7faa1b349209ba7fdc497499dc8f2eef39 Mon Sep 17 00:00:00 2001
From: Jaden Diefenbaugh <blakcap@users.noreply.github.com>
Date: Mon, 3 Apr 2017 11:08:55 +0200
Subject: [PATCH] documentation & minor tweaks

---
 .../app/controllers/reportController.js       |  3 +-
 .../app/services/experimentsService.js        |  9 ++++
 .../reports/app/services/groupsService.js     | 47 +++++++++++++------
 .../reports/app/services/plotService.js       | 29 ++++++++++--
 .../reports/app/services/reportService.js     | 27 +++++++++--
 .../web/reports/templates/reports/report.html |  1 +
 6 files changed, 90 insertions(+), 26 deletions(-)

diff --git a/beat/web/reports/static/reports/app/controllers/reportController.js b/beat/web/reports/static/reports/app/controllers/reportController.js
index 677bc8518..2c4700588 100644
--- a/beat/web/reports/static/reports/app/controllers/reportController.js
+++ b/beat/web/reports/static/reports/app/controllers/reportController.js
@@ -27,8 +27,7 @@
  *
  * This controller is "deprecated" - it needs to be completely removed, and should not be expanded/built upon.
  */
-angular.module('reportApp').controller('reportController',['$scope', 'reportFactory', function ($scope, reportFactory){
-	$scope.q = $q;
+angular.module('reportApp').controller('reportController',['$scope', 'reportFactory', 'ReportService', function ($scope, reportFactory, ReportService){
 	$scope.user;
 	$scope.report_id;
 	$scope.url_prefix;
diff --git a/beat/web/reports/static/reports/app/services/experimentsService.js b/beat/web/reports/static/reports/app/services/experimentsService.js
index 90a413959..98a1999f0 100644
--- a/beat/web/reports/static/reports/app/services/experimentsService.js
+++ b/beat/web/reports/static/reports/app/services/experimentsService.js
@@ -146,6 +146,7 @@ angular.module('reportApp').factory('ExperimentsService', ['experimentFactory',
 	};
 
 	// make sure there are no invalid experiments in the report's groups
+	// invalid -> in a group but not in the report
 	const cleanGroups = (validExpNames) => {
 		GroupsService.groups.forEach(g => {
 			g.experiments.forEach(e => {
@@ -163,6 +164,7 @@ angular.module('reportApp').factory('ExperimentsService', ['experimentFactory',
 		});
 	};
 
+	// fetch the exp data and process it
 	const loadExperiments = () => {
 		let expFetch;
 		const namePath = UrlService.getByNamePath();
@@ -181,10 +183,17 @@ angular.module('reportApp').factory('ExperimentsService', ['experimentFactory',
 
 		return expFetch
 		.then((exps) => {
+			// save the exp names as they were given by the server
 			Object.keys(exps).forEach(e => rawExpNames.push(e));
 
+			// process the given exp data
 			Object.entries(exps)
 			.forEach(([expName, exp]) => {
+				// depending on the permissions of the user
+				// when viewing this report
+				// the author/toolchain may be hidden.
+				// to be safe, always process
+				// both the given name (either the full or short name)
 				const shortName = expName.split('/').pop();
 				for(let n of [shortName, expName]){
 					expData[n] = exp;
diff --git a/beat/web/reports/static/reports/app/services/groupsService.js b/beat/web/reports/static/reports/app/services/groupsService.js
index 6e4460200..e4f8908f9 100644
--- a/beat/web/reports/static/reports/app/services/groupsService.js
+++ b/beat/web/reports/static/reports/app/services/groupsService.js
@@ -23,8 +23,8 @@
 /*
  * GroupsService
  * Desc:
- * 	The datastore for the reports app, including data fetched from the
- * 	server and cross-component app state
+ * 	The main datastore for the reports app, holding the tree of
+ * 	relationships between groups, experiments, aliases, and report items
  */
 angular.module('reportApp').factory('GroupsService', ['reportFactory', function(reportFactory){
 	let groupsServiceInstance = {};
@@ -47,6 +47,9 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function(
 		/*
 		 * deepFreeze func found http://stackoverflow.com/a/34776962
 		 * changed to use ES6 functionality
+		 * recursively freezes a JS obj so it cant be altered
+		 * just a nice layer of safety to make sure
+		 * the frontend doesnt change if the backend wont change
 		 */
 		const deepFreeze = (o) => {
 			Object.freeze(o);
@@ -114,6 +117,8 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function(
 		}
 
 		// add an exp to this group
+		// optionally sets the analyzer
+		// initializes the new exp's alias to its name
 		addExperiment (expName, analyzer) {
 			let res = this._experimentNames.add(expName);
 			if(this._experimentNames.size === 1 && analyzer && analyzer.length > 0){
@@ -127,7 +132,7 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function(
 			return res;
 		}
 
-		// rm an exp from this group
+		// rm an exp from this group as well as its alias
 		removeExperiment (expName) {
 			let res = this._experimentNames.delete(expName);
 			if(this._experimentNames.size === 0){
@@ -139,7 +144,7 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function(
 			return res;
 		}
 
-		// add an item (table or plot) to this group
+		// add an item (table, plot, or text block) to this group
 		// if the id already exists, it just replaces the old
 		// element with the new one
 		addReportItem (id, content) {
@@ -157,7 +162,7 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function(
 			}
 		}
 
-		// rm an exp from this group
+		// rm a report item from this group
 		removeReportItem (id) {
 			let idx = this._reportItems
 			.indexOf(this._reportItems.find(o => o.id === id));
@@ -185,9 +190,16 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function(
 
 	// serializes groups as an object with form:
 	// {
-	// 	<group name 1>: { experiments: [], reportItems: [], analyzer: '' },
+	// 	<group name 1>: {
+	// 		experiments: [],
+	// 		reportItems: [],
+	// 		analyzer: '',
+	// 		aliases: {},
+	// 		idx: 1
+	// 		},
 	// 	...
 	// }
+	// the 'idx' saves the ordering of the groups
 	groupsServiceInstance.serializeGroups = () => {
 		return groupData
 		.map((g, i) => { return {
@@ -222,6 +234,7 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function(
 	};
 
 	// delete a group
+	// via MUTATING the groupdata
 	groupsServiceInstance.deleteGroup = (name) => {
 		let idx = groupData.indexOf(groupData.find(g => g.name === name));
 		if (idx > -1) {
@@ -231,11 +244,17 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function(
 
 	// load group info from the serialized format:
 	// {
-	// 	<group name 1>: { experiments: [], reportItems: [], analyzer: '' },
+	// 	<group name 1>: {
+	// 		experiments: [],
+	// 		reportItems: [],
+	// 		analyzer: '',
+	// 		aliases: {},
+	// 		idx: 1
+	// 		},
 	// 	...
 	// }
 	groupsServiceInstance.loadGroups = (data) => {
-		// wipe data and load groups
+		// wipe data
 		groupData.splice(0, groupData.length);
 		let safeData = data || {};
 
@@ -251,10 +270,15 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function(
 		})
 		.forEach(([groupName, gData]) => {
 			let g = groupsServiceInstance.createGroup(groupName);
+
+			// default group data to empty
 			let analyzer = gData.analyzer || '';
 			let experiments = gData.experiments || [];
 			let reportItems = gData.reportItems || [];
 			let aliases = gData.aliases || {};
+
+			// save fields to group
+			// by MUTATING the group obj
 			g.analyzer = analyzer;
 			experiments.forEach(n => g.addExperiment(n));
 			reportItems.forEach(i => g.addReportItem(i.id, i.content));
@@ -262,12 +286,5 @@ angular.module('reportApp').factory('GroupsService', ['reportFactory', function(
 		});
 	};
 
-	// helper to assert that a group exists
-	function checkForGroup (groupName) {
-		if(!groupData.find(g => g.name === groupName)){
-			throw new Error(`Could not find group "${JSON.stringify(groupName)}"`);
-		}
-	}
-
 	return groupsServiceInstance;
 }]);
diff --git a/beat/web/reports/static/reports/app/services/plotService.js b/beat/web/reports/static/reports/app/services/plotService.js
index 996520b28..d5a6c1ff5 100644
--- a/beat/web/reports/static/reports/app/services/plotService.js
+++ b/beat/web/reports/static/reports/app/services/plotService.js
@@ -33,15 +33,20 @@
 angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlService){
 	const ps = {};
 
-	// these are provided by reportService
+	// these are provided by ReportService
 	let plotters;
 	let defaultPlotters;
 	let plotterParameters;
 	let reportNumber;
 
+	// 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.).
+	// until the queue is processed (after which, no queue is needed),
+	// plots that want to be rendered are added to a queue to wait.
 	const queue = [];
 	let noQueueNeeded = false;
 
+	// constructs the payload to send to the server
 	const constructPlotInfo = (group, itemId) => {
 		const content = group.reportItems.find(i => i.id === itemId).content;
 
@@ -57,12 +62,14 @@ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlSe
 		console.log(config);
 
 		// sanity check for the plotter & config
+		// the config's "plotter" field should be equal to the plotter's id field
 		if(!(config.plotter === plotter.id)){
 			console.error(`Config plotter val "${config.plotter}" != plotter id "${plotter.id}":`);
 			console.log(config);
 			console.log(plotter);
 		};
 
+		// the data to be sent to the server
 		const requestData = {
 			report_number: reportNumber,
 			// exps in the group
@@ -82,11 +89,16 @@ 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)
@@ -106,10 +118,14 @@ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlSe
 		return returnStruct;
 	};
 
+	// makes the call to the server, via some helper funcs found in the global namespace
 	const fetchRenderUsingStruct = (requestData, containerId) => {
-		const urlPrefix = ''//UrlService.getApiSegment().split('/').filter(s => s.length > 0).join('/');
+		// the 'url_prefix' field found throughout the BEAT code is confusing,
+		// but it seems to always be an empty string now
+		const urlPrefix = '';//UrlService.getApiSegment().split('/').filter(s => s.length > 0).join('/');
 		console.log(urlPrefix);
-		// promisify this utils func
+
+		// promisify this utils func so we dont have to deal with callback hell
 		return new Promise((resolve, reject) => {
 			beat.experiments.utils.displayPlot(
 				// url_prefix
@@ -130,11 +146,13 @@ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlSe
 		});
 	};
 
+	// helper func to process a request to plot
 	const processItem = (group, itemId, containerId) => {
 		const reqData = constructPlotInfo(group, itemId);
 		return fetchRenderUsingStruct(reqData, containerId);
 	};
 
+	// used if we arent ready to directly service requests
 	const addItemToQueue = (group, itemId, containerId) => {
 		queue.push([
 			group,
@@ -144,7 +162,9 @@ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlSe
 	};
 
 	// called by ReportService,
-	// or by someone having this report-level info
+	// or by someone having this report-level info.
+	// 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;
@@ -158,6 +178,7 @@ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlSe
 		return promises;
 	};
 
+	// chooses whether to add the plot request to a queue or service directly
 	// args: group, itemId, containerId
 	ps.addPlot = (...args) => noQueueNeeded ? processItem(...args) : addItemToQueue(...args);
 
diff --git a/beat/web/reports/static/reports/app/services/reportService.js b/beat/web/reports/static/reports/app/services/reportService.js
index 39c534e40..160963c2a 100644
--- a/beat/web/reports/static/reports/app/services/reportService.js
+++ b/beat/web/reports/static/reports/app/services/reportService.js
@@ -24,7 +24,7 @@
  * ReportService
  * Desc:
  * 	Consumes the "report" object from the API and digests it into helper
- * 	funcs and report-wide info. Basically an adaptor.
+ * 	funcs and report-wide info. Basically an adaptor & bootstrap-er.
  */
 angular.module('reportApp').factory('ReportService', ['GroupsService', 'plotterFactory', 'PlotService', 'reportFactory', 'UrlService', function(GroupsService, plotterFactory, PlotService, reportFactory, UrlService){
 	const rs = {};
@@ -39,19 +39,30 @@ angular.module('reportApp').factory('ReportService', ['GroupsService', 'plotterF
 	rs.defaultPlotters = [];
 	rs.plotterParameters = [];
 
+	// processed the report data received from the server,
+	// and bootstraps the state of various services
 	rs.processReport = (report) => {
 		console.log(report);
 
+		// useful info about the app
 		rs.isAnonymous = report.anonymous;
 		rs.isOwner = report.is_owner;
 		rs.status = report.status;
 		rs.number = report.number;
 		rs.user = report.user;
 
+		// start up our GroupsService
 		GroupsService.loadGroups(report.content.groups);
+		// if the report should not change,
+		// add a nice layer of immutability by freezing the Group tree
+		// (see GroupsService for more info)
 		const isEditable = rs.isOwner && rs.status === 'editable' && !rs.isAnonymous;
 		GroupsService.setEditable(isEditable);
 
+		console.log(GroupsService.groups);
+
+		// fetch all our plotter data
+		// these three fetches do not depend on eachother
 		const pPlotters = plotterFactory.getPlotters('')
 		.then(res => {
 			res.data.forEach(p => rs.plotters.push(p));
@@ -67,31 +78,37 @@ angular.module('reportApp').factory('ReportService', ['GroupsService', 'plotterF
 			res.data.forEach(p => rs.plotterParameters.push(p));
 		});
 
+		// process the fetched plot info
 		return Promise.all([pPlotters, pDefaults, pParams])
 		.then(() => PlotService.processQueue(rs.plotters, rs.defaultPlotters, rs.plotterParameters, rs.number))
+		;
 	};
 
+	// fetch the report data using either the by-name or by-number scheme,
+	// according to what URLService found
 	rs.fetchReport = () => {
 		const nameSeg = UrlService.getNameSegment();
 		const numSeg = UrlService.getNumberSegment();
 
 		if(nameSeg){
+			// the nameSeg is something like 'report/<user>/<report name>/'
 			let [user, reportId] = nameSeg.split('/').filter(s => s.length > 0).slice(1);
 
-			console.log(user);
-			console.log(reportId);
-
 			return reportFactory.getReportInformation(user, reportId, '')
 			.then(res => rs.processReport(res.data));
 		} else if(numSeg) {
+			// the numSeg is something like 'report/<report number>/'
 			let [number] = numSeg.split('/').filter(s => s.length > 0).slice(1);
 
 			return reportFactory.getReportInformationFromNumber(number, '')
 			.then(res => rs.processReport(res.data));
+		} else {
+			console.error('UrlService could not parse the current URL');
 		}
 	};
 
-	rs.fetchReport();
+	rs.fetchReport()
+	.catch(e => console.error(e));
 
 	console.log(rs);
 
diff --git a/beat/web/reports/templates/reports/report.html b/beat/web/reports/templates/reports/report.html
index ed18936f9..d27e338a1 100644
--- a/beat/web/reports/templates/reports/report.html
+++ b/beat/web/reports/templates/reports/report.html
@@ -77,6 +77,7 @@
 
     <!-- controllers -->
     <script src="{% fingerprint "reports/app/controllers/reportController.js" %}" type="text/javascript" charset="utf-8"></script>
+    <script src="{% fingerprint "reports/app/controllers/groupsController.js" %}" type="text/javascript" charset="utf-8"></script>
 
     <!-- factories -->
     <script src="{% fingerprint "reports/app/factories/reportFactory.js" %}" type="text/javascript" charset="utf-8"></script>
-- 
GitLab