From f37229c20299adb51ea41a306a4562082f57714b Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Fri, 14 Oct 2022 20:33:27 +0530 Subject: [PATCH 1/5] feat: statistics section --- lms/hooks.py | 2 +- .../new_signups/new_signups.json | 32 ++++++++++++++++ lms/public/css/style.css | 23 +++++------ lms/templates/statistics.html | 6 +-- lms/templates/stats.html | 16 ++++++++ lms/www/courses/course.html | 6 +++ lms/www/courses/index.html | 14 ++++++- lms/www/courses/index.js | 38 +++++++++++++++++++ 8 files changed, 120 insertions(+), 17 deletions(-) create mode 100644 lms/lms/dashboard_chart/new_signups/new_signups.json create mode 100644 lms/templates/stats.html create mode 100644 lms/www/courses/index.js diff --git a/lms/hooks.py b/lms/hooks.py index db6a33de..6d5b87f1 100644 --- a/lms/hooks.py +++ b/lms/hooks.py @@ -21,7 +21,7 @@ app_license = "AGPL" # include js, css files in header of web template web_include_css = "lms.bundle.css" # web_include_css = "/assets/lms/css/lms.css" -web_include_js = ["website.bundle.js", "controls.bundle.js"] +web_include_js = ["website.bundle.js"] # include custom scss in every website theme (without file extension ".scss") # website_theme_scss = "lms/public/scss/website" diff --git a/lms/lms/dashboard_chart/new_signups/new_signups.json b/lms/lms/dashboard_chart/new_signups/new_signups.json new file mode 100644 index 00000000..a72c7438 --- /dev/null +++ b/lms/lms/dashboard_chart/new_signups/new_signups.json @@ -0,0 +1,32 @@ +{ + "based_on": "creation", + "chart_name": "New Signups", + "chart_type": "Count", + "color": "#4463F0", + "creation": "2021-09-28 18:57:50.047656", + "docstatus": 0, + "doctype": "Dashboard Chart", + "document_type": "User", + "dynamic_filters_json": "[]", + "filters_json": "[]", + "group_by_type": "Count", + "idx": 1, + "is_public": 1, + "is_standard": 1, + "last_synced_on": "2022-10-14 15:57:47.583435", + "modified": "2022-10-14 17:20:21.880532", + "modified_by": "Administrator", + "module": "LMS", + "name": "New Signups", + "number_of_groups": 0, + "owner": "basawaraj@erpnext.com", + "roles": [], + "source": "", + "time_interval": "Daily", + "timeseries": 1, + "timespan": "Last Quarter", + "type": "Line", + "use_report_chart": 0, + "value_based_on": "", + "y_axis": [] +} \ No newline at end of file diff --git a/lms/public/css/style.css b/lms/public/css/style.css index 6a6846a5..166170a5 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -1713,25 +1713,20 @@ li { .stats-parent { display: grid; - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-gap: 2rem; } .stats-label { - color: var(--text-muted); - font-weight: bold; + color: var(--gray-900); + font-weight: 500; } .stats-value { color: var(--gray-900); - font-weight: 600; - font-size: 2rem; -} - -.stats-card { - display: flex; - flex-direction: column; - align-items: center; + font-weight: 500; + font-size: 1.5rem; + margin-top: 2rem; } .indicator-pill.green::before { @@ -1774,3 +1769,9 @@ li { .modal-header .modal-title { color: var(--gray-900); } + +.frappe-chart .title { + font-size: 1rem; + font-weight: bold; + color: var(--gray-900); +} diff --git a/lms/templates/statistics.html b/lms/templates/statistics.html index b8080650..252d3ac3 100644 --- a/lms/templates/statistics.html +++ b/lms/templates/statistics.html @@ -1,7 +1,7 @@
{% if published_courses %} -
+
{{ _("Published Courses") }}
@@ -12,7 +12,7 @@ {% endif %} {% if total_signups %} -
+
{{ _("Total Signups") }}
@@ -23,7 +23,7 @@ {% endif %} {% if enrollment_count %} -
+
{{ _("Enrollment Count") }}
diff --git a/lms/templates/stats.html b/lms/templates/stats.html new file mode 100644 index 00000000..e35591c1 --- /dev/null +++ b/lms/templates/stats.html @@ -0,0 +1,16 @@ +{% set published_courses = True %} +{% set total_signups = True %} +{% set enrollment_count = True %} + +
+ {% include "lms/templates/statistics.html" %} + +
+
+
+
+
+
+
+
+
diff --git a/lms/www/courses/course.html b/lms/www/courses/course.html index be5fac09..0cc4c4e1 100644 --- a/lms/www/courses/course.html +++ b/lms/www/courses/course.html @@ -423,3 +423,9 @@
{% endmacro %} + + +{%- block script %} + {{ super() }} + {{ include_script('controls.bundle.js') }} +{% endblock %} diff --git a/lms/www/courses/index.html b/lms/www/courses/index.html index 8ae83339..aeaf8392 100644 --- a/lms/www/courses/index.html +++ b/lms/www/courses/index.html @@ -42,7 +42,7 @@
-
+
{% set courses = live_courses %} {% set title = _("Live Courses") %} {% set classes = "live-courses" %} @@ -113,6 +119,10 @@
{% endif %} +
+ {% include "lms/templates/stats.html" %} +
+
{% endif %} diff --git a/lms/www/courses/index.js b/lms/www/courses/index.js new file mode 100644 index 00000000..5e7204df --- /dev/null +++ b/lms/www/courses/index.js @@ -0,0 +1,38 @@ + +frappe.ready(() => { + generate_graph("New Signups"); + generate_graph("Course Enrollments"); +}); + + +const generate_graph = (chart_name) => { + let date = frappe.datetime; + + frappe.call({ + method: "frappe.desk.doctype.dashboard_chart.dashboard_chart.get", + args: { + "chart_name": chart_name, + "timespan": "Select Date Range", + "from_date": date.add_days(date.get_today(), -30), + "to_date": date.get_today() + }, + 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: ['#2490ef'], + axisOptions: { + xIsSeries: 1, + }, + }); +}; From 13274c01d72d1f1f4d73db694caa3510542a87c5 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 17 Oct 2022 10:56:06 +0530 Subject: [PATCH 2/5] fix: chart color --- lms/www/courses/index.html | 12 ++++++++---- lms/www/courses/index.js | 8 +++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lms/www/courses/index.html b/lms/www/courses/index.html index aeaf8392..e4f7d693 100644 --- a/lms/www/courses/index.html +++ b/lms/www/courses/index.html @@ -42,7 +42,7 @@
-
+
{% set courses = live_courses %} {% set title = _("Live Courses") %} {% set classes = "live-courses" %} @@ -119,9 +121,11 @@
{% endif %} -
+ {% if frappe.session.user != "Guest" %} +
{% include "lms/templates/stats.html" %}
+ {% endif %}
diff --git a/lms/www/courses/index.js b/lms/www/courses/index.js index 5e7204df..d265d68b 100644 --- a/lms/www/courses/index.js +++ b/lms/www/courses/index.js @@ -1,7 +1,9 @@ frappe.ready(() => { - generate_graph("New Signups"); - generate_graph("Course Enrollments"); + if (frappe.session.user != "Guest") { + generate_graph("New Signups"); + generate_graph("Course Enrollments"); + } }); @@ -30,7 +32,7 @@ const render_chart = (data, chart_name) => { data: data, type: 'line', height: 250, - colors: ['#2490ef'], + colors: ['#4563f1'], axisOptions: { xIsSeries: 1, }, From 7d029c53051af1f1f424b13df299101d3adec206 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 17 Oct 2022 11:26:47 +0530 Subject: [PATCH 3/5] fix: stats grid width --- lms/public/css/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lms/public/css/style.css b/lms/public/css/style.css index 166170a5..c5a6a861 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -1713,7 +1713,7 @@ li { .stats-parent { display: grid; - grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); grid-gap: 2rem; } From 3c1449c89890020262e5fe36070281eb1be7b320 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 17 Oct 2022 19:47:11 +0530 Subject: [PATCH 4/5] fix: import chart lib from website bundle --- lms/public/js/common_functions.js | 9 ++------- lms/public/js/website.bundle.js | 1 + lms/templates/courses_created.html | 4 ++-- lms/www/batch/learn.html | 3 +-- lms/www/courses/course.html | 4 ++-- lms/www/courses/index.js | 2 +- 6 files changed, 9 insertions(+), 14 deletions(-) diff --git a/lms/public/js/common_functions.js b/lms/public/js/common_functions.js index 88fa7aec..c8815f85 100644 --- a/lms/public/js/common_functions.js +++ b/lms/public/js/common_functions.js @@ -1,6 +1,6 @@ frappe.ready(() => { - setup_vue_and_file_size(); + setup_file_size(); $(".join-batch").click((e) => { join_course(e); @@ -21,12 +21,7 @@ frappe.ready(() => { }); -const setup_vue_and_file_size = () => { - frappe.require("/assets/frappe/node_modules/vue/dist/vue.js", () => { - Vue.prototype.__ = window.__; - Vue.prototype.frappe = window.frappe; - }); - +const setup_file_size = () => { frappe.provide("frappe.form.formatters"); frappe.form.formatters.FileSize = file_size; }; diff --git a/lms/public/js/website.bundle.js b/lms/public/js/website.bundle.js index 628957f6..d32bbaa5 100644 --- a/lms/public/js/website.bundle.js +++ b/lms/public/js/website.bundle.js @@ -1,2 +1,3 @@ import "./profile.js" import "./common_functions.js" +import "../../../../frappe/frappe/public/js/frappe/ui/chart.js" diff --git a/lms/templates/courses_created.html b/lms/templates/courses_created.html index 1bcc0d4a..2711bc02 100644 --- a/lms/templates/courses_created.html +++ b/lms/templates/courses_created.html @@ -1,4 +1,4 @@ -{% set courses = get_authored_courses(user or None, only_published or False) %} +{% set courses = courses_created if courses_created else get_authored_courses(user or None, only_published or False) %} {% if courses | length %}
@@ -12,7 +12,7 @@
{{ _("No courses created") }}
-
{{ _("Help others learn something new.") }}
+
{{ _("Help others learn something new by creating a course.") }}
{% endif %} diff --git a/lms/www/batch/learn.html b/lms/www/batch/learn.html index 1dd123d3..c3249a85 100644 --- a/lms/www/batch/learn.html +++ b/lms/www/batch/learn.html @@ -255,8 +255,7 @@ "reference_doctype": "Course Lesson", "reference_docname": lesson.name }) %} - {% set is_instructor = frappe.session.user == course.instructor %} - {% set condition = is_instructor if is_instructor else membership %} + {% set condition = is_instructor(course.name) or membership %} {% set doctype, docname = _("Course Lesson"), lesson.name %} {% set title = "Questions" if topics_count else "" %} {% set cta_title = "Ask a Question" %} diff --git a/lms/www/courses/course.html b/lms/www/courses/course.html index 0cc4c4e1..1af64182 100644 --- a/lms/www/courses/course.html +++ b/lms/www/courses/course.html @@ -293,12 +293,12 @@ membership.current_lesson else "1.1" if first_lesson_exists(course.name) else None %} {% if show_start_learing_cta(course, membership) %} -
+
{{ _("Start Learning") }}
{% elif is_instructor(course.name) and not course.published and course.status != "Under Review" %} -
+
{{ _("Submit for Review") }}
diff --git a/lms/www/courses/index.js b/lms/www/courses/index.js index d265d68b..7fccbce9 100644 --- a/lms/www/courses/index.js +++ b/lms/www/courses/index.js @@ -26,7 +26,7 @@ const generate_graph = (chart_name) => { const render_chart = (data, chart_name) => { - let dom_element = chart_name == "Course Enrollments" ? "#course-enrollments" : "#new-signups" + let dom_element = chart_name == "Course Enrollments" ? "#course-enrollments" : "#new-signups"; const chart = new frappe.Chart(dom_element, { title: chart_name, data: data, From 4feab27c59842da814c06bc52ba1bc93fc16d5d2 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Tue, 18 Oct 2022 09:42:29 +0530 Subject: [PATCH 5/5] fix: show stats to guest users --- lms/lms/utils.py | 40 +++++++++++++++++++++++++++++++++++++- lms/www/courses/index.html | 4 ---- lms/www/courses/index.js | 9 ++++----- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/lms/lms/utils.py b/lms/lms/utils.py index baf6dbee..04939d1b 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -1,10 +1,13 @@ import re import frappe -from frappe.utils import flt, cint, cstr, getdate, add_months, fmt_money +from frappe.utils import flt, cint, cstr, getdate, add_months, fmt_money, get_datetime, format_date from lms.lms.md import markdown_to_html, find_macros import string from frappe import _ from frappe.desk.doctype.notification_log.notification_log import make_notification_logs +from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_result +from frappe.utils.dateutils import get_period + RE_SLUG_NOTALLOWED = re.compile("[^a-z0-9]+") @@ -546,3 +549,38 @@ def get_filtered_membership(course, memberships): def show_start_learing_cta(course, membership): return not course.disable_self_learning and not membership and not course.upcoming \ and not check_profile_restriction() and not is_instructor(course.name) and course.status == "Approved" + + +@frappe.whitelist(allow_guest=True) +def get_chart_data(chart_name, timespan, timegrain, from_date, to_date): + chart = frappe.get_doc("Dashboard Chart", chart_name) + filters = [([chart.document_type, "docstatus", "<", 2, False])] + doctype = chart.document_type + datefield = chart.based_on + value_field = chart.value_based_on or "1" + from_date = get_datetime(from_date).strftime("%Y-%m-%d") + to_date = get_datetime(to_date) + + filters.append([doctype, datefield, ">=", from_date, False]) + filters.append([doctype, datefield, "<=", to_date, False]) + + data = frappe.db.get_all( + doctype, + fields=[f"{datefield} as _unit", f"SUM({value_field})", "COUNT(*)"], + filters=filters, + group_by="_unit", + order_by="_unit asc", + as_list=True, + ) + + result = get_result(data, timegrain, from_date, to_date, chart.chart_type) + + return { + "labels": [ + format_date(get_period(r[0], timegrain), parse_day_first=True) + if timegrain in ("Daily", "Weekly") + else get_period(r[0], timegrain) + for r in result + ], + "datasets": [{"name": chart.name, "values": [r[1] for r in result]}], + } diff --git a/lms/www/courses/index.html b/lms/www/courses/index.html index e4f7d693..85a55751 100644 --- a/lms/www/courses/index.html +++ b/lms/www/courses/index.html @@ -77,13 +77,11 @@ {% endif %} - {% if frappe.session.user != "Guest" %} - {% endif %}
@@ -121,11 +119,9 @@
{% endif %} - {% if frappe.session.user != "Guest" %}
{% include "lms/templates/stats.html" %}
- {% endif %}
diff --git a/lms/www/courses/index.js b/lms/www/courses/index.js index 7fccbce9..415d6a5a 100644 --- a/lms/www/courses/index.js +++ b/lms/www/courses/index.js @@ -1,9 +1,7 @@ frappe.ready(() => { - if (frappe.session.user != "Guest") { - generate_graph("New Signups"); - generate_graph("Course Enrollments"); - } + generate_graph("New Signups"); + generate_graph("Course Enrollments"); }); @@ -11,10 +9,11 @@ const generate_graph = (chart_name) => { let date = frappe.datetime; frappe.call({ - method: "frappe.desk.doctype.dashboard_chart.dashboard_chart.get", + 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.get_today() },