Skip to content

Commit

Permalink
feat: allow to embed superset dashboard in instructor dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
Ian2012 committed Feb 20, 2024
1 parent 1e08a12 commit 811eb58
Show file tree
Hide file tree
Showing 20 changed files with 613 additions and 30 deletions.
4 changes: 4 additions & 0 deletions aspects/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
"""
One-line description for README and other doc files.
"""
import os
from pathlib import Path

__version__ = '0.1.0'

ROOT_DIRECTORY = Path(os.path.dirname(os.path.abspath(__file__)))
21 changes: 21 additions & 0 deletions aspects/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,24 @@ class AspectsConfig(AppConfig):
"""

name = 'aspects'

plugin_app = {
"settings_config": {
"lms.djangoapp": {
"common": {"relative_path": "settings.common"},
"test": {"relative_path": "settings.test"},
"production": {"relative_path": "settings.production"},
},
"cms.djangoapp": {
"common": {"relative_path": "settings.common"},
"test": {"relative_path": "settings.test"},
"production": {"relative_path": "settings.production"},
},
},
}

def ready(self):
"""Load modules of Aspects."""
from aspects.extensions import ( # pylint: disable=unused-import, import-outside-toplevel
filters,
)
Empty file added aspects/extensions/__init__.py
Empty file.
70 changes: 70 additions & 0 deletions aspects/extensions/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"""
Open edX Filters needed for Aspects integration.
"""
import pkg_resources
from django.conf import settings
from django.template import Context, Template
from openedx_filters import PipelineStep
from web_fragments.fragment import Fragment

from aspects.utils import update_context

TEMPLATE_ABSOLUTE_PATH = "/instructor_dashboard/"
BLOCK_CATEGORY = "superset"


class AddSupersetTab(PipelineStep):
"""Add superset tab to instructor dashboard."""

def run_filter(
self, context, template_name
): # pylint: disable=arguments-differ, unused-argument
"""Execute filter that modifies the instructor dashboard context.
Args:
context (dict): the context for the instructor dashboard.
_ (str): instructor dashboard template name.
"""
course = context["course"]

Check warning on line 27 in aspects/extensions/filters.py

View check run for this annotation

Codecov / codecov/patch

aspects/extensions/filters.py#L27

Added line #L27 was not covered by tests

instructor_dashboard_config = getattr(

Check warning on line 29 in aspects/extensions/filters.py

View check run for this annotation

Codecov / codecov/patch

aspects/extensions/filters.py#L29

Added line #L29 was not covered by tests
settings, "SUPERSET_INSTRUCTOR_DASHBOARD", {}
)
dashboard_uuid = instructor_dashboard_config.get("dashboard_uuid")

Check warning on line 32 in aspects/extensions/filters.py

View check run for this annotation

Codecov / codecov/patch

aspects/extensions/filters.py#L32

Added line #L32 was not covered by tests

extra_filters_format = getattr(settings, "SUPERSET_EXTRA_FILTERS_FORMAT", [])

Check warning on line 34 in aspects/extensions/filters.py

View check run for this annotation

Codecov / codecov/patch

aspects/extensions/filters.py#L34

Added line #L34 was not covered by tests

default_filters = [

Check warning on line 36 in aspects/extensions/filters.py

View check run for this annotation

Codecov / codecov/patch

aspects/extensions/filters.py#L36

Added line #L36 was not covered by tests
"org = '{course.org}'",
"course_name = '{course.display_name}'",
"course_run = '{course.id.run}'",
]

filters = default_filters + extra_filters_format

Check warning on line 42 in aspects/extensions/filters.py

View check run for this annotation

Codecov / codecov/patch

aspects/extensions/filters.py#L42

Added line #L42 was not covered by tests

context = update_context(

Check warning on line 44 in aspects/extensions/filters.py

View check run for this annotation

Codecov / codecov/patch

aspects/extensions/filters.py#L44

Added line #L44 was not covered by tests
context, dashboard_uuid=dashboard_uuid, filters=filters
)
template = Template(self.resource_string("static/html/superset.html"))

Check warning on line 47 in aspects/extensions/filters.py

View check run for this annotation

Codecov / codecov/patch

aspects/extensions/filters.py#L47

Added line #L47 was not covered by tests

html = template.render(Context(context))
frag = Fragment(html)

Check warning on line 50 in aspects/extensions/filters.py

View check run for this annotation

Codecov / codecov/patch

aspects/extensions/filters.py#L49-L50

Added lines #L49 - L50 were not covered by tests

frag.add_css(self.resource_string("static/css/superset.css"))
frag.add_javascript(self.resource_string("static/js/embed_dashboard.js"))

Check warning on line 53 in aspects/extensions/filters.py

View check run for this annotation

Codecov / codecov/patch

aspects/extensions/filters.py#L52-L53

Added lines #L52 - L53 were not covered by tests

section_data = {

Check warning on line 55 in aspects/extensions/filters.py

View check run for this annotation

Codecov / codecov/patch

aspects/extensions/filters.py#L55

Added line #L55 was not covered by tests
"fragment": frag,
"section_key": BLOCK_CATEGORY,
"section_display_name": "Aspects",
"course_id": str(course.id),
"template_path_prefix": TEMPLATE_ABSOLUTE_PATH,
}
context["sections"].append(section_data)
return {

Check warning on line 63 in aspects/extensions/filters.py

View check run for this annotation

Codecov / codecov/patch

aspects/extensions/filters.py#L62-L63

Added lines #L62 - L63 were not covered by tests
"context": context,
}

def resource_string(self, path):
"""Handy helper for getting resources from our kit."""
data = pkg_resources.resource_string("aspects", path)
return data.decode("utf8")

Check warning on line 70 in aspects/extensions/filters.py

View check run for this annotation

Codecov / codecov/patch

aspects/extensions/filters.py#L69-L70

Added lines #L69 - L70 were not covered by tests
Empty file added aspects/settings/__init__.py
Empty file.
49 changes: 49 additions & 0 deletions aspects/settings/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""
Common Django settings for eox_hooks project.
For more information on this file, see
https://docs.djangoproject.com/en/2.22/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.22/ref/settings/
"""
from aspects import ROOT_DIRECTORY

Check warning on line 8 in aspects/settings/common.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/common.py#L8

Added line #L8 was not covered by tests

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.22/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "secret-key"

Check warning on line 14 in aspects/settings/common.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/common.py#L14

Added line #L14 was not covered by tests


# Application definition

INSTALLED_APPS = [

Check warning on line 19 in aspects/settings/common.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/common.py#L19

Added line #L19 was not covered by tests
"aspects",
]


# Internationalization
# https://docs.djangoproject.com/en/2.22/topics/i18n/

LANGUAGE_CODE = "en-us"

Check warning on line 27 in aspects/settings/common.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/common.py#L27

Added line #L27 was not covered by tests

TIME_ZONE = "UTC"

Check warning on line 29 in aspects/settings/common.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/common.py#L29

Added line #L29 was not covered by tests

USE_TZ = True

Check warning on line 31 in aspects/settings/common.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/common.py#L31

Added line #L31 was not covered by tests


def plugin_settings(settings):

Check warning on line 34 in aspects/settings/common.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/common.py#L34

Added line #L34 was not covered by tests
"""
Set of plugin settings used by the Open Edx platform.
More info: https://github.com/edx/edx-platform/blob/master/openedx/core/djangoapps/plugins/README.rst
"""
settings.MAKO_TEMPLATE_DIRS_BASE.append(ROOT_DIRECTORY / "templates")
settings.SUPERSET_CONFIG = {

Check warning on line 40 in aspects/settings/common.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/common.py#L39-L40

Added lines #L39 - L40 were not covered by tests
"url": "http://superset.local.overhang.io:8088",
"username": "superset",
"password": "superset",
}
settings.SUPERSET_INSTRUCTOR_DASHBOARD = {

Check warning on line 45 in aspects/settings/common.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/common.py#L45

Added line #L45 was not covered by tests
"dashboard_slug": "instructor-dashboard",
"dashboard_uuid": "1d6bf904-f53f-47fd-b1c9-6cd7e284d286",
}
settings.SUPERSET_EXTRA_FILTERS_FORMAT = []

Check warning on line 49 in aspects/settings/common.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/common.py#L49

Added line #L49 was not covered by tests
19 changes: 19 additions & 0 deletions aspects/settings/production.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""
Production Django settings for Aspects project.
"""


def plugin_settings(settings):

Check warning on line 6 in aspects/settings/production.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/production.py#L6

Added line #L6 was not covered by tests
"""
Set of plugin settings used by the Open Edx platform.
More info: https://github.com/edx/edx-platform/blob/master/openedx/core/djangoapps/plugins/README.rst
"""
settings.SUPERSET_CONFIG = getattr(settings, "ENV_TOKENS", {}).get(

Check warning on line 11 in aspects/settings/production.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/production.py#L11

Added line #L11 was not covered by tests
"SUPERSET_CONFIG", settings.SUPERSET_CONFIG
)
settings.SUPERSET_INSTRUCTOR_DASHBOARD = getattr(settings, "ENV_TOKENS", {}).get(

Check warning on line 14 in aspects/settings/production.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/production.py#L14

Added line #L14 was not covered by tests
"SUPERSET_INSTRUCTOR_DASHBOARD", settings.SUPERSET_INSTRUCTOR_DASHBOARD
)
settings.SUPERSET_EXTRA_FILTERS_FORMAT = getattr(settings, "ENV_TOKENS", {}).get(

Check warning on line 17 in aspects/settings/production.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/production.py#L17

Added line #L17 was not covered by tests
"SUPERSET_EXTRA_FILTERS_FORMAT", settings.SUPERSET_EXTRA_FILTERS_FORMAT
)
42 changes: 42 additions & 0 deletions aspects/settings/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""
Common Django settings for eox_hooks project.
For more information on this file, see
https://docs.djangoproject.com/en/2.22/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.22/ref/settings/
"""


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.22/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
DATABASES = {

Check warning on line 14 in aspects/settings/test.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/test.py#L14

Added line #L14 was not covered by tests
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": "default.db",
"USER": "",
"PASSWORD": "",
"HOST": "",
"PORT": "",
},
"read_replica": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": "read_replica.db",
"USER": "",
"PASSWORD": "",
"HOST": "",
"PORT": "",
},
}

SECRET_KEY = "not-so-secret-key"

Check warning on line 33 in aspects/settings/test.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/test.py#L33

Added line #L33 was not covered by tests

# Internationalization
# https://docs.djangoproject.com/en/2.22/topics/i18n/

LANGUAGE_CODE = "en-us"

Check warning on line 38 in aspects/settings/test.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/test.py#L38

Added line #L38 was not covered by tests

TIME_ZONE = "UTC"

Check warning on line 40 in aspects/settings/test.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/test.py#L40

Added line #L40 was not covered by tests

USE_TZ = True

Check warning on line 42 in aspects/settings/test.py

View check run for this annotation

Codecov / codecov/patch

aspects/settings/test.py#L42

Added line #L42 was not covered by tests
5 changes: 5 additions & 0 deletions aspects/static/css/superset.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.superset-embedded-container > iframe {
height: 720px;
width: 100%;
display: block;
}
25 changes: 25 additions & 0 deletions aspects/static/html/superset.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{% load i18n %}

<script src="https://unpkg.com/@superset-ui/embedded-sdk"></script>

<div class="email-notifier-instructor-wrapper" width="parent">
<h2>{{display_name}}</h2>

{% if exception %}
<p>{% trans 'Superset is not configured properly. Please contact your system administrator.'%}</p>
<p>
{{exception}}
</p>
{% elif not dashboard_uuid %}
<p>
Dashboard UUID is not set. Please set the dashboard UUID in the Studio. {{dashboard_uuid}}
</p>
{% elif superset_url and superset_token %}
<div class="superset-embedded-container" id="superset-embedded-container-{{xblock_id}}"></div>
<script type="text/javascript">
window.dashboard_uuid ="{{dashboard_uuid}}";
window.superset_url = "{{superset_url}}";
window.superset_token = "{{superset_token}}";
</script>
{% endif %}
</div>
30 changes: 30 additions & 0 deletions aspects/static/js/embed_dashboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
function embedDashboard(dashboard_uuid, superset_url, superset_token, xblock_id) {
xblock_id = xblock_id || "";
window.supersetEmbeddedSdk
.embedDashboard({
id: dashboard_uuid, // given by the Superset embedding UI
supersetDomain: superset_url, // your Superset instance
mountPoint: document.getElementById(`superset-embedded-container-${xblock_id}`), // any html element that can contain an iframe
fetchGuestToken: () => superset_token, // function that returns a Promise with the guest token
dashboardUiConfig: {
// dashboard UI config: hideTitle, hideTab, hideChartControls, filters.visible, filters.expanded (optional)
hideTitle: true,
filters: {
expanded: false,
},
hideTab: true,
hideChartControls: false,
hideFilters: true,
},
})
.then((dashboard) => {
mountPoint = document.getElementById("superset-embedded-container");
/*
Perform extra operations on the dashboard object or the container
when the dashboard is loaded
*/
});
}
if (window.dashboard_uuid !== undefined) {
embedDashboard(window.dashboard_uuid, window.superset_url, window.superset_token, window.xblock_id);
}
36 changes: 36 additions & 0 deletions aspects/static/js/superset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* Javascript for SupersetXBlock. */
function SupersetXBlock(runtime, element, context) {
const dashboard_uuid = context.dashboard_uuid;
const superset_url = context.superset_url;
const superset_token = context.superset_token;
const xblock_id = context.xblock_id

function initSuperset(supersetEmbeddedSdk) {
embedDashboard(dashboard_uuid, superset_url, superset_token, xblock_id);
}

if (typeof require === "function") {
require(["supersetEmbeddedSdk"], function (supersetEmbeddedSdk) {
window.supersetEmbeddedSdk = supersetEmbeddedSdk;
initSuperset();
});
} else {
loadJS(function () {
initSuperset();
});
}
}

function loadJS(callback) {
if (window.supersetEmbeddedSdk) {
callback();
} else {
$.getScript("https://cdn.jsdelivr.net/npm/@superset-ui/[email protected]/bundle/index.min.js")
.done(function () {
callback();
})
.fail(function () {
console.error("Error loading supersetEmbeddedSdk.");
});
}
}
26 changes: 0 additions & 26 deletions aspects/templates/aspects/base.html

This file was deleted.

Loading

0 comments on commit 811eb58

Please sign in to comment.