feat(Education): added form dashboards and refactored custom buttons for better linking (#22727)

* feat: add form dashboards to all forms in Education Module

* feat: Add Course to Programs button in Course DocType

* refactor: custom buttons in Education module forms

* feat: buttons to add topic, article, quiz to their respective parent doctypes

* feat: add charts to form dashboards

* fix: code cleanup
diff --git a/erpnext/education/doctype/academic_term/academic_term_dashboard.py b/erpnext/education/doctype/academic_term/academic_term_dashboard.py
new file mode 100644
index 0000000..871e0f3
--- /dev/null
+++ b/erpnext/education/doctype/academic_term/academic_term_dashboard.py
@@ -0,0 +1,25 @@
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+	return {
+		'fieldname': 'academic_term',
+		'transactions': [
+			{
+				'label': _('Student'),
+				'items': ['Student Applicant', 'Student Group', 'Student Log']
+			},
+			{
+				'label': _('Fee'),
+				'items': ['Fees', 'Fee Schedule', 'Fee Structure']
+			},
+			{
+				'label': _('Program'),
+				'items': ['Program Enrollment']
+			},
+			{
+				'label': _('Assessment'),
+				'items': ['Assessment Plan', 'Assessment Result']
+			}
+		]
+	}
\ No newline at end of file
diff --git a/erpnext/education/doctype/academic_year/academic_year.js b/erpnext/education/doctype/academic_year/academic_year.js
index 21caa63..0e86198 100644
--- a/erpnext/education/doctype/academic_year/academic_year.js
+++ b/erpnext/education/doctype/academic_year/academic_year.js
@@ -1,10 +1,2 @@
-frappe.ui.form.on("Academic Year", "refresh", function(frm) {
-	if(!frm.doc.__islocal) {
-		frm.add_custom_button(__("Student Group"), function() {
-			frappe.route_options = {
-				academic_year: frm.doc.name
-			}
-			frappe.set_route("List", "Student Group");
-		});
-	}
+frappe.ui.form.on("Academic Year", {
 });
\ No newline at end of file
diff --git a/erpnext/education/doctype/academic_year/academic_year_dashboard.py b/erpnext/education/doctype/academic_year/academic_year_dashboard.py
new file mode 100644
index 0000000..f27f7d1
--- /dev/null
+++ b/erpnext/education/doctype/academic_year/academic_year_dashboard.py
@@ -0,0 +1,25 @@
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+	return {
+		'fieldname': 'academic_year',
+		'transactions': [
+			{
+				'label': _('Student'),
+				'items': ['Student Admission', 'Student Applicant', 'Student Group', 'Student Log']
+			},
+			{
+				'label': _('Fee'),
+				'items': ['Fees', 'Fee Schedule', 'Fee Structure']
+			},
+			{
+				'label': _('Academic Term and Program'),
+				'items': ['Academic Term', 'Program Enrollment']
+			},
+			{
+				'label': _('Assessment'),
+				'items': ['Assessment Plan', 'Assessment Result']
+			}
+		]
+	}
\ No newline at end of file
diff --git a/erpnext/education/doctype/article/article.js b/erpnext/education/doctype/article/article.js
index 4c9c6f0..edfec26 100644
--- a/erpnext/education/doctype/article/article.js
+++ b/erpnext/education/doctype/article/article.js
@@ -3,6 +3,54 @@
 
 frappe.ui.form.on('Article', {
 	refresh: function(frm) {
+		if (!frm.doc.__islocal) {
+			frm.add_custom_button(__('Add to Topics'), function() {
+				frm.trigger('add_article_to_topics');
+			}, __('Action'));
+		}
+	},
 
+	add_article_to_topics: function(frm) {
+		get_topics_without_article(frm.doc.name).then(r => {
+			if (r.message.length) {
+				frappe.prompt([
+					{
+						fieldname: 'topics',
+						label: __('Topics'),
+						fieldtype: 'MultiSelectPills',
+						get_data: function() {
+							return r.message;
+						}
+					}
+				],
+				function(data) {
+					frappe.call({
+						method: 'erpnext.education.doctype.topic.topic.add_content_to_topics',
+						args: {
+							'content_type': 'Article',
+							'content': frm.doc.name,
+							'topics': data.topics,
+						},
+						callback: function(r) {
+							if (!r.exc) {
+								frm.reload_doc();
+							}
+						},
+						freeze: true,
+						freeze_message: __('...Adding Article to Topics')
+					});
+				}, __('Add Article to Topics'), __('Add'));
+			} else {
+				frappe.msgprint(__('This article is already added to the existing topics'));
+			}
+		});
 	}
 });
+
+let get_topics_without_article = function(article) {
+	return frappe.call({
+		type: 'GET',
+		method: 'erpnext.education.doctype.article.article.get_topics_without_article',
+		args: {'article': article}
+	});
+};
\ No newline at end of file
diff --git a/erpnext/education/doctype/article/article.py b/erpnext/education/doctype/article/article.py
index 7dc850b..8ba367d 100644
--- a/erpnext/education/doctype/article/article.py
+++ b/erpnext/education/doctype/article/article.py
@@ -7,9 +7,15 @@
 from frappe.model.document import Document
 
 class Article(Document):
-
-
 	def get_article(self):
 		pass
 
-
+@frappe.whitelist()
+def get_topics_without_article(article):
+	data = []
+	for entry in frappe.db.get_all('Topic'):
+		topic = frappe.get_doc('Topic', entry.name)
+		topic_contents = [tc.content for tc in topic.topic_content]
+		if not topic_contents or article not in topic_contents:
+			data.append(topic.name)
+	return data
\ No newline at end of file
diff --git a/erpnext/education/doctype/assessment_group/assessment_group_dashboard.py b/erpnext/education/doctype/assessment_group/assessment_group_dashboard.py
new file mode 100644
index 0000000..2649d4b
--- /dev/null
+++ b/erpnext/education/doctype/assessment_group/assessment_group_dashboard.py
@@ -0,0 +1,15 @@
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+	return {
+		'fieldname': 'assessment_group',
+		'transactions': [
+			{
+				'label': _('Assessment'),
+				'items': ['Assessment Plan', 'Assessment Result']
+			}
+		]
+	}
\ No newline at end of file
diff --git a/erpnext/education/doctype/assessment_plan/assessment_plan.js b/erpnext/education/doctype/assessment_plan/assessment_plan.js
index 0cb642b..c4c5614 100644
--- a/erpnext/education/doctype/assessment_plan/assessment_plan.js
+++ b/erpnext/education/doctype/assessment_plan/assessment_plan.js
@@ -2,9 +2,9 @@
 // For license information, please see license.txt
 
 
-frappe.ui.form.on("Assessment Plan", {
+frappe.ui.form.on('Assessment Plan', {
 	onload: function(frm) {
-		frm.set_query("assessment_group", function(doc, cdt, cdn) {
+		frm.set_query('assessment_group', function(doc, cdt, cdn) {
 			return{
 				filters: {
 					'is_group': 0
@@ -22,20 +22,20 @@
 
 	refresh: function(frm) {
 		if (frm.doc.docstatus == 1) {
-			frm.add_custom_button(__("Assessment Result"), function() {
+			frm.add_custom_button(__('Assessment Result Tool'), function() {
 				frappe.route_options = {
 					assessment_plan: frm.doc.name,
 					student_group: frm.doc.student_group
 				}
-				frappe.set_route("Form", "Assessment Result Tool");
-			});
+				frappe.set_route('Form', 'Assessment Result Tool');
+			}, __('Tools'));
 		}
 	},
 
 	course: function(frm) {
 		if (frm.doc.course && frm.doc.maximum_assessment_score) {
 			frappe.call({
-				method: "erpnext.education.api.get_assessment_criteria",
+				method: 'erpnext.education.api.get_assessment_criteria',
 				args: {
 					course: frm.doc.course
 				},
@@ -43,12 +43,12 @@
 					if (r.message) {
 						frm.doc.assessment_criteria = [];
 						$.each(r.message, function(i, d) {
-							var row = frappe.model.add_child(frm.doc, "Assessment Plan Criteria", "assessment_criteria");
+							var row = frappe.model.add_child(frm.doc, 'Assessment Plan Criteria', 'assessment_criteria');
 							row.assessment_criteria = d.assessment_criteria;
 							row.maximum_score = d.weightage / 100 * frm.doc.maximum_assessment_score;
 						});
 					}
-					refresh_field("assessment_criteria");
+					refresh_field('assessment_criteria');
 
 				}
 			});
@@ -56,6 +56,6 @@
 	},
 
 	maximum_assessment_score: function(frm) {
-		frm.trigger("course");
+		frm.trigger('course');
 	}
 });
\ No newline at end of file
diff --git a/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py b/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py
index c36dfb1..5e6c29d 100644
--- a/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py
+++ b/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py
@@ -6,12 +6,16 @@
 def get_data():
 	return {
 		'fieldname': 'assessment_plan',
-		'non_standard_fieldnames': {
-		},
 		'transactions': [
 			{
 				'label': _('Assessment'),
 				'items': ['Assessment Result']
 			}
+		],
+		'reports': [
+			{
+				'label': _('Report'),
+				'items': ['Assessment Plan Status']
+			}
 		]
 	}
\ No newline at end of file
diff --git a/erpnext/education/doctype/assessment_result/assessment_result.js b/erpnext/education/doctype/assessment_result/assessment_result.js
index 84865ca..12fdd91 100644
--- a/erpnext/education/doctype/assessment_result/assessment_result.js
+++ b/erpnext/education/doctype/assessment_result/assessment_result.js
@@ -1,7 +1,13 @@
 // Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
 // For license information, please see license.txt
 
-frappe.ui.form.on("Assessment Result", {
+frappe.ui.form.on('Assessment Result', {
+	refresh: function(frm) {
+		if (!frm.doc.__islocal) {
+			frm.trigger('setup_chart');
+		}
+	},
+
 	onload: function(frm) {
 		frm.set_query('assessment_plan', function(){
 			return {
@@ -15,7 +21,7 @@
 	assessment_plan: function(frm) {
 		if (frm.doc.assessment_plan) {
 			frappe.call({
-				method: "erpnext.education.api.get_assessment_details",
+				method: 'erpnext.education.api.get_assessment_details',
 				args: {
 					assessment_plan: frm.doc.assessment_plan
 				},
@@ -23,40 +29,75 @@
 					if (r.message) {
 						frm.doc.details = [];
 						$.each(r.message, function(i, d) {
-							var row = frappe.model.add_child(frm.doc, "Assessment Result Detail", "details");
+							var row = frappe.model.add_child(frm.doc, 'Assessment Result Detail', 'details');
 							row.assessment_criteria = d.assessment_criteria;
 							row.maximum_score = d.maximum_score;
 						});
 					}
-					refresh_field("details");
+					refresh_field('details');
 				}
 			});
 		}
+	},
+
+	setup_chart: function(frm) {
+		let labels = [];
+		let maximum_scores = [];
+		let scores = [];
+		$.each(frm.doc.details, function(_i, e) {
+			labels.push(e.assessment_criteria);
+			maximum_scores.push(e.maximum_score);
+			scores.push(e.score);
+		});
+
+		if (labels.length && maximum_scores.length && scores.length) {
+			frm.dashboard.chart_area.empty().removeClass('hidden');
+			new frappe.Chart('.form-graph', {
+				title: 'Assessment Results',
+				data: {
+					labels: labels,
+					datasets: [
+						{
+							name: 'Maximum Score',
+							chartType: 'bar',
+							values: maximum_scores,
+						},
+						{
+							name: 'Score Obtained',
+							chartType: 'bar',
+							values: scores,
+						}
+					]
+				},
+				colors: ['#4CA746', '#98D85B'],
+				type: 'bar'
+			});
+		}
 	}
 });
 
-frappe.ui.form.on("Assessment Result Detail", {
+frappe.ui.form.on('Assessment Result Detail', {
 	score: function(frm, cdt, cdn) {
 		var d  = locals[cdt][cdn];
 
 		if(!d.maximum_score || !frm.doc.grading_scale) {
-			d.score = "";
-			frappe.throw(__("Please fill in all the details to generate Assessment Result."));
+			d.score = '';
+			frappe.throw(__('Please fill in all the details to generate Assessment Result.'));
 		}
 
 		if (d.score > d.maximum_score) {
-			frappe.throw(__("Score cannot be greater than Maximum Score"));
+			frappe.throw(__('Score cannot be greater than Maximum Score'));
 		}
 		else {
 			frappe.call({
-				method: "erpnext.education.api.get_grade",
+				method: 'erpnext.education.api.get_grade',
 				args: {
 					grading_scale: frm.doc.grading_scale,
 					percentage: ((d.score/d.maximum_score) * 100)
 				},
 				callback: function(r) {
 					if (r.message) {
-						frappe.model.set_value(cdt, cdn, "grade", r.message);
+						frappe.model.set_value(cdt, cdn, 'grade', r.message);
 					}
 				}
 			});
diff --git a/erpnext/education/doctype/assessment_result/assessment_result_dashboard.py b/erpnext/education/doctype/assessment_result/assessment_result_dashboard.py
new file mode 100644
index 0000000..438379d
--- /dev/null
+++ b/erpnext/education/doctype/assessment_result/assessment_result_dashboard.py
@@ -0,0 +1,14 @@
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+	return {
+		'reports': [
+			{
+				'label': _('Reports'),
+				'items': ['Final Assessment Grades', 'Course wise Assessment Report']
+			}
+		]
+	}
\ No newline at end of file
diff --git a/erpnext/education/doctype/course/course.js b/erpnext/education/doctype/course/course.js
index 6932989..81e4a8c 100644
--- a/erpnext/education/doctype/course/course.js
+++ b/erpnext/education/doctype/course/course.js
@@ -1,41 +1,60 @@
-frappe.ui.form.on("Course", "refresh", function(frm) {
-	if(!cur_frm.doc.__islocal) {
-		frm.add_custom_button(__("Program"), function() {
-			frappe.route_options = {
-				"Program Course.course": frm.doc.name
-			}
-			frappe.set_route("List", "Program");
-		});
+frappe.ui.form.on('Course', {
+	refresh: function(frm) {
+		if (!cur_frm.doc.__islocal) {
+			frm.add_custom_button(__('Add to Programs'), function() {
+				frm.trigger('add_course_to_programs')
+			}, __('Action'));
+		}
 
-		frm.add_custom_button(__("Student Group"), function() {
-			frappe.route_options = {
-				course: frm.doc.name
+		frm.set_query('default_grading_scale', function(){
+			return {
+				filters: {
+					docstatus: 1
+				}
 			}
-			frappe.set_route("List", "Student Group");
 		});
+	},
 
-		frm.add_custom_button(__("Course Schedule"), function() {
-			frappe.route_options = {
-				course: frm.doc.name
+	add_course_to_programs: function(frm) {
+		get_programs_without_course(frm.doc.name).then(r => {
+			if (r.message.length) {
+				frappe.prompt([
+					{
+						fieldname: 'programs',
+						label: __('Programs'),
+						fieldtype: 'MultiSelectPills',
+						get_data: function() {
+							return r.message;
+						}
+					},
+					{
+						fieldtype: 'Check',
+						label: __('Is Mandatory'),
+						fieldname: 'mandatory',
+					}
+				],
+				function(data) {
+					frappe.call({
+						method: 'erpnext.education.doctype.course.course.add_course_to_programs',
+						args: {
+							'course': frm.doc.name,
+							'programs': data.programs,
+							'mandatory': data.mandatory
+						},
+						callback: function(r) {
+							if (!r.exc) {
+								frm.reload_doc();
+							}
+						},
+						freeze: true,
+						freeze_message: __('...Adding Course to Programs')
+					})
+				}, __('Add Course to Programs'), __('Add'));
+			} else {
+				frappe.msgprint(__('This course is already added to the existing programs'));
 			}
-			frappe.set_route("List", "Course Schedule");
-		});
-
-		frm.add_custom_button(__("Assessment Plan"), function() {
-			frappe.route_options = {
-				course: frm.doc.name
-			}
-			frappe.set_route("List", "Assessment Plan");
 		});
 	}
-
-	frm.set_query('default_grading_scale', function(){
-		return {
-			filters: {
-				docstatus: 1
-			}
-		}
-	});
 });
 
 frappe.ui.form.on('Course Topic', {
@@ -50,3 +69,11 @@
 		};
 	}
 });
+
+let get_programs_without_course = function(course) {
+	return frappe.call({
+		type: 'GET',
+		method: 'erpnext.education.doctype.course.course.get_programs_without_course',
+		args: {'course': course}
+	});
+}
\ No newline at end of file
diff --git a/erpnext/education/doctype/course/course.py b/erpnext/education/doctype/course/course.py
index 0747a22..06efa54 100644
--- a/erpnext/education/doctype/course/course.py
+++ b/erpnext/education/doctype/course/course.py
@@ -4,6 +4,7 @@
 
 from __future__ import unicode_literals
 import frappe
+import json
 from frappe.model.document import Document
 from frappe import _
 
@@ -17,12 +18,39 @@
 			for criteria in self.assessment_criteria:
 				total_weightage += criteria.weightage or 0
 			if total_weightage != 100:
-				frappe.throw(_("Total Weightage of all Assessment Criteria must be 100%"))
+				frappe.throw(_('Total Weightage of all Assessment Criteria must be 100%'))
 
 	def get_topics(self):
 		topic_data= []
 		for topic in self.topics:
-			topic_doc = frappe.get_doc("Topic", topic.topic)
+			topic_doc = frappe.get_doc('Topic', topic.topic)
 			if topic_doc.topic_content:
 				topic_data.append(topic_doc)
-		return topic_data
\ No newline at end of file
+		return topic_data
+
+
+@frappe.whitelist()
+def add_course_to_programs(course, programs, mandatory=False):
+	programs = json.loads(programs)
+	for entry in programs:
+		program = frappe.get_doc('Program', entry)
+		program.append('courses', {
+			'course': course,
+			'course_name': course,
+			'mandatory': mandatory
+		})
+		program.flags.ignore_mandatory = True
+		program.save()
+	frappe.db.commit()
+	frappe.msgprint(_('Course {0} has been added to all the selected programs successfully.').format(frappe.bold(course)),
+		title=_('Programs updated'), indicator='green')
+
+@frappe.whitelist()
+def get_programs_without_course(course):
+	data = []
+	for entry in frappe.db.get_all('Program'):
+		program = frappe.get_doc('Program', entry.name)
+		courses = [c.course for c in program.courses]
+		if not courses or course not in courses:
+			data.append(program.name)
+	return data
\ No newline at end of file
diff --git a/erpnext/education/doctype/course/course_dashboard.py b/erpnext/education/doctype/course/course_dashboard.py
index 752af29..8a570bd 100644
--- a/erpnext/education/doctype/course/course_dashboard.py
+++ b/erpnext/education/doctype/course/course_dashboard.py
@@ -6,12 +6,10 @@
 def get_data():
 	return {
 		'fieldname': 'course',
-		'non_standard_fieldnames': {
-		},
 		'transactions': [
 			{
-				'label': _('Course'),
-				'items': ['Course Enrollment', 'Course Schedule']
+				'label': _('Program and Course'),
+				'items': ['Program', 'Course Enrollment', 'Course Schedule']
 			},
 			{
 				'label': _('Student'),
@@ -19,7 +17,7 @@
 			},
 			{
 				'label': _('Assessment'),
-				'items': ['Assessment Plan']
+				'items': ['Assessment Plan', 'Assessment Result']
 			},
 		]
 	}
\ No newline at end of file
diff --git a/erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py b/erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py
new file mode 100644
index 0000000..b9dd457
--- /dev/null
+++ b/erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py
@@ -0,0 +1,15 @@
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+	return {
+		'fieldname': 'enrollment',
+		'transactions': [
+			{
+				'label': _('Activity'),
+				'items': ['Course Activity', 'Quiz Activity']
+			}
+		]
+	}
\ No newline at end of file
diff --git a/erpnext/education/doctype/course_schedule/course_schedule.js b/erpnext/education/doctype/course_schedule/course_schedule.js
index 692c2a8..4275f6e 100644
--- a/erpnext/education/doctype/course_schedule/course_schedule.js
+++ b/erpnext/education/doctype/course_schedule/course_schedule.js
@@ -4,13 +4,13 @@
 frappe.ui.form.on("Course Schedule", {
 	refresh: function(frm) {
 		if (!frm.doc.__islocal) {
-			frm.add_custom_button(__("Attendance"), function() {
+			frm.add_custom_button(__("Mark Attendance"), function() {
 				frappe.route_options = {
 					based_on: "Course Schedule",
 					course_schedule: frm.doc.name
 				}
 				frappe.set_route("Form", "Student Attendance Tool");
-			});
+			}).addClass("btn-primary");
 		}
 	}
 });
\ No newline at end of file
diff --git a/erpnext/education/doctype/course_schedule/course_schedule.json b/erpnext/education/doctype/course_schedule/course_schedule.json
index 7346cab..8c6746b 100644
--- a/erpnext/education/doctype/course_schedule/course_schedule.json
+++ b/erpnext/education/doctype/course_schedule/course_schedule.json
@@ -1,520 +1,520 @@
 {
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 1, 
- "allow_rename": 0, 
- "autoname": "naming_series:", 
- "beta": 0, 
- "creation": "2015-09-09 16:34:04.960369", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "Document", 
- "editable_grid": 0, 
- "engine": "InnoDB", 
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 1,
+ "allow_rename": 0,
+ "autoname": "naming_series:",
+ "beta": 0,
+ "creation": "2015-09-09 16:34:04.960369",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 0,
+ "engine": "InnoDB",
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "student_group", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 1, 
-   "in_list_view": 0, 
-   "in_standard_filter": 1, 
-   "label": "Student Group", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Student Group", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "student_group",
+   "fieldtype": "Link",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 1,
+   "in_list_view": 0,
+   "in_standard_filter": 1,
+   "label": "Student Group",
+   "length": 0,
+   "no_copy": 0,
+   "options": "Student Group",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 1,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "instructor", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 1, 
-   "label": "Instructor", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Instructor", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "instructor",
+   "fieldtype": "Link",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 1,
+   "label": "Instructor",
+   "length": 0,
+   "no_copy": 0,
+   "options": "Instructor",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 1,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_from": "instructor.Instructor_name", 
-   "fieldname": "instructor_name", 
-   "fieldtype": "Read Only", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 1, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Instructor Name", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fetch_from": "instructor.Instructor_name",
+   "fieldname": "instructor_name",
+   "fieldtype": "Read Only",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 1,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Instructor Name",
+   "length": 0,
+   "no_copy": 0,
+   "options": "",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 1,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_2", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "column_break_2",
+   "fieldtype": "Column Break",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "", 
-   "fieldname": "naming_series", 
-   "fieldtype": "Select", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Naming Series", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "EDU-CSH-.YYYY.-", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 1, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "default": "",
+   "fieldname": "naming_series",
+   "fieldtype": "Select",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Naming Series",
+   "length": 0,
+   "no_copy": 0,
+   "options": "EDU-CSH-.YYYY.-",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 1,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "course", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 1, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Course", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Course", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "course",
+   "fieldtype": "Link",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 1,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Course",
+   "length": 0,
+   "no_copy": 0,
+   "options": "Course",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 1,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "color", 
-   "fieldtype": "Color", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Color", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "color",
+   "fieldtype": "Color",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Color",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 1,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "section_break_6", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "section_break_6",
+   "fieldtype": "Section Break",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "Today", 
-   "fieldname": "schedule_date", 
-   "fieldtype": "Date", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Schedule Date", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "default": "Today",
+   "fieldname": "schedule_date",
+   "fieldtype": "Date",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Schedule Date",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "room", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Room", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Room", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "room",
+   "fieldtype": "Link",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Room",
+   "length": 0,
+   "no_copy": 0,
+   "options": "Room",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 1,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_9", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "column_break_9",
+   "fieldtype": "Column Break",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "from_time", 
-   "fieldtype": "Time", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "From Time", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "from_time",
+   "fieldtype": "Time",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 1,
+   "in_standard_filter": 0,
+   "label": "From Time",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 1,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "to_time", 
-   "fieldtype": "Time", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "To Time", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "to_time",
+   "fieldtype": "Time",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 1,
+   "in_standard_filter": 0,
+   "label": "To Time",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 1,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "title", 
-   "fieldtype": "Data", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Title", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "title",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Title",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
   }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "idx": 0, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 0, 
- "issingle": 0, 
- "istable": 0, 
- "max_attachments": 0, 
- "menu_index": 0, 
- "modified": "2018-08-21 14:44:51.827225", 
- "modified_by": "Administrator", 
- "module": "Education", 
- "name": "Course Schedule", 
- "name_case": "", 
- "owner": "Administrator", 
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "menu_index": 0,
+ "modified": "2018-08-21 14:44:51.827225",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Course Schedule",
+ "name_case": "",
+ "owner": "Administrator",
  "permissions": [
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Academics User", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "amend": 0,
+   "cancel": 0,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "if_owner": 0,
+   "import": 0,
+   "permlevel": 0,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Academics User",
+   "set_user_permissions": 0,
+   "share": 1,
+   "submit": 0,
    "write": 1
   }
- ], 
- "quick_entry": 0, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "restrict_to_domain": "Education", 
- "show_name_in_global_search": 0, 
- "sort_field": "schedule_date", 
- "sort_order": "DESC", 
- "title_field": "title", 
- "track_changes": 0, 
- "track_seen": 0, 
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "restrict_to_domain": "Education",
+ "show_name_in_global_search": 0,
+ "sort_field": "schedule_date",
+ "sort_order": "DESC",
+ "title_field": "title",
+ "track_changes": 0,
+ "track_seen": 0,
  "track_views": 0
 }
\ No newline at end of file
diff --git a/erpnext/education/doctype/course_schedule/course_schedule_dashboard.py b/erpnext/education/doctype/course_schedule/course_schedule_dashboard.py
new file mode 100644
index 0000000..0866cd6
--- /dev/null
+++ b/erpnext/education/doctype/course_schedule/course_schedule_dashboard.py
@@ -0,0 +1,15 @@
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+	return {
+		'fieldname': 'course_schedule',
+		'transactions': [
+			{
+				'label': _('Attendance'),
+				'items': ['Student Attendance']
+			}
+		]
+	}
\ No newline at end of file
diff --git a/erpnext/education/doctype/fee_schedule/fee_schedule.js b/erpnext/education/doctype/fee_schedule/fee_schedule.js
index 1338331..75dd446 100644
--- a/erpnext/education/doctype/fee_schedule/fee_schedule.js
+++ b/erpnext/education/doctype/fee_schedule/fee_schedule.js
@@ -3,13 +3,13 @@
 
 frappe.ui.form.on('Fee Schedule', {
 	setup: function(frm) {
-		frm.add_fetch("fee_structure", "receivable_account", "receivable_account");
-		frm.add_fetch("fee_structure", "income_account", "income_account");
-		frm.add_fetch("fee_structure", "cost_center", "cost_center");
+		frm.add_fetch('fee_structure', 'receivable_account', 'receivable_account');
+		frm.add_fetch('fee_structure', 'income_account', 'income_account');
+		frm.add_fetch('fee_structure', 'cost_center', 'cost_center');
 	},
 
 	onload: function(frm) {
-		frm.set_query("receivable_account", function(doc) {
+		frm.set_query('receivable_account', function(doc) {
 			return {
 				filters: {
 					'account_type': 'Receivable',
@@ -18,7 +18,8 @@
 				}
 			};
 		});
-		frm.set_query("income_account", function(doc) {
+
+		frm.set_query('income_account', function(doc) {
 			return {
 				filters: {
 					'account_type': 'Income Account',
@@ -27,57 +28,59 @@
 				}
 			};
 		});
-		frm.set_query("student_group", "student_groups", function() {
+
+		frm.set_query('student_group', 'student_groups', function() {
 			return {
-				"program": frm.doc.program,
-				"academic_term": frm.doc.academic_term,
-				"academic_year": frm.doc.academic_year,
-				"disabled": 0
+				'program': frm.doc.program,
+				'academic_term': frm.doc.academic_term,
+				'academic_year': frm.doc.academic_year,
+				'disabled': 0
 			};
 		});
-		frappe.realtime.on("fee_schedule_progress", function(data) {
+
+		frappe.realtime.on('fee_schedule_progress', function(data) {
 			if (data.reload && data.reload === 1) {
 				frm.reload_doc();
 			}
 			if (data.progress) {
-				let progress_bar = $(cur_frm.dashboard.progress_area).find(".progress-bar");
+				let progress_bar = $(cur_frm.dashboard.progress_area).find('.progress-bar');
 				if (progress_bar) {
-					$(progress_bar).removeClass("progress-bar-danger").addClass("progress-bar-success progress-bar-striped");
-					$(progress_bar).css("width", data.progress+"%");
+					$(progress_bar).removeClass('progress-bar-danger').addClass('progress-bar-success progress-bar-striped');
+					$(progress_bar).css('width', data.progress+'%');
 				}
 			}
 		});
 	},
 
 	refresh: function(frm) {
-		if(!frm.doc.__islocal && frm.doc.__onload && frm.doc.__onload.dashboard_info &&
-			frm.doc.fee_creation_status=="Successful") {
+		if (!frm.doc.__islocal && frm.doc.__onload && frm.doc.__onload.dashboard_info &&
+			frm.doc.fee_creation_status === 'Successful') {
 			var info = frm.doc.__onload.dashboard_info;
 			frm.dashboard.add_indicator(__('Total Collected: {0}', [format_currency(info.total_paid,
 				info.currency)]), 'blue');
 			frm.dashboard.add_indicator(__('Total Outstanding: {0}', [format_currency(info.total_unpaid,
 				info.currency)]), info.total_unpaid ? 'orange' : 'green');
 		}
-		if (frm.doc.fee_creation_status=="In Process") {
-			frm.dashboard.add_progress("Fee Creation Status", "0");
+		if (frm.doc.fee_creation_status === 'In Process') {
+			frm.dashboard.add_progress('Fee Creation Status', '0');
 		}
-		if (frm.doc.docstatus==1 && !frm.doc.fee_creation_status || frm.doc.fee_creation_status == "Failed") {
+		if (frm.doc.docstatus === 1 && !frm.doc.fee_creation_status || frm.doc.fee_creation_status === 'Failed') {
 			frm.add_custom_button(__('Create Fees'), function() {
 				frappe.call({
-					method: "create_fees",
+					method: 'create_fees',
 					doc: frm.doc,
 					callback: function() {
 						frm.refresh();
 					}
 				});
-			}, "fa fa-play", "btn-success");
+			}).addClass('btn-primary');;
 		}
-		if (frm.doc.fee_creation_status == "Successful") {
-			frm.add_custom_button(__("View Fees Records"), function() {
+		if (frm.doc.fee_creation_status === 'Successful') {
+			frm.add_custom_button(__('View Fees Records'), function() {
 				frappe.route_options = {
 					fee_schedule: frm.doc.name
 				};
-				frappe.set_route("List", "Fees");
+				frappe.set_route('List', 'Fees');
 			});
 		}
 
@@ -86,35 +89,35 @@
 	fee_structure: function(frm) {
 		if (frm.doc.fee_structure) {
 			frappe.call({
-				method: "erpnext.education.doctype.fee_schedule.fee_schedule.get_fee_structure",
+				method: 'erpnext.education.doctype.fee_schedule.fee_schedule.get_fee_structure',
 				args: {
-					"target_doc": frm.doc.name,
-					"source_name": frm.doc.fee_structure
+					'target_doc': frm.doc.name,
+					'source_name': frm.doc.fee_structure
 				},
 				callback: function(r) {
 					var doc = frappe.model.sync(r.message);
-					frappe.set_route("Form", doc[0].doctype, doc[0].name);
+					frappe.set_route('Form', doc[0].doctype, doc[0].name);
 				}
 			});
 		}
 	}
 });
 
-frappe.ui.form.on("Fee Schedule Student Group", {
+frappe.ui.form.on('Fee Schedule Student Group', {
 	student_group: function(frm, cdt, cdn) {
 		var row = locals[cdt][cdn];
 		if (row.student_group && frm.doc.academic_year) {
 			frappe.call({
-				method: "erpnext.education.doctype.fee_schedule.fee_schedule.get_total_students",
+				method: 'erpnext.education.doctype.fee_schedule.fee_schedule.get_total_students',
 				args: {
-					"student_group": row.student_group,
-					"academic_year": frm.doc.academic_year,
-					"academic_term": frm.doc.academic_term,
-					"student_category": frm.doc.student_category
+					'student_group': row.student_group,
+					'academic_year': frm.doc.academic_year,
+					'academic_term': frm.doc.academic_term,
+					'student_category': frm.doc.student_category
 				},
 				callback: function(r) {
-					if(!r.exc) {
-						frappe.model.set_value(cdt, cdn, "total_students", r.message);
+					if (!r.exc) {
+						frappe.model.set_value(cdt, cdn, 'total_students', r.message);
 					}
 				}
 			});
diff --git a/erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py b/erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py
new file mode 100644
index 0000000..acfe400
--- /dev/null
+++ b/erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py
@@ -0,0 +1,13 @@
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+from __future__ import unicode_literals
+
+def get_data():
+	return {
+		'fieldname': 'fee_schedule',
+		'transactions': [
+			{
+				'items': ['Fees']
+			}
+		]
+	}
\ No newline at end of file
diff --git a/erpnext/education/doctype/fee_structure/fee_structure.js b/erpnext/education/doctype/fee_structure/fee_structure.js
index f09d2ef..b331c6d 100644
--- a/erpnext/education/doctype/fee_structure/fee_structure.js
+++ b/erpnext/education/doctype/fee_structure/fee_structure.js
@@ -3,21 +3,21 @@
 
 frappe.ui.form.on('Fee Structure', {
 	setup: function(frm) {
-		frm.add_fetch("company", "default_receivable_account", "receivable_account");
-		frm.add_fetch("company", "default_income_account", "income_account");
-		frm.add_fetch("company", "cost_center", "cost_center");
+		frm.add_fetch('company', 'default_receivable_account', 'receivable_account');
+		frm.add_fetch('company', 'default_income_account', 'income_account');
+		frm.add_fetch('company', 'cost_center', 'cost_center');
 	},
 
 	onload: function(frm) {
-		frm.set_query("academic_term", function() {
+		frm.set_query('academic_term', function() {
 			return {
-				"filters": {
-					"academic_year": frm.doc.academic_year
+				'filters': {
+					'academic_year': frm.doc.academic_year
 				}
 			};
 		});
 
-		frm.set_query("receivable_account", function(doc) {
+		frm.set_query('receivable_account', function(doc) {
 			return {
 				filters: {
 					'account_type': 'Receivable',
@@ -26,7 +26,7 @@
 				}
 			};
 		});
-		frm.set_query("income_account", function(doc) {
+		frm.set_query('income_account', function(doc) {
 			return {
 				filters: {
 					'account_type': 'Income Account',
@@ -38,27 +38,27 @@
 	},
 
 	refresh: function(frm) {
-		if(frm.doc.docstatus === 1) {
+		if (frm.doc.docstatus === 1) {
 			frm.add_custom_button(__('Create Fee Schedule'), function() {
 				frm.events.make_fee_schedule(frm);
-			});
+			}).addClass('btn-primary');
 		}
 	},
 
 	make_fee_schedule: function(frm) {
 		frappe.model.open_mapped_doc({
-			method: "erpnext.education.doctype.fee_structure.fee_structure.make_fee_schedule",
+			method: 'erpnext.education.doctype.fee_structure.fee_structure.make_fee_schedule',
 			frm: frm
 		});
 	}
 });
 
-frappe.ui.form.on("Fee Component", {
+frappe.ui.form.on('Fee Component', {
 	amount: function(frm) {
 		var total_amount = 0;
-		for(var i=0;i<frm.doc.components.length;i++) {
+		for (var i=0;i<frm.doc.components.length;i++) {
 			total_amount += frm.doc.components[i].amount;
 		}
-		frm.set_value("total_amount", total_amount);
+		frm.set_value('total_amount', total_amount);
 	}
 });
\ No newline at end of file
diff --git a/erpnext/education/doctype/fee_structure/fee_structure_dashboard.py b/erpnext/education/doctype/fee_structure/fee_structure_dashboard.py
new file mode 100644
index 0000000..73e314f
--- /dev/null
+++ b/erpnext/education/doctype/fee_structure/fee_structure_dashboard.py
@@ -0,0 +1,15 @@
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+	return {
+		'fieldname': 'fee_structure',
+		'transactions': [
+			{
+                'label': _('Fee'),
+				'items': ['Fees', 'Fee Schedule']
+			}
+		]
+	}
\ No newline at end of file
diff --git a/erpnext/education/doctype/grading_scale/grading_scale_dashboard.py b/erpnext/education/doctype/grading_scale/grading_scale_dashboard.py
new file mode 100644
index 0000000..2a3f13b
--- /dev/null
+++ b/erpnext/education/doctype/grading_scale/grading_scale_dashboard.py
@@ -0,0 +1,20 @@
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+	return {
+		'fieldname': 'grading_scale',
+		'non_standard_fieldnames': {
+			'Course': 'default_grading_scale'
+		},
+		'transactions': [
+			{
+				'label': _('Course'),
+				'items': ['Course']
+			},
+			{
+				'label': _('Assessment'),
+				'items': ['Assessment Plan', 'Assessment Result']
+			}
+		]
+	}
diff --git a/erpnext/education/doctype/instructor/instructor.js b/erpnext/education/doctype/instructor/instructor.js
index 69bd2cf..abb47ed 100644
--- a/erpnext/education/doctype/instructor/instructor.js
+++ b/erpnext/education/doctype/instructor/instructor.js
@@ -3,8 +3,8 @@
 
 frappe.ui.form.on("Instructor", {
 	employee: function(frm) {
-		if(!frm.doc.employee) return;
-		frappe.db.get_value('Employee', {name: frm.doc.employee}, 'company', (d) => {
+		if (!frm.doc.employee) return;
+		frappe.db.get_value("Employee", {name: frm.doc.employee}, "company", (d) => {
 			frm.set_query("department", function() {
 				return {
 					"filters": {
@@ -22,30 +22,16 @@
 		});
 	},
 	refresh: function(frm) {
-		if(!frm.doc.__islocal) {
-			frm.add_custom_button(__("Student Group"), function() {
-				frappe.route_options = {
-					instructor: frm.doc.name
-				}
-				frappe.set_route("List", "Student Group");
-			});
-			frm.add_custom_button(__("Course Schedule"), function() {
-				frappe.route_options = {
-					instructor: frm.doc.name
-				}
-				frappe.set_route("List", "Course Schedule");
-			});
+		if (!frm.doc.__islocal) {
 			frm.add_custom_button(__("As Examiner"), function() {
-				frappe.route_options = {
+				frappe.new_doc("Assessment Plan", {
 					examiner: frm.doc.name
-				}
-				frappe.set_route("List", "Assessment Plan");
+				});
 			}, __("Assessment Plan"));
 			frm.add_custom_button(__("As Supervisor"), function() {
-				frappe.route_options = {
+				frappe.new_doc("Assessment Plan", {
 					supervisor: frm.doc.name
-				}
-				frappe.set_route("List", "Assessment Plan");
+				});
 			}, __("Assessment Plan"));
 		}
 		frm.set_query("employee", function(doc) {
diff --git a/erpnext/education/doctype/instructor/instructor.py b/erpnext/education/doctype/instructor/instructor.py
index 28df2fc..b1bfcbb 100644
--- a/erpnext/education/doctype/instructor/instructor.py
+++ b/erpnext/education/doctype/instructor/instructor.py
@@ -30,4 +30,14 @@
 		if self.employee and frappe.db.get_value("Instructor", {'employee': self.employee, 'name': ['!=', self.name]}, 'name'):
 			frappe.throw(_("Employee ID is linked with another instructor"))
 
-
+def get_timeline_data(doctype, name):
+	"""Return timeline for course schedule"""
+	return dict(frappe.db.sql(
+		"""
+			SELECT unix_timestamp(`schedule_date`), count(*)
+			FROM `tabCourse Schedule`
+			WHERE
+				instructor=%s and
+				`schedule_date` > date_sub(curdate(), interval 1 year)
+			GROUP BY schedule_date
+		""", name))
diff --git a/erpnext/education/doctype/instructor/instructor_dashboard.py b/erpnext/education/doctype/instructor/instructor_dashboard.py
new file mode 100644
index 0000000..a404fc5
--- /dev/null
+++ b/erpnext/education/doctype/instructor/instructor_dashboard.py
@@ -0,0 +1,24 @@
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+	return {
+		'heatmap': True,
+		'heatmap_message': _('This is based on the course schedules of this Instructor'),
+		'fieldname': 'instructor',
+		'non_standard_fieldnames': {
+			'Assessment Plan': 'supervisor'
+		},
+		'transactions': [
+			{
+				'label': _('Course and Assessment'),
+				'items': ['Course Schedule', 'Assessment Plan']
+			},
+			{
+				'label': _('Students'),
+				'items': ['Student Group']
+			}
+		]
+	}
\ No newline at end of file
diff --git a/erpnext/education/doctype/program/program_dashboard.py b/erpnext/education/doctype/program/program_dashboard.py
index cb8f742..c5d2494 100644
--- a/erpnext/education/doctype/program/program_dashboard.py
+++ b/erpnext/education/doctype/program/program_dashboard.py
@@ -10,11 +10,15 @@
 			},
 			{
 				'label': _('Student Activity'),
-				'items': ['Student Group' ]
+				'items': ['Student Group', 'Student Log']
 			},
 			{
 				'label': _('Fee'),
-				'items': ['Fees','Fee Structure']
+				'items': ['Fees','Fee Structure', 'Fee Schedule']
+			},
+			{
+				'label': _('Assessment'),
+				'items': ['Assessment Plan', 'Assessment Result']
 			}
 		]
 	}
\ No newline at end of file
diff --git a/erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py b/erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py
new file mode 100644
index 0000000..18d307c
--- /dev/null
+++ b/erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py
@@ -0,0 +1,19 @@
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+	return {
+		'fieldname': 'program_enrollment',
+		'transactions': [
+			{
+				'label': _('Course and Fee'),
+				'items': ['Course Enrollment', 'Fees']
+			}
+		],
+		'reports': [
+			{
+				'label': _('Report'),
+				'items': ['Student and Guardian Contact Details']
+			}
+		]
+	}
\ No newline at end of file
diff --git a/erpnext/education/doctype/quiz/quiz.js b/erpnext/education/doctype/quiz/quiz.js
index 7b87088..01bcf73 100644
--- a/erpnext/education/doctype/quiz/quiz.js
+++ b/erpnext/education/doctype/quiz/quiz.js
@@ -3,11 +3,17 @@
 
 frappe.ui.form.on('Quiz', {
 	refresh: function(frm) {
-
+		if (!frm.doc.__islocal) {
+			frm.add_custom_button(__('Add to Topics'), function() {
+				frm.trigger('add_quiz_to_topics');
+			}, __('Action'));
+		}
 	},
+
 	validate: function(frm){
 		frm.events.check_duplicate_question(frm.doc.question);
 	},
+
 	check_duplicate_question: function(questions_data){
 		var questions = [];
 		questions_data.forEach(function(q){
@@ -15,7 +21,51 @@
 		});
 		var questions_set = new Set(questions);
 		if (questions.length != questions_set.size) {
-			frappe.throw(__("The question cannot be duplicate"));
+			frappe.throw(__('The question cannot be duplicate'));
 		}
+	},
+
+	add_quiz_to_topics: function(frm) {
+		get_topics_without_quiz(frm.doc.name).then(r => {
+			if (r.message.length) {
+				frappe.prompt([
+					{
+						fieldname: 'topics',
+						label: __('Topics'),
+						fieldtype: 'MultiSelectPills',
+						get_data: function() {
+							return r.message;
+						}
+					}
+				],
+				function(data) {
+					frappe.call({
+						method: 'erpnext.education.doctype.topic.topic.add_content_to_topics',
+						args: {
+							'content_type': 'Quiz',
+							'content': frm.doc.name,
+							'topics': data.topics,
+						},
+						callback: function(r) {
+							if (!r.exc) {
+								frm.reload_doc();
+							}
+						},
+						freeze: true,
+						freeze_message: __('...Adding Quiz to Topics')
+					});
+				}, __('Add Quiz to Topics'), __('Add'));
+			} else {
+				frappe.msgprint(__('This quiz is already added to the existing topics'));
+			}
+		});
 	}
-});
\ No newline at end of file
+});
+
+let get_topics_without_quiz = function(quiz) {
+	return frappe.call({
+		type: 'GET',
+		method: 'erpnext.education.doctype.quiz.quiz.get_topics_without_quiz',
+		args: {'quiz': quiz}
+	});
+};
\ No newline at end of file
diff --git a/erpnext/education/doctype/quiz/quiz.py b/erpnext/education/doctype/quiz/quiz.py
index ae1cb6c..a774b88 100644
--- a/erpnext/education/doctype/quiz/quiz.py
+++ b/erpnext/education/doctype/quiz/quiz.py
@@ -4,6 +4,7 @@
 
 from __future__ import unicode_literals
 import frappe
+import json
 from frappe import _
 from frappe.model.document import Document
 
@@ -59,3 +60,12 @@
 	except TypeError:
 		frappe.throw(_("Compare List function takes on list arguments"))
 
+@frappe.whitelist()
+def get_topics_without_quiz(quiz):
+	data = []
+	for entry in frappe.db.get_all('Topic'):
+		topic = frappe.get_doc('Topic', entry.name)
+		topic_contents = [tc.content for tc in topic.topic_content]
+		if not topic_contents or quiz not in topic_contents:
+			data.append(topic.name)
+	return data
\ No newline at end of file
diff --git a/erpnext/education/doctype/room/room.js b/erpnext/education/doctype/room/room.js
index 032db98..20cee6b 100644
--- a/erpnext/education/doctype/room/room.js
+++ b/erpnext/education/doctype/room/room.js
@@ -1,10 +1,2 @@
-frappe.ui.form.on("Room", "refresh", function(frm) {
-	if(!cur_frm.doc.__islocal) {
-		frm.add_custom_button(__("Course Schedule"), function() {
-			frappe.route_options = {
-				room: frm.doc.name
-			}
-			frappe.set_route("List", "Course Schedule");
-		});
-	}
+frappe.ui.form.on("Room", {
 });
\ No newline at end of file
diff --git a/erpnext/education/doctype/room/room_dashboard.py b/erpnext/education/doctype/room/room_dashboard.py
new file mode 100644
index 0000000..99aac33
--- /dev/null
+++ b/erpnext/education/doctype/room/room_dashboard.py
@@ -0,0 +1,19 @@
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+	return {
+		'fieldname': 'room',
+		'transactions': [
+			{
+				'label': _('Course'),
+				'items': ['Course Schedule']
+			},
+			{
+				'label': _('Assessment'),
+				'items': ['Assessment Plan']
+			}
+		]
+	}
\ No newline at end of file
diff --git a/erpnext/education/doctype/student_attendance/student_attendance_dashboard.py b/erpnext/education/doctype/student_attendance/student_attendance_dashboard.py
new file mode 100644
index 0000000..9c41b8f
--- /dev/null
+++ b/erpnext/education/doctype/student_attendance/student_attendance_dashboard.py
@@ -0,0 +1,12 @@
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+	return {
+		'reports': [
+			{
+				'label': _('Reports'),
+				'items': ['Student Monthly Attendance Sheet', 'Student Batch-Wise Attendance']
+			}
+		]
+	}
\ No newline at end of file
diff --git a/erpnext/education/doctype/student_category/student_category_dashboard.py b/erpnext/education/doctype/student_category/student_category_dashboard.py
new file mode 100644
index 0000000..f31c34b
--- /dev/null
+++ b/erpnext/education/doctype/student_category/student_category_dashboard.py
@@ -0,0 +1,13 @@
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+	return {
+		'fieldname': 'student_category',
+		'transactions': [
+			{
+				'label': _('Fee'),
+				'items': ['Fee Structure', 'Fee Schedule', 'Fees']
+			}
+		]
+	}
diff --git a/erpnext/education/doctype/student_group/student_group.js b/erpnext/education/doctype/student_group/student_group.js
index 1372440..51e3b74 100644
--- a/erpnext/education/doctype/student_group/student_group.js
+++ b/erpnext/education/doctype/student_group/student_group.js
@@ -1,18 +1,18 @@
-cur_frm.add_fetch("student", "title", "student_name");
+cur_frm.add_fetch('student', 'title', 'student_name');
 
-frappe.ui.form.on("Student Group", {
+frappe.ui.form.on('Student Group', {
 	onload: function(frm) {
-		frm.set_query("academic_term", function() {
+		frm.set_query('academic_term', function() {
 			return {
-				"filters": {
-					"academic_year": (frm.doc.academic_year)
+				filters: {
+					'academic_year': (frm.doc.academic_year)
 				}
 			};
 		});
 		if (!frm.__islocal) {
-			frm.set_query("student", "students", function() {
+			frm.set_query('student', 'students', function() {
 				return{
-					query: "erpnext.education.doctype.student_group.student_group.fetch_students",
+					query: 'erpnext.education.doctype.student_group.student_group.fetch_students',
 					filters: {
 						'academic_year': frm.doc.academic_year,
 						'group_based_on': frm.doc.group_based_on,
@@ -30,87 +30,86 @@
 
 	refresh: function(frm) {
 		if (!frm.doc.__islocal) {
-			frm.add_custom_button(__("Attendance"), function() {
-				frappe.route_options = {
-					based_on: "Student Group",
-					student_group: frm.doc.name
-				}
-				frappe.set_route("List", "Student Attendance Tool");
-			});
-			frm.add_custom_button(__("Course Schedule"), function() {
-				frappe.route_options = {
-					student_group: frm.doc.name
-				}
-				frappe.set_route("List", "Course Schedule");
-			});
-			frm.add_custom_button(__("Assessment Plan"), function() {
-				frappe.route_options = {
-					student_group: frm.doc.name
-				}
-				frappe.set_route("List", "Assessment Plan");
-			});
-			frm.add_custom_button(__("Update Email Group"), function() {
+
+			frm.add_custom_button(__('Add Guardians to Email Group'), function() {
 				frappe.call({
-					method: "erpnext.education.api.update_email_group",
+					method: 'erpnext.education.api.update_email_group',
 					args: {
-						"doctype": "Student Group",
-						"name": frm.doc.name
+						'doctype': 'Student Group',
+						'name': frm.doc.name
 					}
 				});
-			});
-			frm.add_custom_button(__("Newsletter"), function() {
+			}, __('Actions'));
+
+			frm.add_custom_button(__('Student Attendance Tool'), function() {
 				frappe.route_options = {
-					"Newsletter Email Group.email_group": frm.doc.name
+					based_on: 'Student Group',
+					student_group: frm.doc.name
 				}
-				frappe.set_route("List", "Newsletter");
-			});
+				frappe.set_route('Form', 'Student Attendance Tool', 'Student Attendance Tool');
+			}, __('Tools'));
+
+			frm.add_custom_button(__('Course Scheduling Tool'), function() {
+				frappe.route_options = {
+					student_group: frm.doc.name
+				}
+				frappe.set_route('Form', 'Course Scheduling Tool', 'Course Scheduling Tool');
+			}, __('Tools'));
+
+			frm.add_custom_button(__('Newsletter'), function() {
+				frappe.route_options = {
+					'Newsletter Email Group.email_group': frm.doc.name
+				}
+				frappe.set_route('List', 'Newsletter');
+			}, __('View'));
+
 		}
 	},
-	
+
 	group_based_on: function(frm) {
-		if (frm.doc.group_based_on == "Batch") {
+		if (frm.doc.group_based_on == 'Batch') {
 			frm.doc.course = null;
 			frm.set_df_property('program', 'reqd', 1);
 			frm.set_df_property('course', 'reqd', 0);
 		}
-		else if (frm.doc.group_based_on == "Course") {
+		else if (frm.doc.group_based_on == 'Course') {
 			frm.set_df_property('program', 'reqd', 0);
 			frm.set_df_property('course', 'reqd', 1);
 		}
-		else if (frm.doc.group_based_on == "Activity") {
+		else if (frm.doc.group_based_on == 'Activity') {
 			frm.set_df_property('program', 'reqd', 0);
 			frm.set_df_property('course', 'reqd', 0);
 		}
 	},
 
 	get_students: function(frm) {
-		if (frm.doc.group_based_on == "Batch" || frm.doc.group_based_on == "Course") {
+		if (frm.doc.group_based_on == 'Batch' || frm.doc.group_based_on == 'Course') {
 			var student_list = [];
 			var max_roll_no = 0;
-			$.each(frm.doc.students, function(i,d) {
+			$.each(frm.doc.students, function(_i,d) {
 				student_list.push(d.student);
 				if (d.group_roll_number>max_roll_no) {
 					max_roll_no = d.group_roll_number;
 				}
 			});
 
-			if(frm.doc.academic_year) {
+			if (frm.doc.academic_year) {
 				frappe.call({
-					method: "erpnext.education.doctype.student_group.student_group.get_students",
+					method: 'erpnext.education.doctype.student_group.student_group.get_students',
 					args: {
-						"academic_year": frm.doc.academic_year,
-						"academic_term": frm.doc.academic_term,
-						"group_based_on": frm.doc.group_based_on,
-						"program": frm.doc.program,
-						"batch" : frm.doc.batch,
-						"student_category" : frm.doc.student_category,
-						"course": frm.doc.course
+						'academic_year': frm.doc.academic_year,
+						'academic_term': frm.doc.academic_term,
+						'group_based_on': frm.doc.group_based_on,
+						'program': frm.doc.program,
+						'batch' : frm.doc.batch,
+						'student_category' : frm.doc.student_category,
+						'course': frm.doc.course
 					},
 					callback: function(r) {
-						if(r.message) {
+						if (r.message) {
 							$.each(r.message, function(i, d) {
 								if(!in_list(student_list, d.student)) {
-									var s = frm.add_child("students");
+									var s = frm.add_child('students');
 									s.student = d.student;
 									s.student_name = d.student_name;
 									if (d.active === 0) {
@@ -119,16 +118,16 @@
 									s.group_roll_number = ++max_roll_no;
 								}
 							});
-							refresh_field("students");
+							refresh_field('students');
 							frm.save();
 						} else {
-							frappe.msgprint(__("Student Group is already updated."))
+							frappe.msgprint(__('Student Group is already updated.'))
 						}
 					}
 				})
 			}
 		} else {
-			frappe.msgprint(__("Select students manually for the Activity based Group"));
+			frappe.msgprint(__('Select students manually for the Activity based Group'));
 		}
 	}
 });
diff --git a/erpnext/education/doctype/student_group/student_group_dashboard.py b/erpnext/education/doctype/student_group/student_group_dashboard.py
new file mode 100644
index 0000000..ad7a6de
--- /dev/null
+++ b/erpnext/education/doctype/student_group/student_group_dashboard.py
@@ -0,0 +1,19 @@
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+	return {
+		'fieldname': 'student_group',
+		'transactions': [
+			{
+				'label': _('Assessment'),
+				'items': ['Assessment Plan', 'Assessment Result']
+			},
+			{
+				'label': _('Course'),
+				'items': ['Course Schedule']
+			}
+		]
+	}
\ No newline at end of file
diff --git a/erpnext/education/doctype/topic/topic.js b/erpnext/education/doctype/topic/topic.js
index 695c174..2002b0c 100644
--- a/erpnext/education/doctype/topic/topic.js
+++ b/erpnext/education/doctype/topic/topic.js
@@ -3,6 +3,53 @@
 
 frappe.ui.form.on('Topic', {
 	refresh: function(frm) {
+		if (!cur_frm.doc.__islocal) {
+			frm.add_custom_button(__('Add to Courses'), function() {
+				frm.trigger('add_topic_to_courses');
+			}, __('Action'));
+		}
+	},
 
+	add_topic_to_courses: function(frm) {
+		get_courses_without_topic(frm.doc.name).then(r => {
+			if (r.message.length) {
+				frappe.prompt([
+					{
+						fieldname: 'courses',
+						label: __('Courses'),
+						fieldtype: 'MultiSelectPills',
+						get_data: function() {
+							return r.message;
+						}
+					}
+				],
+				function(data) {
+					frappe.call({
+						method: 'erpnext.education.doctype.topic.topic.add_topic_to_courses',
+						args: {
+							'topic': frm.doc.name,
+							'courses': data.courses
+						},
+						callback: function(r) {
+							if (!r.exc) {
+								frm.reload_doc();
+							}
+						},
+						freeze: true,
+						freeze_message: __('...Adding Topic to Courses')
+					});
+				}, __('Add Topic to Courses'), __('Add'));
+			} else {
+				frappe.msgprint(__('This topic is already added to the existing courses'));
+			}
+		});
 	}
 });
+
+let get_courses_without_topic = function(topic) {
+	return frappe.call({
+		type: 'GET',
+		method: 'erpnext.education.doctype.topic.topic.get_courses_without_topic',
+		args: {'topic': topic}
+	});
+};
\ No newline at end of file
diff --git a/erpnext/education/doctype/topic/topic.py b/erpnext/education/doctype/topic/topic.py
index 7e5da32..a5253e9 100644
--- a/erpnext/education/doctype/topic/topic.py
+++ b/erpnext/education/doctype/topic/topic.py
@@ -4,6 +4,8 @@
 
 from __future__ import unicode_literals
 import frappe
+import json
+from frappe import _
 from frappe.model.document import Document
 
 class Topic(Document):
@@ -14,4 +16,44 @@
 		except Exception as e:
 			frappe.log_error(frappe.get_traceback())
 			return None
-		return content_data
\ No newline at end of file
+		return content_data
+
+@frappe.whitelist()
+def get_courses_without_topic(topic):
+	data = []
+	for entry in frappe.db.get_all('Course'):
+		course = frappe.get_doc('Course', entry.name)
+		topics = [t.topic for t in course.topics]
+		if not topics or topic not in topics:
+			data.append(course.name)
+	return data
+
+@frappe.whitelist()
+def add_topic_to_courses(topic, courses, mandatory=False):
+	courses = json.loads(courses)
+	for entry in courses:
+		course = frappe.get_doc('Course', entry)
+		course.append('topics', {
+			'topic': topic,
+			'topic_name': topic
+		})
+		course.flags.ignore_mandatory = True
+		course.save()
+	frappe.db.commit()
+	frappe.msgprint(_('Topic {0} has been added to all the selected courses successfully.').format(frappe.bold(topic)),
+		title=_('Courses updated'), indicator='green')
+
+@frappe.whitelist()
+def add_content_to_topics(content_type, content, topics):
+	topics = json.loads(topics)
+	for entry in topics:
+		topic = frappe.get_doc('Topic', entry)
+		topic.append('topic_content', {
+			'content_type': content_type,
+			'content': content,
+		})
+		topic.flags.ignore_mandatory = True
+		topic.save()
+	frappe.db.commit()
+	frappe.msgprint(_('{0} {1} has been added to all the selected topics successfully.').format(content_type, frappe.bold(content)),
+		title=_('Topics updated'), indicator='green')
\ No newline at end of file