Skip to content

Commit

Permalink
feat: allow to embed multiple superset dasboards
Browse files Browse the repository at this point in the history
  • Loading branch information
Ian2012 committed Mar 18, 2024
1 parent 3430bff commit dee2365
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 39 deletions.
4 changes: 2 additions & 2 deletions platform_plugin_aspects/extensions/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def run_filter(
_ (str): instructor dashboard template name.
"""
course = context["course"]
dashboard_uuid = settings.ASPECTS_INSTRUCTOR_DASHBOARD_UUID
dashboards = settings.ASPECTS_INSTRUCTOR_DASHBOARDS
extra_filters_format = settings.SUPERSET_EXTRA_FILTERS_FORMAT

filters = ASPECTS_SECURITY_FILTERS_FORMAT + extra_filters_format
Expand All @@ -45,7 +45,7 @@ def run_filter(
context = generate_superset_context(
context,
user,
dashboard_uuid=dashboard_uuid,
dashboards=dashboards,
filters=filters,
)

Expand Down
7 changes: 6 additions & 1 deletion platform_plugin_aspects/settings/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ def plugin_settings(settings):
"username": "superset",
"password": "superset",
}
settings.ASPECTS_INSTRUCTOR_DASHBOARD_UUID = "1d6bf904-f53f-47fd-b1c9-6cd7e284d286"
settings.ASPECTS_INSTRUCTOR_DASHBOARDS = [
{
"name": "Instructor Dashboard",
"uuid": "1d6bf904-f53f-47fd-b1c9-6cd7e284d286",
},
]
settings.SUPERSET_EXTRA_FILTERS_FORMAT = []
settings.EVENT_SINK_CLICKHOUSE_BACKEND_CONFIG = {
# URL to a running ClickHouse server's HTTP interface. ex: https://foo.openedx.org:8443/ or
Expand Down
6 changes: 2 additions & 4 deletions platform_plugin_aspects/settings/production.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@ def plugin_settings(settings):
settings.SUPERSET_CONFIG = getattr(settings, "ENV_TOKENS", {}).get(
"SUPERSET_CONFIG", settings.SUPERSET_CONFIG
)
settings.ASPECTS_INSTRUCTOR_DASHBOARD_UUID = getattr(
settings, "ENV_TOKENS", {}
).get(
"ASPECTS_INSTRUCTOR_DASHBOARD_UUID", settings.ASPECTS_INSTRUCTOR_DASHBOARD_UUID
settings.ASPECTS_INSTRUCTOR_DASHBOARDS = getattr(settings, "ENV_TOKENS", {}).get(
"ASPECTS_INSTRUCTOR_DASHBOARDS", settings.ASPECTS_INSTRUCTOR_DASHBOARDS
)
settings.SUPERSET_EXTRA_FILTERS_FORMAT = getattr(settings, "ENV_TOKENS", {}).get(
"SUPERSET_EXTRA_FILTERS_FORMAT", settings.SUPERSET_EXTRA_FILTERS_FORMAT
Expand Down
13 changes: 9 additions & 4 deletions platform_plugin_aspects/settings/tests/test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def test_common_settings(self):
self.assertNotIn("service_url", settings.SUPERSET_CONFIG)
self.assertIn("username", settings.SUPERSET_CONFIG)
self.assertIn("password", settings.SUPERSET_CONFIG)
self.assertIsNotNone(settings.ASPECTS_INSTRUCTOR_DASHBOARD_UUID)
self.assertIsNotNone(settings.ASPECTS_INSTRUCTOR_DASHBOARDS)
self.assertIsNotNone(settings.SUPERSET_EXTRA_FILTERS_FORMAT)
for key in ("url", "username", "password", "database", "timeout_secs"):
assert key in settings.EVENT_SINK_CLICKHOUSE_BACKEND_CONFIG
Expand All @@ -46,7 +46,12 @@ def test_production_settings(self):
"username": "superset",
"password": "superset",
},
"ASPECTS_INSTRUCTOR_DASHBOARD_UUID": "test-settings-dashboard-uuid",
"ASPECTS_INSTRUCTOR_DASHBOARDS": [
{
"name": "Instructor Dashboard",
"uuid": "test-settings-dashboard-uuid",
}
],
"SUPERSET_EXTRA_FILTERS_FORMAT": [],
"EVENT_SINK_CLICKHOUSE_BACKEND_CONFIG": {
"url": test_url,
Expand All @@ -61,8 +66,8 @@ def test_production_settings(self):
settings.SUPERSET_CONFIG, settings.ENV_TOKENS["SUPERSET_CONFIG"]
)
self.assertEqual(
settings.ASPECTS_INSTRUCTOR_DASHBOARD_UUID,
settings.ENV_TOKENS["ASPECTS_INSTRUCTOR_DASHBOARD_UUID"],
settings.ASPECTS_INSTRUCTOR_DASHBOARDS,
settings.ENV_TOKENS["ASPECTS_INSTRUCTOR_DASHBOARDS"],
)
self.assertEqual(
settings.SUPERSET_EXTRA_FILTERS_FORMAT,
Expand Down
17 changes: 13 additions & 4 deletions platform_plugin_aspects/static/html/superset.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,31 @@

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

<div class="email-notifier-instructor-wrapper" width="parent">
<div class="aspects-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 %}
{% elif not dashboard_uuid and not superset_dashboards %}
<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>
{% if xblock_id %}
<div class="superset-embedded-container" id="superset-embedded-container-{{xblock_id}}"></div>
{% else %}
{% for dashboard in superset_dashboards %}
<div>
<h3>{{dashboard.name}}</h3>
</div>
<div class="superset-embedded-container" id="superset-embedded-container-{{dashboard.uuid}}"></div>
{% endfor %}
{% endif %}
<script type="text/javascript">
window.dashboard_uuid ="{{dashboard_uuid}}";
window.superset_dashboards = {{superset_dashboards | safe }};
window.superset_url = "{{superset_url}}";
window.superset_token = "{{superset_token}}";
</script>
Expand Down
10 changes: 7 additions & 3 deletions platform_plugin_aspects/static/js/embed_dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ function embedDashboard(dashboard_uuid, superset_url, superset_token, xblock_id)
when the dashboard is loaded
*/
});
}
if (window.dashboard_uuid !== undefined) {
embedDashboard(window.dashboard_uuid, window.superset_url, window.superset_token, window.xblock_id);
};

if (window.superset_dashboards !== undefined) {
window.superset_dashboards.forEach(function(dashboard) {
console.log(dashboard)
embedDashboard(dashboard.uuid, window.superset_url, window.superset_token, dashboard.uuid);
});
}
16 changes: 10 additions & 6 deletions platform_plugin_aspects/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,18 @@ def test_generate_superset_context(self, mock_generate_guest_token):
filter_mock = Mock()
user_mock = Mock()
context = {"course": course_mock}
mock_generate_guest_token.return_value = ("test-token", "test-dashboard-uuid")
dashboards = [{"name": "test", "uuid": "test-dashboard-uuid"}]
mock_generate_guest_token.return_value = ("test-token", dashboards)

context = generate_superset_context(
context,
user_mock,
dashboard_uuid="test-dashboard-uuid",
dashboards=dashboards,
filters=[filter_mock],
)

self.assertEqual(context["superset_token"], "test-token")
self.assertEqual(context["dashboard_uuid"], "test-dashboard-uuid")
self.assertEqual(context["superset_dashboards"], dashboards)
self.assertEqual(context["superset_url"], "http://superset-dummy-url/")
self.assertNotIn("exception", context)

Expand All @@ -143,7 +144,7 @@ def test_generate_superset_context_with_superset_client_exception(
context = generate_superset_context(
context,
user_mock,
dashboard_uuid="test-dashboard-uuid",
dashboards=[{"name": "test", "uuid": "test-dashboard-uuid"}],
filters=[filter_mock],
)

Expand Down Expand Up @@ -175,14 +176,17 @@ def test_generate_superset_context_succesful(self, mock_superset_client):
"token": "test-token",
}

dashboards = [{"name": "test", "uuid": "test-dashboard-uuid"}]

context = generate_superset_context(
context,
user_mock,
dashboards=dashboards,
filters=[filter_mock],
)

self.assertEqual(context["superset_token"], "test-token")
self.assertEqual(context["dashboard_uuid"], "test-settings-dashboard-uuid")
self.assertEqual(context["superset_dashboards"], dashboards)
self.assertEqual(context["superset_url"], "http://dummy-superset-url/")

def test_generate_superset_context_with_exception(self):
Expand All @@ -198,7 +202,7 @@ def test_generate_superset_context_with_exception(self):
context = generate_superset_context(
context,
user_mock,
dashboard_uuid="test-dashboard-uuid",
dashboards=[{"name": "test", "uuid": "test-dashboard-uuid"}],
filters=[filter_mock],
)

Expand Down
24 changes: 12 additions & 12 deletions platform_plugin_aspects/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def _(text):
def generate_superset_context( # pylint: disable=dangerous-default-value
context,
user,
dashboard_uuid=None,
dashboards,
filters=[],
):
"""
Expand All @@ -38,17 +38,17 @@ def generate_superset_context( # pylint: disable=dangerous-default-value
context (dict): the context for the instructor dashboard. It must include a course object
user (XBlockUser or User): the current user.
superset_config (dict): superset config.
dashboard_uuid (str): superset dashboard uuid.
dashboards (list): list of superset dashboard uuid.
filters (list): list of filters to apply to the dashboard.
"""
course = context["course"]
superset_config = settings.SUPERSET_CONFIG

superset_token, dashboard_uuid = _generate_guest_token(
superset_token, dashboards = _generate_guest_token(
user=user,
course=course,
superset_config=superset_config,
dashboard_uuid=dashboard_uuid,
dashboards=dashboards,
filters=filters,
)

Expand All @@ -57,21 +57,21 @@ def generate_superset_context( # pylint: disable=dangerous-default-value
context.update(
{
"superset_token": superset_token,
"dashboard_uuid": dashboard_uuid,
"superset_dashboards": dashboards,
"superset_url": superset_url,
}
)
else:
context.update(
{
"exception": str(dashboard_uuid),
"exception": str(dashboards),
}
)

return context


def _generate_guest_token(user, course, superset_config, dashboard_uuid, filters):
def _generate_guest_token(user, course, superset_config, dashboards, filters):
"""
Generate a Superset guest token for the user.
Expand Down Expand Up @@ -102,16 +102,16 @@ def _generate_guest_token(user, course, superset_config, dashboard_uuid, filters

formatted_filters = [filter.format(course=course, user=user) for filter in filters]

if not dashboard_uuid:
dashboard_uuid = settings.ASPECTS_INSTRUCTOR_DASHBOARD_UUID

data = {
"user": _superset_user_data(user),
"resources": [{"type": "dashboard", "id": dashboard_uuid}],
"resources": [
{"type": "dashboard", "id": dashboard["uuid"]} for dashboard in dashboards
],
"rls": [{"clause": filter} for filter in formatted_filters],
}

try:
logger.info(f"Requesting guest token from Superset, {data}")
response = client.session.post(
url=f"{superset_internal_host}api/v1/security/guest_token/",
json=data,
Expand All @@ -120,7 +120,7 @@ def _generate_guest_token(user, course, superset_config, dashboard_uuid, filters
response.raise_for_status()
token = response.json()["token"]

return token, dashboard_uuid
return token, dashboards
except Exception as exc: # pylint: disable=broad-except
logger.error(exc)
return None, exc
Expand Down
4 changes: 2 additions & 2 deletions platform_plugin_aspects/xblock.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def student_view(self, context=None):
context = generate_superset_context(
context=context,
user=user,
dashboard_uuid=self.dashboard_uuid,
dashboards=[{"name": self.display_name, "uuid": self.dashboard_uuid}],
filters=self.filters,
)
context["xblock_id"] = str(self.scope_ids.usage_id.block_id)
Expand All @@ -125,7 +125,7 @@ def student_view(self, context=None):
frag.initialize_js(
"SupersetXBlock",
json_args={
"dashboard_uuid": context.get("dashboard_uuid"),
"dashboard_uuid": self.dashboard_uuid,
"superset_url": context.get("superset_url"),
"superset_token": context.get("superset_token"),
"xblock_id": context.get("xblock_id"),
Expand Down
7 changes: 6 additions & 1 deletion test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,12 @@
}
]

ASPECTS_INSTRUCTOR_DASHBOARD_UUID = "test-dashboard-uuid"
ASPECTS_INSTRUCTOR_DASHBOARDS = [
{
"name": "Instructor Dashboard",
"uuid": "1d6bf904-f53f-47fd-b1c9-6cd7e284d286",
},
]

SUPERSET_EXTRA_FILTERS_FORMAT = []

Expand Down

0 comments on commit dee2365

Please sign in to comment.