Skip to content

Commit

Permalink
feat: add tenant stats view
Browse files Browse the repository at this point in the history
chore: update essentials version

chore: update styles to remove background
  • Loading branch information
andrey-canon authored and johanseto committed Jun 30, 2023
1 parent ff69441 commit 3c81d49
Show file tree
Hide file tree
Showing 18 changed files with 351 additions and 21 deletions.
9 changes: 8 additions & 1 deletion eox_nelp/edxapp_wrapper/test_backends/edxmako_m_v1.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.shortcuts import render
from mock import MagicMock


Expand All @@ -7,4 +8,10 @@ def get_edxmako():
Returns:
Mock class.
"""
return MagicMock()
def render_wrapper(template_name, dictionary, namespace, request, **kwargs):
return render(request, template_name, context=dictionary)

edxmako = MagicMock()
edxmako.shortcuts.render_to_response = render_wrapper

return edxmako
5 changes: 1 addition & 4 deletions eox_nelp/settings/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ def plugin_settings(settings): # pylint: disable=function-redefined
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, 'course_experience/frontend/templates'),
os.path.join(BASE_DIR, 'stats/templates'),
],
'APP_DIRS': True,
'OPTIONS': {
Expand All @@ -119,10 +120,6 @@ def plugin_settings(settings): # pylint: disable=function-redefined
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
# 'loaders': [
# 'django.template.loaders.filesystem.Loader',
# 'django.template.loaders.app_directories.Loader',
# ],
'debug': True,
},
},
Expand Down
65 changes: 65 additions & 0 deletions eox_nelp/static/tenant_stats/css/tenant_stats.css

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions eox_nelp/static/tenant_stats/js/tenant_stats.js

Large diffs are not rendered by default.

80 changes: 80 additions & 0 deletions eox_nelp/static/tenant_stats/js/tenant_stats.js.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/

/*!
Copyright (c) 2018 Jed Watson.
Licensed under the MIT License (MIT), see
http://jedwatson.github.io/classnames
*/

/*!
localForage -- Offline Storage, Improved
Version 1.10.0
https://localforage.github.io/localForage
(c) 2013-2017 Mozilla, Apache License 2.0
*/

/*!
* cookie
* Copyright(c) 2012-2014 Roman Shtylman
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/

/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */

/**
* @mui/styled-engine v5.13.2
*
* @license MIT
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/** @license React v0.19.1
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/** @license React v16.13.1
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/** @license React v16.14.0
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/** @license React v16.14.0
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/** @license React v16.14.0
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
Empty file.
29 changes: 29 additions & 0 deletions eox_nelp/stats/frontend/src/components/TenantStats/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React, { useState} from 'react';
import ReactDOM from 'react-dom';
import { APP_INIT_ERROR, APP_READY, subscribe, initialize } from '@edx/frontend-platform';
import { getLocale, getMessages, IntlProvider } from '@edx/frontend-platform/i18n';
import { StatsContainer, messages as essentialsMessages } from '@edunext/frontend-essentials'

import './index.scss';

function LaunchStatsContainer() {
const [locale, setLocale] = useState(getLocale());

return (
<IntlProvider locale={locale} messages={getMessages()}>
<StatsContainer
showVideos={showVideos}
showCourses={showCourses}
showProblems={showProblems}
showLearners={showLearners}
showInstructors={showInstructors}
/>
</IntlProvider>
);
}

subscribe(APP_READY, () => {
ReactDOM.render(<LaunchStatsContainer />, document.getElementById('tenant-stats'));
});

initialize({ messages: [essentialsMessages]});
16 changes: 16 additions & 0 deletions eox_nelp/stats/frontend/src/components/TenantStats/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@import "~@edx/brand/paragon/fonts";
@import "~@edx/brand/paragon/variables";
@import "~@edx/paragon/scss/core/core";
@import "~@edx/brand/paragon/overrides";

body {
background-color: transparent;

#tenant-stats{
.stats-container{
margin: 0;
width: auto;
}
}
}

Empty file.
19 changes: 19 additions & 0 deletions eox_nelp/stats/templates/tenant_stats.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<%namespace name='static' file='static_content.html'/>
<html>
<head>
<meta charset="utf-8">
<title>Tenant Stats</title>
<link rel="stylesheet" href="${static.url('tenant_stats/css/tenant_stats.css')}">
</head>
<body>
<div id="tenant-stats"></div>
<script>
var showVideos = "true" === "${showVideos}";
var showCourses = "true" === "${showCourses}";
var showProblems = "true" === "${showProblems}";
var showLearners = "true" === "${showLearners}";
var showInstructors = "true" === "${showInstructors}";
</script>
<script src="${static.url('tenant_stats/js/tenant_stats.js')}"></script>
</body>
</html>
62 changes: 62 additions & 0 deletions eox_nelp/stats/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""This file contains all the test for the stats views.py file.
Classes:
GetTenantStatsTestCase: Test get_tenant_stats function based view.
"""
from ddt import data, ddt
from django.test import Client, TestCase
from django.urls import reverse
from rest_framework import status


@ddt
class GetTenantStatsTestCase(TestCase):
""" Test get_tenant_stats function based view."""

def setUp(self): # pylint: disable=invalid-name
"""
Set base variables and objects across experience test cases.
"""
self.client = Client()
self.template_name = "tenant_stats.html"

def test_get_default_stats(self):
"""
Test that the default behavior, that is just render the tenant-stats div
Expected behavior:
- Status code 200.
- template name is as expected.
- tenant-stats div exist
"""
url_endpoint = reverse("stats:tenant")

response = self.client.get(url_endpoint)

self.assertEqual(status.HTTP_200_OK, response.status_code)
self.assertEqual(self.template_name, response.templates[0].name)
self.assertContains(response, '<div id="tenant-stats"></div')

@data("showVideos", "showCourse", "showProblems", "showInstructors", "showLearners")
def test_get_specific_stat(self, query_param):
"""
Test that the view render successfully when a query param is included
Expected behavior:
- Status code 200.
- template name is as expected.
- tenant-stats div exist
- the query param is 'true'
- CSS was included
- JS was included
"""
url_endpoint = f"{reverse('stats:tenant')}?{query_param}=true"

response = self.client.get(url_endpoint)

self.assertEqual(status.HTTP_200_OK, response.status_code)
self.assertEqual(self.template_name, response.templates[0].name)
self.assertContains(response, '<div id="tenant-stats"></div')
self.assertEqual("true", response.context[query_param])
self.assertContains(response, "tenant_stats/css/tenant_stats.css")
self.assertContains(response, "tenant_stats/js/tenant_stats.js")
10 changes: 10 additions & 0 deletions eox_nelp/stats/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""frontend templates urls for course_experience"""
from django.urls import path

from eox_nelp.stats.views import get_tenant_stats

app_name = "eox_nelp" # pylint: disable=invalid-name

urlpatterns = [
path('tenant/', get_tenant_stats, name='tenant')
]
40 changes: 40 additions & 0 deletions eox_nelp/stats/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""Stats Views file.
Contains all the views for stats
classes:
get_tenant_stats: function based view.
"""

from eox_nelp.templates_config import render_to_response


def get_tenant_stats(request):
"""
Simple function based view that renders the StatsContainer essential component.
By default this show nothing since this requires the specific query para to show the content.
Examples:
renders just video card /eox-nelp/stats/tenant/?showVideos=true
render multiple components
/eox-nelp/stats/tenant/?showVideos=true&showCourses=true&showInstructors=true
The available options are:
showVideos
showCourses
showLearners
showInstructors
showProblems
"""

context = {
"showCourses": "false",
"showVideos": "false",
"showProblems": "false",
"showLearners": "false",
"showInstructors": "false",
}
context.update(request.GET.dict())

return render_to_response("tenant_stats.html", context)
2 changes: 2 additions & 0 deletions eox_nelp/templates_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@

import eox_nelp.course_experience.frontend.templates as course_experience_templates
from eox_nelp.edxapp_wrapper.edxmako import edxmako
from eox_nelp.stats import templates as stats_templates

module_templates_to_include = [
stats_templates,
course_experience_templates,
]

Expand Down
1 change: 1 addition & 0 deletions eox_nelp/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@
include('eox_nelp.course_experience.frontend.urls', namespace='course-experience-frontend'),
),
path('api/stats/', include('eox_nelp.stats.api.urls', namespace='stats-api')),
path('stats/', include('eox_nelp.stats.urls', namespace='stats')),
]
27 changes: 13 additions & 14 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
"license": "ISC",
"homepage": "https://bitbucket.org/edunext/eox-nelp#readme",
"dependencies": {
"@edunext/frontend-essentials": "^1.1.0-feedback-carousel",
"@edx/brand": "npm:@edx/brand-openedx@^1.2.0",
"@edunext/frontend-essentials": "^1.3.0",
"@edx/brand": "github:nelc/brand-openedx#ednx-release/mango.nelp",
"@edx/frontend-platform": "npm:@edunext/frontend-platform@^3.3.1",
"@edx/paragon": "npm:@edunext/paragon@^20.22.48",
"babel-loader": "^8.2.3",
Expand Down
1 change: 1 addition & 0 deletions webpack.common.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const config = createConfig('webpack-prod');
// Override entries.
config.entry = {
feedback_carousel: './eox_nelp/course_experience/frontend/src/components/FeedbackCarousel/index',
tenant_stats: './eox_nelp/stats/frontend/src/components/TenantStats/index',
}

// Override output configuration in order to get a unique folder per entry.
Expand Down

0 comments on commit 3c81d49

Please sign in to comment.