diff --git a/lms/hooks.py b/lms/hooks.py index 52e30375..8fb9cb6f 100644 --- a/lms/hooks.py +++ b/lms/hooks.py @@ -58,6 +58,7 @@ web_include_js = ["website.bundle.js"] # ------------ # before_install = "lms.install.before_install" +after_install = "lms.install.add_pages_to_nav" after_sync = "lms.install.after_sync" after_uninstall = "lms.install.after_uninstall" diff --git a/lms/install.py b/lms/install.py index 4adf68cc..03645ab9 100644 --- a/lms/install.py +++ b/lms/install.py @@ -2,6 +2,10 @@ import frappe from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to +def after_install(): + add_pages_to_nav() + + def after_sync(): create_lms_roles() set_default_home() @@ -91,3 +95,41 @@ def delete_custom_fields(): for field in fields: frappe.db.delete("Custom Field", {"fieldname": field}) frappe.db.commit() + + +def add_pages_to_nav(): + pages = [ + {"label": "Courses", "url": "/courses", "parent": "Explore", "idx": 2}, + {"label": "Statistics", "url": "/statistics", "parent": "Explore", "idx": 3}, + {"label": "Jobs", "url": "/jobs", "parent": "Explore", "idx": 4}, + {"label": "People", "url": "/community", "parent": "Explore", "idx": 5}, + ] + + if not frappe.db.exists("Top Bar Item", {"label": "Explore"}): + frappe.get_doc( + { + "doctype": "Top Bar Item", + "label": "Explore", + "parent": "Website Settings", + "parenttype": "Website Settings", + "parentfield": "top_bar_items", + "idx": 1, + } + ).save() + + for page in pages: + if not frappe.db.exists( + "Top Bar Item", {"url": ["like", "%" + page.get("url") + "%"]} + ): + frappe.get_doc( + { + "doctype": "Top Bar Item", + "label": page.get("label"), + "url": page.get("url"), + "parent_label": page.get("parent"), + "idx": page.get("idx"), + "parent": "Website Settings", + "parenttype": "Website Settings", + "parentfield": "top_bar_items", + } + ).save() diff --git a/lms/lms/dashboard_chart/lesson_completion/lesson_completion.json b/lms/lms/dashboard_chart/lesson_completion/lesson_completion.json new file mode 100644 index 00000000..f38ccc2a --- /dev/null +++ b/lms/lms/dashboard_chart/lesson_completion/lesson_completion.json @@ -0,0 +1,33 @@ +{ + "based_on": "creation", + "chart_name": "Lesson Completion", + "chart_type": "Count", + "color": "#4463F0", + "creation": "2022-11-09 16:52:19.021695", + "custom_options": "{\"type\": \"line\", \"axisOptions\": {\"xIsSeries\": 1}, \"lineOptions\": {\"regionFill\": 1}}", + "docstatus": 0, + "doctype": "Dashboard Chart", + "document_type": "LMS Course Progress", + "dynamic_filters_json": "[]", + "filters_json": "[]", + "group_by_type": "Count", + "idx": 0, + "is_public": 1, + "is_standard": 1, + "modified": "2022-11-09 16:52:52.241756", + "modified_by": "Administrator", + "module": "LMS", + "name": "Lesson Completion", + "number_of_groups": 0, + "owner": "Administrator", + "parent_document_type": "", + "roles": [], + "source": "", + "time_interval": "Daily", + "timeseries": 1, + "timespan": "Last Month", + "type": "Line", + "use_report_chart": 0, + "value_based_on": "", + "y_axis": [] +} \ No newline at end of file diff --git a/lms/lms/doctype/lms_batch_membership/lms_batch_membership.json b/lms/lms/doctype/lms_batch_membership/lms_batch_membership.json index 1efcf744..903f66ce 100644 --- a/lms/lms/doctype/lms_batch_membership/lms_batch_membership.json +++ b/lms/lms/doctype/lms_batch_membership/lms_batch_membership.json @@ -89,7 +89,7 @@ }, { "fieldname": "progress", - "fieldtype": "Data", + "fieldtype": "Float", "label": "Progress", "read_only": 1 }, @@ -116,7 +116,7 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2022-10-10 12:38:17.839525", + "modified": "2022-10-10 12:38:17.839526", "modified_by": "Administrator", "module": "LMS", "name": "LMS Batch Membership", @@ -141,4 +141,4 @@ "sort_order": "DESC", "states": [], "title_field": "member_name" -} \ No newline at end of file +} diff --git a/lms/lms/utils.py b/lms/lms/utils.py index f42d2b26..edb256b0 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -654,3 +654,19 @@ def get_chart_data(chart_name, timespan, timegrain, from_date, to_date): ], "datasets": [{"name": chart.name, "values": [r[1] for r in result]}], } + + +@frappe.whitelist(allow_guest=True) +def get_course_completion_data(): + all_membership = frappe.db.count("LMS Batch Membership") + completed = frappe.db.count("LMS Batch Membership", {"progress": ["like", "%100%"]}) + + return { + "labels": ["Completed", "In Progress"], + "datasets": [ + { + "name": "Course Completion", + "values": [completed, all_membership - completed], + } + ], + } diff --git a/lms/lms/workspace/lms/lms.json b/lms/lms/workspace/lms/lms.json index 3964ac72..02924879 100644 --- a/lms/lms/workspace/lms/lms.json +++ b/lms/lms/workspace/lms/lms.json @@ -143,7 +143,7 @@ "type": "Link" } ], - "modified": "2022-11-07 18:49:38.954136", + "modified": "2022-11-09 17:16:03.973258", "modified_by": "Administrator", "module": "LMS", "name": "LMS", @@ -169,7 +169,7 @@ "format": "{} Completed", "label": "Course Completed", "link_to": "LMS Batch Membership", - "stats_filter": "{\"progress\":[\"=\",\"100\"]}", + "stats_filter": "{\"progress\":[\"like\",\"%100%\"]}", "type": "DocType" }, { diff --git a/lms/patches.txt b/lms/patches.txt index 9438129d..012a7f4c 100644 --- a/lms/patches.txt +++ b/lms/patches.txt @@ -34,4 +34,6 @@ lms.patches.v0_0.create_course_instructor_role #29-08-2022 lms.patches.v0_0.create_course_moderator_role lms.patches.v0_0.set_dashboard #11-10-2022 lms.patches.v0_0.set_courses_page_as_home -lms.patches.v0_0.set_member_in_progress +lms.patches.v0_0.set_member_in_progress #09-11-2022 +lms.patches.v0_0.convert_progress_to_float +lms.patches.v0_0.add_pages_to_nav #11-11-2022 diff --git a/lms/patches/v0_0/add_pages_to_nav.py b/lms/patches/v0_0/add_pages_to_nav.py new file mode 100644 index 00000000..d883d755 --- /dev/null +++ b/lms/patches/v0_0/add_pages_to_nav.py @@ -0,0 +1,6 @@ +import frappe +from lms.install import add_pages_to_nav + + +def execute(): + add_pages_to_nav() diff --git a/lms/patches/v0_0/convert_progress_to_float.py b/lms/patches/v0_0/convert_progress_to_float.py new file mode 100644 index 00000000..28ba459a --- /dev/null +++ b/lms/patches/v0_0/convert_progress_to_float.py @@ -0,0 +1,11 @@ +import frappe +from frappe.utils import flt + + +def execute(): + frappe.reload_doc("lms", "doctype", "lms_course_progress") + progress_records = frappe.get_all("LMS Batch Membership", fields=["name", "progress"]) + for progress in progress_records: + frappe.db.set_value( + "LMS Batch Membership", progress.name, "progress", flt(progress.progress) + ) diff --git a/lms/patches/v0_0/set_member_in_progress.py b/lms/patches/v0_0/set_member_in_progress.py index e67f688a..7c9cff75 100644 --- a/lms/patches/v0_0/set_member_in_progress.py +++ b/lms/patches/v0_0/set_member_in_progress.py @@ -2,6 +2,7 @@ import frappe def execute(): + frappe.reload_doc("lms", "doctype", "lms_course_progress") progress_records = frappe.get_all("LMS Course Progress", fields=["name", "owner"]) for progress in progress_records: diff --git a/lms/public/css/style.css b/lms/public/css/style.css index a1be2240..65ef4106 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -1715,7 +1715,7 @@ li { grid-gap: 2rem; } -.tab-pane .stats-parent { +.statistics .stats-parent { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-gap: 1rem; } diff --git a/lms/public/js/common_functions.js b/lms/public/js/common_functions.js index a5e4bfe5..f60b4721 100644 --- a/lms/public/js/common_functions.js +++ b/lms/public/js/common_functions.js @@ -16,6 +16,13 @@ frappe.ready(() => { $(document).on("click", ".btn-save-chapter", (e) => { save_chapter(e); }); + + if (window.location.pathname == "/statistics") { + generate_graph("New Signups", "#new-signups"); + generate_graph("Course Enrollments", "#course-enrollments"); + generate_graph("Lesson Completion", "#lesson-completion"); + generate_course_completion_graph(); + } }); const setup_file_size = () => { @@ -155,3 +162,51 @@ const save_chapter = (e) => { }, }); }; + +const generate_graph = (chart_name, element, type = "line") => { + let date = frappe.datetime; + + frappe.call({ + method: "lms.lms.utils.get_chart_data", + args: { + chart_name: chart_name, + timespan: "Select Date Range", + timegrain: "Daily", + from_date: date.add_days(date.get_today(), -30), + to_date: date.add_days(date.get_today(), +1), + }, + callback: (data) => { + render_chart(data.message, chart_name, element, type); + }, + }); +}; + +const render_chart = (data, chart_name, element, type) => { + const chart = new frappe.Chart(element, { + title: chart_name, + data: data, + type: type, + height: 250, + colors: ["#4563f1"], + axisOptions: { + xIsSeries: 1, + }, + lineOptions: { + regionFill: 1, + }, + }); +}; + +const generate_course_completion_graph = () => { + frappe.call({ + method: "lms.lms.utils.get_course_completion_data", + callback: (data) => { + render_chart( + data.message, + "Course Completion", + "#course-completion", + "pie" + ); + }, + }); +}; diff --git a/lms/templates/statistics.html b/lms/templates/statistics.html index 94ea9c1c..347107c4 100644 --- a/lms/templates/statistics.html +++ b/lms/templates/statistics.html @@ -48,7 +48,7 @@ {% if course_completion %} {% set course_completion_count = frappe.db.count("LMS Batch Membership", { - "progress":["=","100"] + "progress":["like","%100%"] }) %}
diff --git a/lms/templates/stats.html b/lms/templates/stats.html deleted file mode 100644 index e0f25fd1..00000000 --- a/lms/templates/stats.html +++ /dev/null @@ -1,19 +0,0 @@ -{% set published_courses = True %} -{% set total_signups = True %} -{% set enrollment_count = True %} -{% set course_completion = True %} -{% set lesson_completion = True %} -{% set quiz_completion = True %} - -
- {% include "lms/templates/statistics.html" %} - -
-
-
-
-
-
-
-
-
diff --git a/lms/www/classes/__init__.py b/lms/www/classes/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lms/www/courses/index.html b/lms/www/courses/index.html index a69c62ff..4940c100 100644 --- a/lms/www/courses/index.html +++ b/lms/www/courses/index.html @@ -84,11 +84,6 @@ {% endif %} -
@@ -126,10 +121,6 @@
{% endif %} -
- {% include "lms/templates/stats.html" %} -
-
{% endif %} diff --git a/lms/www/courses/index.js b/lms/www/courses/index.js index 3c4e9c8a..f3bc44ec 100644 --- a/lms/www/courses/index.js +++ b/lms/www/courses/index.js @@ -1,7 +1,4 @@ frappe.ready(() => { - generate_graph("New Signups"); - generate_graph("Course Enrollments"); - $(".nav-link").click((e) => { change_hash(e); }); @@ -11,44 +8,6 @@ frappe.ready(() => { } }); -const generate_graph = (chart_name) => { - let date = frappe.datetime; - - frappe.call({ - method: "lms.lms.utils.get_chart_data", - args: { - chart_name: chart_name, - timespan: "Select Date Range", - timegrain: "Daily", - from_date: date.add_days(date.get_today(), -30), - to_date: date.add_days(date.get_today(), +1), - }, - callback: (data) => { - render_chart(data.message, chart_name); - }, - }); -}; - -const render_chart = (data, chart_name) => { - let dom_element = - chart_name == "Course Enrollments" - ? "#course-enrollments" - : "#new-signups"; - const chart = new frappe.Chart(dom_element, { - title: chart_name, - data: data, - type: "line", - height: 250, - colors: ["#4563f1"], - axisOptions: { - xIsSeries: 1, - }, - lineOptions: { - regionFill: 1, - }, - }); -}; - const change_hash = (e) => { window.location.hash = $(e.currentTarget).attr("href"); }; diff --git a/lms/www/statistics/__init__.py b/lms/www/statistics/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lms/www/statistics/index.html b/lms/www/statistics/index.html new file mode 100644 index 00000000..27881531 --- /dev/null +++ b/lms/www/statistics/index.html @@ -0,0 +1,46 @@ +{% extends "templates/base.html" %} + + +{% block title %} +{{ _("Statistics") }} +{% endblock %} + + +{% block content %} +
+
+
+ {{ _("Statistics") }} +
+ {% set published_courses = True %} + {% set total_signups = True %} + {% set enrollment_count = True %} + {% set course_completion = True %} + {% set lesson_completion = True %} + {% set quiz_completion = True %} + +
+ {% include "lms/templates/statistics.html" %} + +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+{% endblock %}