From 7ebc619f369be2a91aaa8389de08bcaf8c66414f Mon Sep 17 00:00:00 2001
From: Jaden Diefenbaugh <blakcap@users.noreply.github.com>
Date: Mon, 3 Apr 2017 12:35:43 +0200
Subject: [PATCH] documentation on all edit directives

---
 .../app/directives/edit/addGroupMenu.js       |  6 ++++-
 .../app/directives/edit/addItemsMenu.js       | 24 +++++++++++++++----
 .../app/directives/edit/itemContainer.js      |  5 +++-
 .../reports/app/directives/edit/layout.js     |  8 ++++---
 .../app/directives/edit/panelContent.js       | 12 ++++++----
 .../app/directives/edit/panelExperiments.js   | 11 ++++++++-
 .../reports/app/directives/edit/panelItems.js |  6 ++++-
 .../reports/app/directives/edit/plotItem.js   |  4 +++-
 .../app/directives/edit/tableFieldSelector.js | 24 +++++++++++++++++++
 .../reports/app/directives/edit/tableItem.js  | 12 +++++++++-
 .../reports/app/directives/edit/textItem.js   | 18 ++++++++------
 11 files changed, 106 insertions(+), 24 deletions(-)

diff --git a/beat/web/reports/static/reports/app/directives/edit/addGroupMenu.js b/beat/web/reports/static/reports/app/directives/edit/addGroupMenu.js
index 40dcee254..dcefe7f83 100644
--- a/beat/web/reports/static/reports/app/directives/edit/addGroupMenu.js
+++ b/beat/web/reports/static/reports/app/directives/edit/addGroupMenu.js
@@ -23,7 +23,7 @@
 /*
  * groupAddGroupMenu
  * Desc:
- * 	represents the menu for creating groups
+ * 	the menu & validating for creating a new group
  */
 angular.module('reportApp')
 .directive("groupAddGroupMenu", ['GroupsService', function(GroupsService){
@@ -32,12 +32,16 @@ angular.module('reportApp')
 		},
 		link: function(scope){
 			scope.newGroupName = { val: '' };
+			// validates the user input
 			scope.hasError = (val) => {
 				// if val is undefined, empty, or a dup, its an err
 				const isErr = !val || val.length === 0 || GroupsService.groups.find(g => g.name === val);
 				// cast to boolean
 				return !!isErr;
 			};
+
+			// creates a new group if the new group name is valid
+			// wipes the input on successful creation
 			scope.createGroup = () => {
 				if(scope.hasError(scope.newGroupName.val)){
 					return;
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 dde9770fe..d4ee0c8a1 100644
--- a/beat/web/reports/static/reports/app/directives/edit/addItemsMenu.js
+++ b/beat/web/reports/static/reports/app/directives/edit/addItemsMenu.js
@@ -23,7 +23,7 @@
 /*
  * groupAddItemsMenu
  * Desc:
- * 	represents the menu for adding report items to a group
+ * 	the button group for adding report items (plot, table, text) to a group
  */
 angular.module('reportApp')
 .directive("groupAddItemsMenu", ['ExperimentsService', 'GroupsService', function(ExperimentsService, GroupsService){
@@ -32,17 +32,22 @@ angular.module('reportApp')
 			group: '='
 		},
 		link: function(scope){
+			// finds the id for the next report item of
+			// the given type
+			// by looking at the existing items
 			const getNextItemId = (type) => {
 				let count = Object.values(scope.group.reportItems)
 				.filter(v => v.id.includes(type))
 				.length
 				;
+
 				let nextId = `${type}_${count}`;
 				return nextId;
 			};
 
 			scope.plottables = ExperimentsService.plottables;
 
+			// helper func for adding a table
 			scope.addNewTable = () => {
 				const id = getNextItemId('table');
 
@@ -62,14 +67,22 @@ angular.module('reportApp')
 				const defaultFields = Array.from(defaultFieldsSet);
 				console.log(defaultFields);
 
-				scope.group.addReportItem(id, {
+				// tables have an arr of selected fields
+				// and a float precision
+				let content = {
 					fields: defaultFields,
 					precision: 10
-				});
+				};
+
+				scope.group.addReportItem(id, content);
 			};
 
+			// helper func for adding a plot
 			scope.addNewPlot = (plot) => {
 				let id = getNextItemId('plot');
+
+				// plots have a given name (by analyzer)
+				// and a plot type
 				let content = {
 					name: plot.label,
 					type: plot.type
@@ -78,9 +91,12 @@ angular.module('reportApp')
 				scope.group.addReportItem(id, content);
 			};
 
+			// helper func for adding a text block
 			scope.addNewText = () => {
 				let id = getNextItemId('text');
-				scope.group.addReportItem(id, '');
+				// text blocks just have raw RST
+				let content = '';
+				scope.group.addReportItem(id, content);
 			};
 		},
 		template: `
diff --git a/beat/web/reports/static/reports/app/directives/edit/itemContainer.js b/beat/web/reports/static/reports/app/directives/edit/itemContainer.js
index 3aed999c4..1361c99e7 100644
--- a/beat/web/reports/static/reports/app/directives/edit/itemContainer.js
+++ b/beat/web/reports/static/reports/app/directives/edit/itemContainer.js
@@ -23,7 +23,9 @@
 /*
  * groupItemContainer
  * Desc:
- * 	container for an item in the group
+ * 	container for an item in the group.
+ * 	depending of the type of the item (found in the item's id)
+ * 	it creates a table, plot, or text item
  */
 angular.module('reportApp')
 .directive("groupItemContainer", [function(){
@@ -34,6 +36,7 @@ angular.module('reportApp')
 		},
 		link: function(scope){
 			scope.item = scope.reportItem;
+			// report-wide-unique prefix for the item to use
 			scope.domId = `${scope.group.name}_${scope.id}`;
 		},
 		template: `
diff --git a/beat/web/reports/static/reports/app/directives/edit/layout.js b/beat/web/reports/static/reports/app/directives/edit/layout.js
index c7b99a60b..c2b40bfae 100644
--- a/beat/web/reports/static/reports/app/directives/edit/layout.js
+++ b/beat/web/reports/static/reports/app/directives/edit/layout.js
@@ -23,17 +23,19 @@
 /*
  * groupsLayout
  * Desc:
- * 	controls the layout of the reports content, generating group panels
- * 	using the GroupsService data.
+ * 	controls the layout of the reports content,
+ * 	generating group panels using the GroupsService data,
+ * 	and holding the menu for adding a group
  */
 angular.module('reportApp').directive("groupsLayout", ['GroupsService', function(GroupsService){
 	return {
-		// isolate scope for modularity & less coupling
 		scope: {
 		},
 		link: function(scope, el, attr){
 			scope.groups = GroupsService.groups;
 			scope.GroupsService = GroupsService;
+
+			// drag handle CSS selector
 			scope.sortableOptions = {
 				handle: '.panel-heading > .panel-title > .action-buttons > .drag-handle'
 			};
diff --git a/beat/web/reports/static/reports/app/directives/edit/panelContent.js b/beat/web/reports/static/reports/app/directives/edit/panelContent.js
index 9bced2aaf..bfb1fecc1 100644
--- a/beat/web/reports/static/reports/app/directives/edit/panelContent.js
+++ b/beat/web/reports/static/reports/app/directives/edit/panelContent.js
@@ -23,7 +23,11 @@
 /*
  * groupPanelContent
  * Desc:
- * 	lays out the content of a group in a panel
+ * 	presents the group to the user in logical blocks:
+ * 	- a panel holds content
+ * 	- panel header contains an (editable) group name label
+ * 	- panel header also contains the buttons to add report items
+ * 	- two sub-panels are added: the experiments list, and the items list
  */
 angular.module('reportApp').directive("groupPanelContent", ['GroupsService', function(GroupsService){
 	return {
@@ -33,7 +37,7 @@ angular.module('reportApp').directive("groupPanelContent", ['GroupsService', fun
 		link: function(scope){
 			scope.deleteGroup = GroupsService.deleteGroup;
 			scope.editingGroupName = false;
-			scope.change = () => {
+			scope.toggleEditingGroupName = () => {
 				scope.editingGroupName = !scope.editingGroupName;
 			};
 		},
@@ -49,7 +53,7 @@ angular.module('reportApp').directive("groupPanelContent", ['GroupsService', fun
 			aria-expanded="true"
 			aria-controls="collapse-{{group.name}}">
 		</a>
-		<span ng-if='!editingGroupName' ng-click='change()'>
+		<span ng-if='!editingGroupName' ng-click='toggleEditingGroupName()'>
 			<span>{{ group.name }}</span>
 			<span style='cursor: pointer;' class='glyphicon glyphicon-pencil'></span>
 		</span>
@@ -61,7 +65,7 @@ angular.module('reportApp').directive("groupPanelContent", ['GroupsService', fun
 					class='form-control'
 					placeholder='Group name...'
 					ng-model='group._name'/>
-				<span class='input-group-addon' ng-click='change()'>
+				<span class='input-group-addon' ng-click='toggleEditingGroupName()'>
 					Save
 				</span>
 			</span>
diff --git a/beat/web/reports/static/reports/app/directives/edit/panelExperiments.js b/beat/web/reports/static/reports/app/directives/edit/panelExperiments.js
index 6435a1bc9..8913dcbd2 100644
--- a/beat/web/reports/static/reports/app/directives/edit/panelExperiments.js
+++ b/beat/web/reports/static/reports/app/directives/edit/panelExperiments.js
@@ -23,7 +23,9 @@
 /*
  * groupPanelExperiments
  * Desc:
- * 	displays the experiments panel of the group
+ * 	displays the experiments panel of the group -
+ * 	a table of experiments in the group, their databases/protocols, and aliases.
+ * 	Also has a menu for adding (compatible) experiments to the group.
  */
 angular.module('reportApp').directive("groupPanelExperiments", ['GroupsService', 'ExperimentsService', 'UrlService', function(GroupsService, ExperimentsService, UrlService){
 	return {
@@ -33,6 +35,9 @@ angular.module('reportApp').directive("groupPanelExperiments", ['GroupsService',
 		link: function(scope){
 			scope.experiments = ExperimentsService.experiments;
 			scope.dropdownId = `${scope.group.name}_exp_add_dropdown`;
+
+			// find experiments that are not in the group but are
+			// compatible with the existing experiments (if any)
 			scope.expsNotInGroup = () => {
 				return ExperimentsService.experimentNames
 				// exps not in group
@@ -41,10 +46,14 @@ angular.module('reportApp').directive("groupPanelExperiments", ['GroupsService',
 				.filter(e => scope.group.analyzer === '' || ExperimentsService.getAnalyzerFromExpName(e) === scope.group.analyzer)
 				;
 			};
+
+			// collects an array of formatted databases & protocols of an experiment
+			// format is "<database name>@<protocol name>"
 			scope.getExpDatabases = (expName) => {
 				let dbs = scope.experiments[expName].declaration.datasets;
 				return Array.from(new Set(Object.values(dbs).map(db => `${db.database}@${db.protocol}`)));
 			};
+
 			scope.getAnalyzerFromExpName = ExperimentsService.getAnalyzerFromExpName;
 			scope.getExpUrl = UrlService.getExperimentUrl;
 			scope.getBlockUrl = UrlService.getBlockUrl;
diff --git a/beat/web/reports/static/reports/app/directives/edit/panelItems.js b/beat/web/reports/static/reports/app/directives/edit/panelItems.js
index 0f446ed82..0c73d4677 100644
--- a/beat/web/reports/static/reports/app/directives/edit/panelItems.js
+++ b/beat/web/reports/static/reports/app/directives/edit/panelItems.js
@@ -23,7 +23,8 @@
 /*
  * groupPanelItems
  * Desc:
- * 	displays the panel of report items of the group
+ * 	displays the panel of report items of the group,
+ * 	using the item container adaptor
  */
 angular.module('reportApp').directive("groupPanelItems", [function(){
 	return {
@@ -31,6 +32,9 @@ angular.module('reportApp').directive("groupPanelItems", [function(){
 			group: '='
 		},
 		link: function(scope){
+			// CSS selector for drag handles for the ui-sortable functionality
+			// TODO: this needs to be changed each time the HTML hierarchy changes.
+			// Make it hierarchy-independent
 			scope.sortableOptions = {
 				handle: '.panel-heading > .panel-title > .action-buttons > .drag-handle'
 			};
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 c6dd7818c..0c399886c 100644
--- a/beat/web/reports/static/reports/app/directives/edit/plotItem.js
+++ b/beat/web/reports/static/reports/app/directives/edit/plotItem.js
@@ -23,7 +23,7 @@
 /*
  * groupPlotItem
  * Desc:
- * 	displays a plot report item
+ * 	displays a plot report item (basically a container for the plots code to insert into)
  */
 angular.module('reportApp')
 .directive("groupPlotItem", ['ExperimentsService', 'PlotService', function(ExperimentsService, PlotService){
@@ -36,6 +36,8 @@ angular.module('reportApp')
 		link: function(scope){
 			const group = scope.group;
 			scope.domId = `${scope.group.name}_${scope.id}`;
+
+			// container for the plots applet to insert into
 			scope.renderDivId = `${scope.domId}-render`;
 
 			PlotService.addPlot(scope.group, scope.id, scope.renderDivId);
diff --git a/beat/web/reports/static/reports/app/directives/edit/tableFieldSelector.js b/beat/web/reports/static/reports/app/directives/edit/tableFieldSelector.js
index 74baebb82..f3ac84adc 100644
--- a/beat/web/reports/static/reports/app/directives/edit/tableFieldSelector.js
+++ b/beat/web/reports/static/reports/app/directives/edit/tableFieldSelector.js
@@ -31,9 +31,13 @@ angular.module('reportApp')
 		scope: {
 			id: '=',
 			group: '=',
+			// currently selected columns for the table
 			colsSelected: '=',
+			// function to execute when the user clicks the submit button
 			buttonAction: '&',
+			// title for the menu
 			title: '@',
+			// text  for the submit button
 			buttonText: '@'
 		},
 		link: function(scope){
@@ -46,34 +50,52 @@ angular.module('reportApp')
 			};
 
 			scope.tableables = () => {
+				// start with the tableables generated in experimentsservice
 				const tableables = ExperimentsService.tableables;
 				const fieldArr = Object.entries(tableables)
+				// only look at fields that are from an experiment in the group
 				.filter(([e, fields]) => scope.group.experiments.includes(e))
+				// get the names of the fields
 				.map(([e, fields]) => Object.keys(fields))
+				// make one big array of all field names
 				.reduce((arr, fArr) => [...arr, ...fArr], [])
 				;
 
+				// converting to and from a Set is a simple way of
+				// removing dups
 				return Array.from(new Set(fieldArr));
 			};
 
+			// has this fieldName already been processed?
+			// need to look at the already-processed field names
 			scope.isUniqueTableable = (expName, fieldName) => {
 				const tableables = ExperimentsService.tableables;
 				const concatNames = (eName, fName) => `${eName}.${fName}`;
 
+				// see if this field is a repeat
 				const isRepeat = Object.entries(tableables)
 				.filter(([e, fields]) => {
+					// only look at tableables of exps that are in group
 					let isInGroup = scope.group.experiments.includes(e);
+					// and have already been looked at
 					let alreadyChecked = Object.keys(tableables).indexOf(e) < Object.keys(tableables).indexOf(expName);
 					return isInGroup && alreadyChecked;
 				})
+				// get field names
 				.map(([e, fields]) => Object.keys(fields))
+				// flatten
 				.reduce((arr, fArr) => [...arr, ...fArr], [])
+				// does this flattened array have this field name in it?
 				.includes(fieldName)
 				;
 
+				// if it isnt a repeat, its unique!
 				return !isRepeat;
 			};
 
+			// many tableable fields are fields from an analyzer, a block, or something else
+			// these fields have a field group name, a '.', and an actual field name
+			// find these group names and use them to subdivide the list of fields in the menu
 			scope.tableablesGroups = () => {
 				let groupNames = scope.tableables()
 				.filter(f => f.includes('.'))
@@ -82,8 +104,10 @@ angular.module('reportApp')
 				return Array.from(new Set(groupNames)).sort((a, b) => groupNames.indexOf(a) - groupNames.indexOf(b));
 			};
 
+			// finds the actual field name whether its in a field group or not
 			scope.subfieldName = (field) => field.includes('.') ? field.split('.').slice(1).join('.') : field;
 
+			// toggle the selection of a field
 			scope.toggleField = (fName) => {
 				let idx = scope.colsSelected.indexOf(fName);
 				if(idx > -1){
diff --git a/beat/web/reports/static/reports/app/directives/edit/tableItem.js b/beat/web/reports/static/reports/app/directives/edit/tableItem.js
index 20b174006..9fba43f28 100644
--- a/beat/web/reports/static/reports/app/directives/edit/tableItem.js
+++ b/beat/web/reports/static/reports/app/directives/edit/tableItem.js
@@ -23,7 +23,8 @@
 /*
  * groupTableItem
  * Desc:
- * 	displays a table report item
+ * 	displays a table report item and lets the user
+ * 	manage this table's selected cols and float precision
  */
 angular.module('reportApp')
 .directive("groupTableItem", ['GroupsService', 'ExperimentsService', function(GroupsService, ExperimentsService){
@@ -41,12 +42,21 @@ angular.module('reportApp')
 			scope.colSelectorId = `${scope.domId}_columnSelector`;
 
 			// 1 - 10
+			// probably the most concise way of generating 1-10 computationally
+			// also vastly more complex than writing [1,2,3,4,5,6,7,9,10]
 			scope.floatingPointRange = [...(new Array(10)).keys()].map(i => i + 1);
 
 			// init the chosen cols for the table with the saved cols
 			scope.chosenCols = Array.from(scope.fields);
+
 			// save new cols choice
+			// due to how angular handles functions passed as props to an element,
+			// it must return a function that does the actual work.
 			scope.saveChosenCols = () => () => {
+				// we want to keep the selected columns in order,
+				// so try to add new columns in their correct indices,
+				// and rm cols by mutating the array
+
 				const newCols = scope.chosenCols
 				.filter(c => !scope.fields.includes(c));
 
diff --git a/beat/web/reports/static/reports/app/directives/edit/textItem.js b/beat/web/reports/static/reports/app/directives/edit/textItem.js
index 020fd50f2..c38e9aafd 100644
--- a/beat/web/reports/static/reports/app/directives/edit/textItem.js
+++ b/beat/web/reports/static/reports/app/directives/edit/textItem.js
@@ -23,7 +23,11 @@
 /*
  * groupTextItem
  * Desc:
- * 	displays a text report item
+ * 	displays a text report item:
+ * 	- sends the raw RST to the server to be compiled,
+ * 		and displays the returned HTML
+ * 	- the user can edit the RST using codemirror
+ * 	- the compile is async and doesnt require refreshing the page
  */
 angular.module('reportApp')
 .directive("groupTextItem", ['GroupsService', '$sce', 'UrlService', 'reportFactory', function(GroupsService, $sce, UrlService, reportFactory){
@@ -34,6 +38,7 @@ angular.module('reportApp')
 		},
 		link: function(scope){
 			// aliases
+			// angular requires that compiling raw html be sanitized
 			scope.trustAsHtml = $sce.trustAsHtml;
 			scope.item = scope.reportItem;
 			scope.domId = `${scope.group.name}_${scope.item.id}`;
@@ -43,13 +48,8 @@ angular.module('reportApp')
 				mode: 'rst',
 			};
 
-			// readonly codemirror options
-			scope.srccmOptions = {
-				mode: 'rst',
-				readOnly: true
-			};
-
 			// handle compiling content
+			// holds the last response from the server
 			scope.compiledContent = { val: '' };
 			scope.compileContent = () => {
 				let url = UrlService.getCompileRstUrl();
@@ -57,18 +57,22 @@ angular.module('reportApp')
 
 				return reportFactory.compileRST(url, content)
 				.then(data => {
+					// when compiled, save the raw html
 					scope.compiledContent.val = data.data.html_str;
 				});
 			};
 
 			// handle edit/save/cancel buttons
 			scope.isEditing = { val: false };
+			// when editing, use a buffer to hold the raw text
 			scope.unsavedContent = { val: `${scope.item.content}` };
+			// save the buffer to the actual report item content
 			scope.saveAction = () => {
 				scope.item.content = scope.unsavedContent.val;
 				scope.compileContent();
 				scope.isEditing.val = false;
 			};
+			// discard buffer and use report item content
 			scope.cancelAction = () => {
 				scope.unsavedContent.val = `${scope.item.content}`;
 				scope.isEditing.val = false;
-- 
GitLab