From b8206de83a0e939136dd4ccc347a90fd8c297bfb Mon Sep 17 00:00:00 2001 From: Alex Velez Date: Tue, 7 Feb 2023 11:34:49 -0500 Subject: [PATCH 01/17] [MyDownloads] Setup the new Kolibri module --- kolibri/plugins/my_downloads/__init__.py | 0 kolibri/plugins/my_downloads/api_urls.py | 1 + .../plugins/my_downloads/assets/src/app.js | 25 +++++++++++ .../assets/src/modules/pluginModule.js | 21 ++++++++++ .../plugins/my_downloads/assets/src/routes.js | 16 ++++++++ .../assets/src/views/MyDownloads.vue | 20 +++++++++ .../src/views/MyDownloadsSideNavEntry.vue | 41 +++++++++++++++++++ kolibri/plugins/my_downloads/buildConfig.js | 14 +++++++ .../plugins/my_downloads/kolibri_plugin.py | 30 ++++++++++++++ .../templates/my_downloads/my_downloads.html | 5 +++ kolibri/plugins/my_downloads/urls.py | 5 +++ kolibri/plugins/my_downloads/views.py | 13 ++++++ kolibri/utils/build_config/default_plugins.py | 1 + 13 files changed, 192 insertions(+) create mode 100644 kolibri/plugins/my_downloads/__init__.py create mode 100644 kolibri/plugins/my_downloads/api_urls.py create mode 100644 kolibri/plugins/my_downloads/assets/src/app.js create mode 100644 kolibri/plugins/my_downloads/assets/src/modules/pluginModule.js create mode 100644 kolibri/plugins/my_downloads/assets/src/routes.js create mode 100644 kolibri/plugins/my_downloads/assets/src/views/MyDownloads.vue create mode 100644 kolibri/plugins/my_downloads/assets/src/views/MyDownloadsSideNavEntry.vue create mode 100644 kolibri/plugins/my_downloads/buildConfig.js create mode 100644 kolibri/plugins/my_downloads/kolibri_plugin.py create mode 100644 kolibri/plugins/my_downloads/templates/my_downloads/my_downloads.html create mode 100644 kolibri/plugins/my_downloads/urls.py create mode 100644 kolibri/plugins/my_downloads/views.py diff --git a/kolibri/plugins/my_downloads/__init__.py b/kolibri/plugins/my_downloads/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/kolibri/plugins/my_downloads/api_urls.py b/kolibri/plugins/my_downloads/api_urls.py new file mode 100644 index 00000000000..637600f58aa --- /dev/null +++ b/kolibri/plugins/my_downloads/api_urls.py @@ -0,0 +1 @@ +urlpatterns = [] diff --git a/kolibri/plugins/my_downloads/assets/src/app.js b/kolibri/plugins/my_downloads/assets/src/app.js new file mode 100644 index 00000000000..fb1fdecd0e6 --- /dev/null +++ b/kolibri/plugins/my_downloads/assets/src/app.js @@ -0,0 +1,25 @@ +import router from 'kolibri.coreVue.router'; +import PageRoot from 'kolibri.coreVue.components.PageRoot'; +import routes from './routes'; +import pluginModule from './modules/pluginModule'; +import KolibriApp from 'kolibri_app'; + +class MyDownloadsModule extends KolibriApp { + get routes() { + return routes; + } + get RootVue() { + return PageRoot; + } + get pluginModule() { + return pluginModule; + } + ready() { + router.afterEach((toRoute, fromRoute) => { + this.store.dispatch('resetModuleState', { toRoute, fromRoute }); + }); + super.ready(); + } +} + +export default new MyDownloadsModule(); diff --git a/kolibri/plugins/my_downloads/assets/src/modules/pluginModule.js b/kolibri/plugins/my_downloads/assets/src/modules/pluginModule.js new file mode 100644 index 00000000000..35d1db353a4 --- /dev/null +++ b/kolibri/plugins/my_downloads/assets/src/modules/pluginModule.js @@ -0,0 +1,21 @@ +export default { + state() { + return { + test: '', + }; + }, + actions: { + reset(store) { + store.commit('CORE_SET_PAGE_LOADING', false); + store.commit('CORE_SET_ERROR', null); + }, + resetModuleState(store) { + store.commit('profile/RESET_STATE'); + }, + }, + mutations: { + SET_Test(state, test) { + state.test = test; + }, + }, +}; diff --git a/kolibri/plugins/my_downloads/assets/src/routes.js b/kolibri/plugins/my_downloads/assets/src/routes.js new file mode 100644 index 00000000000..f36dfccacc6 --- /dev/null +++ b/kolibri/plugins/my_downloads/assets/src/routes.js @@ -0,0 +1,16 @@ +import MyDownloadsPage from './views/MyDownloads'; + +export default [ + { + path: '/', + name: 'MY_DOWNLOADS', + component: MyDownloadsPage, + // beforeEnter(to, from, next) { + // if (!store.getters.isUserLoggedIn) { + // redirectBrowser(); + // } else { + // preload(next); + // } + // }, + }, +]; diff --git a/kolibri/plugins/my_downloads/assets/src/views/MyDownloads.vue b/kolibri/plugins/my_downloads/assets/src/views/MyDownloads.vue new file mode 100644 index 00000000000..66335f3aa9c --- /dev/null +++ b/kolibri/plugins/my_downloads/assets/src/views/MyDownloads.vue @@ -0,0 +1,20 @@ + + + + + + + diff --git a/kolibri/plugins/my_downloads/assets/src/views/MyDownloadsSideNavEntry.vue b/kolibri/plugins/my_downloads/assets/src/views/MyDownloadsSideNavEntry.vue new file mode 100644 index 00000000000..d3bb9e5ea59 --- /dev/null +++ b/kolibri/plugins/my_downloads/assets/src/views/MyDownloadsSideNavEntry.vue @@ -0,0 +1,41 @@ + + + + diff --git a/kolibri/plugins/my_downloads/buildConfig.js b/kolibri/plugins/my_downloads/buildConfig.js new file mode 100644 index 00000000000..a8f741a300c --- /dev/null +++ b/kolibri/plugins/my_downloads/buildConfig.js @@ -0,0 +1,14 @@ +module.exports = [ + { + bundle_id: 'app', + webpack_config: { + entry: './assets/src/app.js', + }, + }, + { + bundle_id: 'my_downloads_side_nav', + webpack_config: { + entry: './assets/src/views/MyDownloadsSideNavEntry.vue', + }, + }, +]; diff --git a/kolibri/plugins/my_downloads/kolibri_plugin.py b/kolibri/plugins/my_downloads/kolibri_plugin.py new file mode 100644 index 00000000000..ca0f9cac092 --- /dev/null +++ b/kolibri/plugins/my_downloads/kolibri_plugin.py @@ -0,0 +1,30 @@ +from __future__ import absolute_import +from __future__ import print_function +from __future__ import unicode_literals + +from kolibri.core.hooks import NavigationHook +from kolibri.core.webpack import hooks as webpack_hooks +from kolibri.plugins import KolibriPluginBase +from kolibri.plugins.hooks import register_hook +from kolibri.utils import translation +from kolibri.utils.translation import ugettext as _ + + +class MyDownloads(KolibriPluginBase): + translated_view_urls = "urls" + untranslated_view_urls = "api_urls" + can_manage_while_running = True + + def name(self, lang): + with translation.override(lang): + return _("My downloads") + + +@register_hook +class MyDownloadsAsset(webpack_hooks.WebpackBundleHook): + bundle_id = "app" + + +@register_hook +class MyDownloadsNavAction(NavigationHook): + bundle_id = "my_downloads_side_nav" diff --git a/kolibri/plugins/my_downloads/templates/my_downloads/my_downloads.html b/kolibri/plugins/my_downloads/templates/my_downloads/my_downloads.html new file mode 100644 index 00000000000..b210985254d --- /dev/null +++ b/kolibri/plugins/my_downloads/templates/my_downloads/my_downloads.html @@ -0,0 +1,5 @@ +{% extends "kolibri/base.html" %} +{% load webpack_tags %} +{% block content %} + {% webpack_asset 'kolibri.plugins.my_downloads.app' %} +{% endblock %} diff --git a/kolibri/plugins/my_downloads/urls.py b/kolibri/plugins/my_downloads/urls.py new file mode 100644 index 00000000000..989147a9c23 --- /dev/null +++ b/kolibri/plugins/my_downloads/urls.py @@ -0,0 +1,5 @@ +from django.conf.urls import url + +from . import views + +urlpatterns = [url(r"^$", views.MyDownloadsView.as_view(), name="my_downloads")] diff --git a/kolibri/plugins/my_downloads/views.py b/kolibri/plugins/my_downloads/views.py new file mode 100644 index 00000000000..5e221052663 --- /dev/null +++ b/kolibri/plugins/my_downloads/views.py @@ -0,0 +1,13 @@ +from __future__ import absolute_import +from __future__ import print_function +from __future__ import unicode_literals + +from django.utils.decorators import method_decorator +from django.views.generic.base import TemplateView + +from kolibri.core.decorators import cache_no_user_data + + +@method_decorator(cache_no_user_data, name="dispatch") +class MyDownloadsView(TemplateView): + template_name = "my_downloads/my_downloads.html" diff --git a/kolibri/utils/build_config/default_plugins.py b/kolibri/utils/build_config/default_plugins.py index c2892a53e50..a513d70aeba 100644 --- a/kolibri/utils/build_config/default_plugins.py +++ b/kolibri/utils/build_config/default_plugins.py @@ -7,6 +7,7 @@ "kolibri.plugins.facility", "kolibri.plugins.learn", "kolibri.plugins.media_player", + "kolibri.plugins.my_downloads", "kolibri.plugins.pdf_viewer", "kolibri.plugins.perseus_viewer", "kolibri.plugins.setup_wizard", From 1387b00cf1f4617353410114d38b1e2ffe3d9e71 Mon Sep 17 00:00:00 2001 From: Alex Velez Date: Mon, 13 Feb 2023 18:02:43 -0500 Subject: [PATCH 02/17] My Downloads setup and head --- kolibri/__init__.py | 1 + .../plugins/my_downloads/assets/src/app.js | 8 +- .../plugins/my_downloads/assets/src/routes.js | 16 +- .../assets/src/views/MyDownloads.vue | 206 +++++++++++++++++- .../src/views/MyDownloadsSideNavEntry.vue | 9 +- .../lib/webpack.config.plugin.js | 2 +- 6 files changed, 220 insertions(+), 22 deletions(-) diff --git a/kolibri/__init__.py b/kolibri/__init__.py index 3deb29cf38c..0a940374b75 100755 --- a/kolibri/__init__.py +++ b/kolibri/__init__.py @@ -35,6 +35,7 @@ "kolibri.plugins.facility", "kolibri.plugins.learn", "kolibri.plugins.media_player", + "kolibri.plugins.my_downloads", "kolibri.plugins.pdf_viewer", "kolibri.plugins.setup_wizard", "kolibri.plugins.slideshow_viewer", diff --git a/kolibri/plugins/my_downloads/assets/src/app.js b/kolibri/plugins/my_downloads/assets/src/app.js index fb1fdecd0e6..4b6a811a636 100644 --- a/kolibri/plugins/my_downloads/assets/src/app.js +++ b/kolibri/plugins/my_downloads/assets/src/app.js @@ -1,4 +1,4 @@ -import router from 'kolibri.coreVue.router'; +// import router from 'kolibri.coreVue.router'; import PageRoot from 'kolibri.coreVue.components.PageRoot'; import routes from './routes'; import pluginModule from './modules/pluginModule'; @@ -15,9 +15,9 @@ class MyDownloadsModule extends KolibriApp { return pluginModule; } ready() { - router.afterEach((toRoute, fromRoute) => { - this.store.dispatch('resetModuleState', { toRoute, fromRoute }); - }); + // router.afterEach((toRoute, fromRoute) => { + // this.store.dispatch('resetModuleState', { toRoute, fromRoute }); + // }); super.ready(); } } diff --git a/kolibri/plugins/my_downloads/assets/src/routes.js b/kolibri/plugins/my_downloads/assets/src/routes.js index f36dfccacc6..9821d2ccfa2 100644 --- a/kolibri/plugins/my_downloads/assets/src/routes.js +++ b/kolibri/plugins/my_downloads/assets/src/routes.js @@ -1,3 +1,5 @@ +import store from 'kolibri.coreVue.vuex.store'; +import redirectBrowser from 'kolibri.utils.redirectBrowser'; import MyDownloadsPage from './views/MyDownloads'; export default [ @@ -5,12 +7,12 @@ export default [ path: '/', name: 'MY_DOWNLOADS', component: MyDownloadsPage, - // beforeEnter(to, from, next) { - // if (!store.getters.isUserLoggedIn) { - // redirectBrowser(); - // } else { - // preload(next); - // } - // }, + beforeEnter(to, from, next) { + if (!store.getters.isUserLoggedIn) { + redirectBrowser(); + } else { + next(); + } + }, }, ]; diff --git a/kolibri/plugins/my_downloads/assets/src/views/MyDownloads.vue b/kolibri/plugins/my_downloads/assets/src/views/MyDownloads.vue index 66335f3aa9c..fb877dbd902 100644 --- a/kolibri/plugins/my_downloads/assets/src/views/MyDownloads.vue +++ b/kolibri/plugins/my_downloads/assets/src/views/MyDownloads.vue @@ -1,20 +1,216 @@ - + diff --git a/kolibri/plugins/my_downloads/assets/src/views/MyDownloadsSideNavEntry.vue b/kolibri/plugins/my_downloads/assets/src/views/MyDownloadsSideNavEntry.vue index d3bb9e5ea59..82acc0c9d34 100644 --- a/kolibri/plugins/my_downloads/assets/src/views/MyDownloadsSideNavEntry.vue +++ b/kolibri/plugins/my_downloads/assets/src/views/MyDownloadsSideNavEntry.vue @@ -1,9 +1,9 @@ @@ -12,6 +12,7 @@ + + + diff --git a/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/PaginatedListContainerWithBackend.vue b/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/PaginatedListContainerWithBackend.vue new file mode 100644 index 00000000000..ea2ea1e08f7 --- /dev/null +++ b/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/PaginatedListContainerWithBackend.vue @@ -0,0 +1,132 @@ + + + + + + + diff --git a/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/SelectionBottomBar.vue b/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/SelectionBottomBar.vue new file mode 100644 index 00000000000..b05f5984afb --- /dev/null +++ b/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/SelectionBottomBar.vue @@ -0,0 +1,64 @@ + + + + + + + diff --git a/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/index.vue b/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/index.vue new file mode 100644 index 00000000000..a8f36a38ac9 --- /dev/null +++ b/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/index.vue @@ -0,0 +1,213 @@ + + + + + + + diff --git a/kolibri/plugins/my_downloads/assets/src/views/MyDownloads.vue b/kolibri/plugins/my_downloads/assets/src/views/MyDownloads.vue index fb877dbd902..bdcf0824dee 100644 --- a/kolibri/plugins/my_downloads/assets/src/views/MyDownloads.vue +++ b/kolibri/plugins/my_downloads/assets/src/views/MyDownloads.vue @@ -61,6 +61,7 @@ /> + @@ -72,11 +73,13 @@ import AppBarPage from 'kolibri.coreVue.components.AppBarPage'; import commonCoreStrings from 'kolibri.coreVue.mixins.commonCoreStrings'; import responsiveWindowMixin from 'kolibri.coreVue.mixins.responsiveWindowMixin'; + import DownloadsList from './DownloadsList'; export default { name: 'MyDownloads', components: { AppBarPage, + DownloadsList, }, mixins: [commonCoreStrings, responsiveWindowMixin], data() { @@ -185,7 +188,7 @@ diff --git a/kolibri/plugins/learn/assets/src/my_downloads/views/DownloadsList/PaginatedListContainerWithBackend.vue b/kolibri/plugins/learn/assets/src/my_downloads/views/DownloadsList/PaginatedListContainerWithBackend.vue new file mode 100644 index 00000000000..ea2ea1e08f7 --- /dev/null +++ b/kolibri/plugins/learn/assets/src/my_downloads/views/DownloadsList/PaginatedListContainerWithBackend.vue @@ -0,0 +1,132 @@ + + + + + + + diff --git a/kolibri/plugins/learn/assets/src/my_downloads/views/DownloadsList/SelectionBottomBar.vue b/kolibri/plugins/learn/assets/src/my_downloads/views/DownloadsList/SelectionBottomBar.vue new file mode 100644 index 00000000000..b05f5984afb --- /dev/null +++ b/kolibri/plugins/learn/assets/src/my_downloads/views/DownloadsList/SelectionBottomBar.vue @@ -0,0 +1,64 @@ + + + + + + + diff --git a/kolibri/plugins/learn/assets/src/my_downloads/views/DownloadsList/index.vue b/kolibri/plugins/learn/assets/src/my_downloads/views/DownloadsList/index.vue new file mode 100644 index 00000000000..a8f36a38ac9 --- /dev/null +++ b/kolibri/plugins/learn/assets/src/my_downloads/views/DownloadsList/index.vue @@ -0,0 +1,213 @@ + + + + + + + diff --git a/kolibri/plugins/learn/assets/src/my_downloads/views/MyDownloads.vue b/kolibri/plugins/learn/assets/src/my_downloads/views/MyDownloads.vue new file mode 100644 index 00000000000..bdcf0824dee --- /dev/null +++ b/kolibri/plugins/learn/assets/src/my_downloads/views/MyDownloads.vue @@ -0,0 +1,219 @@ + + + + + + + diff --git a/kolibri/plugins/learn/assets/src/my_downloads/views/MyDownloadsSideNavEntry.vue b/kolibri/plugins/learn/assets/src/my_downloads/views/MyDownloadsSideNavEntry.vue new file mode 100644 index 00000000000..82acc0c9d34 --- /dev/null +++ b/kolibri/plugins/learn/assets/src/my_downloads/views/MyDownloadsSideNavEntry.vue @@ -0,0 +1,40 @@ + + + + diff --git a/kolibri/plugins/learn/buildConfig.js b/kolibri/plugins/learn/buildConfig.js index bafbfe2debf..c60a56d08db 100644 --- a/kolibri/plugins/learn/buildConfig.js +++ b/kolibri/plugins/learn/buildConfig.js @@ -11,10 +11,16 @@ module.exports = [ entry: './assets/src/views/LearnSideNavEntry.vue', }, }, + { + bundle_id: 'my_downloads_app', + webpack_config: { + entry: './assets/src/my_downloads/app.js', + }, + }, { bundle_id: 'my_downloads_side_nav', webpack_config: { - entry: './assets/src/views/MyDownloadsSideNavEntry.vue', + entry: './assets/src/my_downloads/views/MyDownloadsSideNavEntry.vue', }, }, ]; diff --git a/kolibri/plugins/learn/templates/learn/my_downloads.html b/kolibri/plugins/learn/templates/learn/my_downloads.html new file mode 100644 index 00000000000..1d75fa6a05d --- /dev/null +++ b/kolibri/plugins/learn/templates/learn/my_downloads.html @@ -0,0 +1,5 @@ +{% extends "kolibri/base.html" %} +{% load webpack_tags %} +{% block content %} + {% webpack_asset 'kolibri.plugins.learn.my_downloads_app' %} +{% endblock %} From 01ffab47f1555673625f76fab7ae337c1e8ca222 Mon Sep 17 00:00:00 2001 From: Alex Velez Date: Tue, 7 Mar 2023 21:36:10 -0500 Subject: [PATCH 06/17] Set MyDownloadsPage as a Learn SPA --- kolibri/__init__.py | 1 - .../learn/assets/src/my_downloads/app.js | 3 - .../views/MyDownloadsSideNavEntry.vue | 2 +- kolibri/plugins/learn/kolibri_plugin.py | 5 + kolibri/plugins/learn/urls.py | 3 +- kolibri/plugins/learn/views.py | 5 + kolibri/plugins/my_downloads/__init__.py | 0 kolibri/plugins/my_downloads/api_urls.py | 1 - .../plugins/my_downloads/assets/src/app.js | 25 -- .../assets/src/modules/pluginModule.js | 21 -- .../plugins/my_downloads/assets/src/routes.js | 18 -- .../DownloadsList/ConfirmationDeleteModal.vue | 56 ----- .../PaginatedListContainerWithBackend.vue | 132 ----------- .../DownloadsList/SelectionBottomBar.vue | 64 ----- .../assets/src/views/DownloadsList/index.vue | 213 ----------------- .../assets/src/views/MyDownloads.vue | 219 ------------------ .../src/views/MyDownloadsSideNavEntry.vue | 40 ---- kolibri/plugins/my_downloads/buildConfig.js | 14 -- .../plugins/my_downloads/kolibri_plugin.py | 30 --- .../templates/my_downloads/my_downloads.html | 5 - kolibri/plugins/my_downloads/urls.py | 5 - kolibri/plugins/my_downloads/views.py | 13 -- kolibri/utils/build_config/default_plugins.py | 1 - 23 files changed, 13 insertions(+), 863 deletions(-) delete mode 100644 kolibri/plugins/my_downloads/__init__.py delete mode 100644 kolibri/plugins/my_downloads/api_urls.py delete mode 100644 kolibri/plugins/my_downloads/assets/src/app.js delete mode 100644 kolibri/plugins/my_downloads/assets/src/modules/pluginModule.js delete mode 100644 kolibri/plugins/my_downloads/assets/src/routes.js delete mode 100644 kolibri/plugins/my_downloads/assets/src/views/DownloadsList/ConfirmationDeleteModal.vue delete mode 100644 kolibri/plugins/my_downloads/assets/src/views/DownloadsList/PaginatedListContainerWithBackend.vue delete mode 100644 kolibri/plugins/my_downloads/assets/src/views/DownloadsList/SelectionBottomBar.vue delete mode 100644 kolibri/plugins/my_downloads/assets/src/views/DownloadsList/index.vue delete mode 100644 kolibri/plugins/my_downloads/assets/src/views/MyDownloads.vue delete mode 100644 kolibri/plugins/my_downloads/assets/src/views/MyDownloadsSideNavEntry.vue delete mode 100644 kolibri/plugins/my_downloads/buildConfig.js delete mode 100644 kolibri/plugins/my_downloads/kolibri_plugin.py delete mode 100644 kolibri/plugins/my_downloads/templates/my_downloads/my_downloads.html delete mode 100644 kolibri/plugins/my_downloads/urls.py delete mode 100644 kolibri/plugins/my_downloads/views.py diff --git a/kolibri/__init__.py b/kolibri/__init__.py index 0a940374b75..3deb29cf38c 100755 --- a/kolibri/__init__.py +++ b/kolibri/__init__.py @@ -35,7 +35,6 @@ "kolibri.plugins.facility", "kolibri.plugins.learn", "kolibri.plugins.media_player", - "kolibri.plugins.my_downloads", "kolibri.plugins.pdf_viewer", "kolibri.plugins.setup_wizard", "kolibri.plugins.slideshow_viewer", diff --git a/kolibri/plugins/learn/assets/src/my_downloads/app.js b/kolibri/plugins/learn/assets/src/my_downloads/app.js index 4b6a811a636..a1f41365667 100644 --- a/kolibri/plugins/learn/assets/src/my_downloads/app.js +++ b/kolibri/plugins/learn/assets/src/my_downloads/app.js @@ -15,9 +15,6 @@ class MyDownloadsModule extends KolibriApp { return pluginModule; } ready() { - // router.afterEach((toRoute, fromRoute) => { - // this.store.dispatch('resetModuleState', { toRoute, fromRoute }); - // }); super.ready(); } } diff --git a/kolibri/plugins/learn/assets/src/my_downloads/views/MyDownloadsSideNavEntry.vue b/kolibri/plugins/learn/assets/src/my_downloads/views/MyDownloadsSideNavEntry.vue index 82acc0c9d34..e3ac6429f0a 100644 --- a/kolibri/plugins/learn/assets/src/my_downloads/views/MyDownloadsSideNavEntry.vue +++ b/kolibri/plugins/learn/assets/src/my_downloads/views/MyDownloadsSideNavEntry.vue @@ -25,7 +25,7 @@ mixins: [commonCoreStrings], computed: { url() { - return urls['kolibri:kolibri.plugins.my_downloads:my_downloads'](); + return urls['kolibri:kolibri.plugins.learn:my_downloads'](); }, }, role: UserKinds.LEARNER, diff --git a/kolibri/plugins/learn/kolibri_plugin.py b/kolibri/plugins/learn/kolibri_plugin.py index 0bf8a4ddc23..707a00a0637 100644 --- a/kolibri/plugins/learn/kolibri_plugin.py +++ b/kolibri/plugins/learn/kolibri_plugin.py @@ -93,6 +93,11 @@ def plugin_data(self): } +@register_hook +class MyDownloadsAsset(webpack_hooks.WebpackBundleHook): + bundle_id = "my_downloads_app" + + @register_hook class LearnContentNodeHook(ContentNodeDisplayHook): def node_url(self, node): diff --git a/kolibri/plugins/learn/urls.py b/kolibri/plugins/learn/urls.py index e083610ad06..2e89a21203b 100644 --- a/kolibri/plugins/learn/urls.py +++ b/kolibri/plugins/learn/urls.py @@ -1,8 +1,9 @@ from django.conf.urls import url from .views import LearnView +from .views import MyDownloadsView urlpatterns = [ url(r"^$", LearnView.as_view(), name="learn"), - url(r"^my-downloads$", LearnView.as_view(), name="my_downloads"), + url(r"^my-downloads$", MyDownloadsView.as_view(), name="my_downloads"), ] diff --git a/kolibri/plugins/learn/views.py b/kolibri/plugins/learn/views.py index 2252442ffad..58539512af5 100644 --- a/kolibri/plugins/learn/views.py +++ b/kolibri/plugins/learn/views.py @@ -11,3 +11,8 @@ @method_decorator(cache_no_user_data, name="dispatch") class LearnView(TemplateView): template_name = "learn/learn.html" + + +@method_decorator(cache_no_user_data, name="dispatch") +class MyDownloadsView(TemplateView): + template_name = "learn/my_downloads.html" diff --git a/kolibri/plugins/my_downloads/__init__.py b/kolibri/plugins/my_downloads/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/kolibri/plugins/my_downloads/api_urls.py b/kolibri/plugins/my_downloads/api_urls.py deleted file mode 100644 index 637600f58aa..00000000000 --- a/kolibri/plugins/my_downloads/api_urls.py +++ /dev/null @@ -1 +0,0 @@ -urlpatterns = [] diff --git a/kolibri/plugins/my_downloads/assets/src/app.js b/kolibri/plugins/my_downloads/assets/src/app.js deleted file mode 100644 index 4b6a811a636..00000000000 --- a/kolibri/plugins/my_downloads/assets/src/app.js +++ /dev/null @@ -1,25 +0,0 @@ -// import router from 'kolibri.coreVue.router'; -import PageRoot from 'kolibri.coreVue.components.PageRoot'; -import routes from './routes'; -import pluginModule from './modules/pluginModule'; -import KolibriApp from 'kolibri_app'; - -class MyDownloadsModule extends KolibriApp { - get routes() { - return routes; - } - get RootVue() { - return PageRoot; - } - get pluginModule() { - return pluginModule; - } - ready() { - // router.afterEach((toRoute, fromRoute) => { - // this.store.dispatch('resetModuleState', { toRoute, fromRoute }); - // }); - super.ready(); - } -} - -export default new MyDownloadsModule(); diff --git a/kolibri/plugins/my_downloads/assets/src/modules/pluginModule.js b/kolibri/plugins/my_downloads/assets/src/modules/pluginModule.js deleted file mode 100644 index 35d1db353a4..00000000000 --- a/kolibri/plugins/my_downloads/assets/src/modules/pluginModule.js +++ /dev/null @@ -1,21 +0,0 @@ -export default { - state() { - return { - test: '', - }; - }, - actions: { - reset(store) { - store.commit('CORE_SET_PAGE_LOADING', false); - store.commit('CORE_SET_ERROR', null); - }, - resetModuleState(store) { - store.commit('profile/RESET_STATE'); - }, - }, - mutations: { - SET_Test(state, test) { - state.test = test; - }, - }, -}; diff --git a/kolibri/plugins/my_downloads/assets/src/routes.js b/kolibri/plugins/my_downloads/assets/src/routes.js deleted file mode 100644 index 9821d2ccfa2..00000000000 --- a/kolibri/plugins/my_downloads/assets/src/routes.js +++ /dev/null @@ -1,18 +0,0 @@ -import store from 'kolibri.coreVue.vuex.store'; -import redirectBrowser from 'kolibri.utils.redirectBrowser'; -import MyDownloadsPage from './views/MyDownloads'; - -export default [ - { - path: '/', - name: 'MY_DOWNLOADS', - component: MyDownloadsPage, - beforeEnter(to, from, next) { - if (!store.getters.isUserLoggedIn) { - redirectBrowser(); - } else { - next(); - } - }, - }, -]; diff --git a/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/ConfirmationDeleteModal.vue b/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/ConfirmationDeleteModal.vue deleted file mode 100644 index 50097e105e5..00000000000 --- a/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/ConfirmationDeleteModal.vue +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - diff --git a/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/PaginatedListContainerWithBackend.vue b/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/PaginatedListContainerWithBackend.vue deleted file mode 100644 index ea2ea1e08f7..00000000000 --- a/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/PaginatedListContainerWithBackend.vue +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - diff --git a/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/SelectionBottomBar.vue b/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/SelectionBottomBar.vue deleted file mode 100644 index b05f5984afb..00000000000 --- a/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/SelectionBottomBar.vue +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - diff --git a/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/index.vue b/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/index.vue deleted file mode 100644 index a8f36a38ac9..00000000000 --- a/kolibri/plugins/my_downloads/assets/src/views/DownloadsList/index.vue +++ /dev/null @@ -1,213 +0,0 @@ - - - - - - - diff --git a/kolibri/plugins/my_downloads/assets/src/views/MyDownloads.vue b/kolibri/plugins/my_downloads/assets/src/views/MyDownloads.vue deleted file mode 100644 index bdcf0824dee..00000000000 --- a/kolibri/plugins/my_downloads/assets/src/views/MyDownloads.vue +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - diff --git a/kolibri/plugins/my_downloads/assets/src/views/MyDownloadsSideNavEntry.vue b/kolibri/plugins/my_downloads/assets/src/views/MyDownloadsSideNavEntry.vue deleted file mode 100644 index 82acc0c9d34..00000000000 --- a/kolibri/plugins/my_downloads/assets/src/views/MyDownloadsSideNavEntry.vue +++ /dev/null @@ -1,40 +0,0 @@ - - - - diff --git a/kolibri/plugins/my_downloads/buildConfig.js b/kolibri/plugins/my_downloads/buildConfig.js deleted file mode 100644 index a8f741a300c..00000000000 --- a/kolibri/plugins/my_downloads/buildConfig.js +++ /dev/null @@ -1,14 +0,0 @@ -module.exports = [ - { - bundle_id: 'app', - webpack_config: { - entry: './assets/src/app.js', - }, - }, - { - bundle_id: 'my_downloads_side_nav', - webpack_config: { - entry: './assets/src/views/MyDownloadsSideNavEntry.vue', - }, - }, -]; diff --git a/kolibri/plugins/my_downloads/kolibri_plugin.py b/kolibri/plugins/my_downloads/kolibri_plugin.py deleted file mode 100644 index ca0f9cac092..00000000000 --- a/kolibri/plugins/my_downloads/kolibri_plugin.py +++ /dev/null @@ -1,30 +0,0 @@ -from __future__ import absolute_import -from __future__ import print_function -from __future__ import unicode_literals - -from kolibri.core.hooks import NavigationHook -from kolibri.core.webpack import hooks as webpack_hooks -from kolibri.plugins import KolibriPluginBase -from kolibri.plugins.hooks import register_hook -from kolibri.utils import translation -from kolibri.utils.translation import ugettext as _ - - -class MyDownloads(KolibriPluginBase): - translated_view_urls = "urls" - untranslated_view_urls = "api_urls" - can_manage_while_running = True - - def name(self, lang): - with translation.override(lang): - return _("My downloads") - - -@register_hook -class MyDownloadsAsset(webpack_hooks.WebpackBundleHook): - bundle_id = "app" - - -@register_hook -class MyDownloadsNavAction(NavigationHook): - bundle_id = "my_downloads_side_nav" diff --git a/kolibri/plugins/my_downloads/templates/my_downloads/my_downloads.html b/kolibri/plugins/my_downloads/templates/my_downloads/my_downloads.html deleted file mode 100644 index b210985254d..00000000000 --- a/kolibri/plugins/my_downloads/templates/my_downloads/my_downloads.html +++ /dev/null @@ -1,5 +0,0 @@ -{% extends "kolibri/base.html" %} -{% load webpack_tags %} -{% block content %} - {% webpack_asset 'kolibri.plugins.my_downloads.app' %} -{% endblock %} diff --git a/kolibri/plugins/my_downloads/urls.py b/kolibri/plugins/my_downloads/urls.py deleted file mode 100644 index 989147a9c23..00000000000 --- a/kolibri/plugins/my_downloads/urls.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.conf.urls import url - -from . import views - -urlpatterns = [url(r"^$", views.MyDownloadsView.as_view(), name="my_downloads")] diff --git a/kolibri/plugins/my_downloads/views.py b/kolibri/plugins/my_downloads/views.py deleted file mode 100644 index 5e221052663..00000000000 --- a/kolibri/plugins/my_downloads/views.py +++ /dev/null @@ -1,13 +0,0 @@ -from __future__ import absolute_import -from __future__ import print_function -from __future__ import unicode_literals - -from django.utils.decorators import method_decorator -from django.views.generic.base import TemplateView - -from kolibri.core.decorators import cache_no_user_data - - -@method_decorator(cache_no_user_data, name="dispatch") -class MyDownloadsView(TemplateView): - template_name = "my_downloads/my_downloads.html" diff --git a/kolibri/utils/build_config/default_plugins.py b/kolibri/utils/build_config/default_plugins.py index a513d70aeba..c2892a53e50 100644 --- a/kolibri/utils/build_config/default_plugins.py +++ b/kolibri/utils/build_config/default_plugins.py @@ -7,7 +7,6 @@ "kolibri.plugins.facility", "kolibri.plugins.learn", "kolibri.plugins.media_player", - "kolibri.plugins.my_downloads", "kolibri.plugins.pdf_viewer", "kolibri.plugins.perseus_viewer", "kolibri.plugins.setup_wizard", From 6cfd0e93ab388823be7b54b9faad688ee8fe346c Mon Sep 17 00:00:00 2001 From: Alex Velez Date: Tue, 7 Mar 2023 21:36:57 -0500 Subject: [PATCH 07/17] Connect composition api and show loading downloads --- .../src/composables/useDownloadRequests.js | 5 ++++- .../my_downloads/views/DownloadsList/index.vue | 5 +++++ .../src/my_downloads/views/MyDownloads.vue | 16 ++++++++++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/kolibri/plugins/learn/assets/src/composables/useDownloadRequests.js b/kolibri/plugins/learn/assets/src/composables/useDownloadRequests.js index 373335d5752..a8b5de54972 100644 --- a/kolibri/plugins/learn/assets/src/composables/useDownloadRequests.js +++ b/kolibri/plugins/learn/assets/src/composables/useDownloadRequests.js @@ -2,7 +2,7 @@ * A composable function containing logic related to download requests */ -import { getCurrentInstance, reactive } from 'kolibri.lib.vueCompositionApi'; +import { getCurrentInstance, reactive, ref } from 'kolibri.lib.vueCompositionApi'; import Vue from 'kolibri.lib.vue'; import { createTranslator } from 'kolibri.utils.i18n'; import { set } from '@vueuse/core'; @@ -28,6 +28,7 @@ const downloadRequestMap = reactive({}); export default function useDownloadRequests(store) { store = store || getCurrentInstance().proxy.$store; function fetchUserDownloadRequests() { + const loading = ref(true); const dummyDownloadRequests = [ { user_id: store.getters.currentUserId, @@ -46,6 +47,8 @@ export default function useDownloadRequests(store) { for (const req of dummyDownloadRequests) { set(downloadRequestMap, req.node_id, req); } + setTimeout(() => set(loading, false), 5000); + return loading; } function navigateToDownloads() {} diff --git a/kolibri/plugins/learn/assets/src/my_downloads/views/DownloadsList/index.vue b/kolibri/plugins/learn/assets/src/my_downloads/views/DownloadsList/index.vue index a8f36a38ac9..42d3d420b33 100644 --- a/kolibri/plugins/learn/assets/src/my_downloads/views/DownloadsList/index.vue +++ b/kolibri/plugins/learn/assets/src/my_downloads/views/DownloadsList/index.vue @@ -141,6 +141,11 @@ }, }, }, + watch: { + downloads(newVal) { + console.log('watch', newVal); + }, + }, methods: { selectAll() { this.allAreSelected = !this.allAreSelected; diff --git a/kolibri/plugins/learn/assets/src/my_downloads/views/MyDownloads.vue b/kolibri/plugins/learn/assets/src/my_downloads/views/MyDownloads.vue index bdcf0824dee..602f56f59f4 100644 --- a/kolibri/plugins/learn/assets/src/my_downloads/views/MyDownloads.vue +++ b/kolibri/plugins/learn/assets/src/my_downloads/views/MyDownloads.vue @@ -1,6 +1,9 @@ +

+ {{ coreString('noResourcesDownloaded') }} +

- + - - - -
{{ coreString('totalSizeMyDownloads', { size: '' }) }} {{ coreString('totalSizeMyDownloads') }} {{ formattedSize(storage.value.myDownloadsSize) }}
Total size of my library - {{ formattedSize(storage.value.myLibrarySize) }} -
{{ coreString('availableStorage') }} @@ -94,7 +87,7 @@ const query = computed(() => get(route).query); const pageNumber = computed(() => Number(query.value.page || 1)); - const pageSizeNumber = computed(() => Number(query.value.page_size || 30)); + const pageSizeNumber = computed(() => Number(query.value.page_size || 25)); const activityType = computed(() => query.value.activity || 'all'); const sort = computed(() => query.value.sort || 'newest'); From 680f1c4c683f6571819e38976f1b00c8ce4f1090 Mon Sep 17 00:00:00 2001 From: Alex Velez Date: Sun, 19 Mar 2023 09:38:31 -0500 Subject: [PATCH 17/17] Fix failing actions --- kolibri/__init__.py | 1 + .../src/composables/useDownloadRequests.js | 1 - .../src/composables/useLearningActivities.js | 19 +++++++++++++++ kolibri/plugins/learn/assets/src/constants.js | 23 ------------------- .../learn/assets/src/my_downloads/app.js | 1 - .../views/DownloadsList/index.vue | 14 ++++------- .../views/Filters/ActivityFilter.vue | 14 ++++++++--- kolibri/plugins/learn/kolibri_plugin.py | 1 + 8 files changed, 37 insertions(+), 37 deletions(-) diff --git a/kolibri/__init__.py b/kolibri/__init__.py index 411afc9b8ef..3deb29cf38c 100755 --- a/kolibri/__init__.py +++ b/kolibri/__init__.py @@ -40,4 +40,5 @@ "kolibri.plugins.slideshow_viewer", "kolibri.plugins.user_auth", "kolibri.plugins.user_profile", + "kolibri.plugins.policies", ] diff --git a/kolibri/plugins/learn/assets/src/composables/useDownloadRequests.js b/kolibri/plugins/learn/assets/src/composables/useDownloadRequests.js index bb474e0569c..7f03273491f 100644 --- a/kolibri/plugins/learn/assets/src/composables/useDownloadRequests.js +++ b/kolibri/plugins/learn/assets/src/composables/useDownloadRequests.js @@ -143,7 +143,6 @@ export default function useDownloadRequests(store) { contentList.forEach(content => { Vue.delete(downloadRequestMap.downloads, content.id); }); - console.log('downloadRequestMap', downloadRequestMap); return Promise.resolve(); } diff --git a/kolibri/plugins/learn/assets/src/composables/useLearningActivities.js b/kolibri/plugins/learn/assets/src/composables/useLearningActivities.js index 26b841a8f71..df4530c36c4 100644 --- a/kolibri/plugins/learn/assets/src/composables/useLearningActivities.js +++ b/kolibri/plugins/learn/assets/src/composables/useLearningActivities.js @@ -24,6 +24,16 @@ export default function useLearningActivities(contentNode) { [LearningActivities.EXPLORE]: coreStrings.$tr('explore'), }; + const _LearningActivityToIconMap = { + [LearningActivities.CREATE]: 'createSolid', + [LearningActivities.LISTEN]: 'listenSolid', + [LearningActivities.REFLECT]: 'reflectSolid', + [LearningActivities.PRACTICE]: 'practiceSolid', + [LearningActivities.READ]: 'readSolid', + [LearningActivities.WATCH]: 'watchSolid', + [LearningActivities.EXPLORE]: 'interactSolid', + }; + /** * @returns {Boolean} Does the content node have exactly * one learning activity associated with it? @@ -130,6 +140,14 @@ export default function useLearningActivities(contentNode) { return _LearningActivityToLabelMap[learningActivity]; } + /** + * @param {String} learningActivity A learning activity constant + * @returns {String} An icon for the learning activity + */ + function getLearningActivityIcon(learningActivity) { + return _LearningActivityToIconMap[learningActivity]; + } + return { ReferenceLabel, hasSingleActivity, @@ -141,5 +159,6 @@ export default function useLearningActivities(contentNode) { durationInSeconds, durationEstimation, getLearningActivityLabel, + getLearningActivityIcon, }; } diff --git a/kolibri/plugins/learn/assets/src/constants.js b/kolibri/plugins/learn/assets/src/constants.js index e186f7d0114..aab7ae367e2 100644 --- a/kolibri/plugins/learn/assets/src/constants.js +++ b/kolibri/plugins/learn/assets/src/constants.js @@ -1,6 +1,3 @@ -import { LearningActivities } from 'kolibri.coreVue.vuex.constants'; -import coreStrings from 'kolibri.utils.coreStrings'; - // a name for every URL pattern export const PageNames = { ROOT: 'ROOT', @@ -54,23 +51,3 @@ export const pageNameToModuleMap = { }; export const KolibriStudioId = 'kolibri-studio'; - -export const LearningActivityToIconMap = { - [LearningActivities.CREATE]: 'createSolid', - [LearningActivities.LISTEN]: 'listenSolid', - [LearningActivities.REFLECT]: 'reflectSolid', - [LearningActivities.PRACTICE]: 'practiceSolid', - [LearningActivities.READ]: 'readSolid', - [LearningActivities.WATCH]: 'watchSolid', - [LearningActivities.EXPLORE]: 'interactSolid', -}; - -export const LearningActivityToLabelMap = { - [LearningActivities.CREATE]: coreStrings.$tr('create'), - [LearningActivities.LISTEN]: coreStrings.$tr('listen'), - [LearningActivities.REFLECT]: coreStrings.$tr('reflect'), - [LearningActivities.PRACTICE]: coreStrings.$tr('practice'), - [LearningActivities.READ]: coreStrings.$tr('read'), - [LearningActivities.WATCH]: coreStrings.$tr('watch'), - [LearningActivities.EXPLORE]: coreStrings.$tr('explore'), -}; diff --git a/kolibri/plugins/learn/assets/src/my_downloads/app.js b/kolibri/plugins/learn/assets/src/my_downloads/app.js index a1f41365667..fee0caff293 100644 --- a/kolibri/plugins/learn/assets/src/my_downloads/app.js +++ b/kolibri/plugins/learn/assets/src/my_downloads/app.js @@ -1,4 +1,3 @@ -// import router from 'kolibri.coreVue.router'; import PageRoot from 'kolibri.coreVue.components.PageRoot'; import routes from './routes'; import pluginModule from './modules/pluginModule'; diff --git a/kolibri/plugins/learn/assets/src/my_downloads/views/DownloadsList/index.vue b/kolibri/plugins/learn/assets/src/my_downloads/views/DownloadsList/index.vue index 416d1629517..f73f9de434d 100644 --- a/kolibri/plugins/learn/assets/src/my_downloads/views/DownloadsList/index.vue +++ b/kolibri/plugins/learn/assets/src/my_downloads/views/DownloadsList/index.vue @@ -94,8 +94,8 @@ import CoreTable from 'kolibri.coreVue.components.CoreTable'; import commonCoreStrings from 'kolibri.coreVue.mixins.commonCoreStrings'; import PaginatedListContainerWithBackend from 'kolibri-common/components/PaginatedListContainerWithBackend'; - import { LearningActivityToIconMap } from '../../../constants'; import useContentLink from '../../../composables/useContentLink'; + import useLearningActivities from '../../../composables/useLearningActivities'; import SelectionBottomBar from './SelectionBottomBar.vue'; import ConfirmationDeleteModal from './ConfirmationDeleteModal.vue'; @@ -110,8 +110,10 @@ mixins: [commonCoreStrings], setup() { const { genExternalContentURLBackLinkCurrentPage } = useContentLink(); + const { getLearningActivityIcon } = useLearningActivities(); return { + getLearningActivityIcon, genExternalContentURLBackLinkCurrentPage, }; }, @@ -229,12 +231,12 @@ this.resourcesToDelete = []; }, getIcon(download) { - return LearningActivityToIconMap[download.resource_metadata.learning_activities[0]]; + return this.getLearningActivityIcon(download.resource_metadata.learning_activities[0]); }, formattedTime(download) { const datetime = download.date_added; if (this.now - datetime < 10000) { - return this.$tr('justNow'); + return this.coreString('justNow'); } return this.$formatRelative(datetime, { now: this.now }); }, @@ -245,12 +247,6 @@ return bytesForHumans(this.selectedDownloadsSize); }, }, - $trs: { - justNow: { - message: 'Just now', - context: 'This is used to indicate that a download was added to the list very recently', - }, - }, }; diff --git a/kolibri/plugins/learn/assets/src/my_downloads/views/Filters/ActivityFilter.vue b/kolibri/plugins/learn/assets/src/my_downloads/views/Filters/ActivityFilter.vue index f42c850460d..f89124708af 100644 --- a/kolibri/plugins/learn/assets/src/my_downloads/views/Filters/ActivityFilter.vue +++ b/kolibri/plugins/learn/assets/src/my_downloads/views/Filters/ActivityFilter.vue @@ -33,11 +33,19 @@ import { LearningActivities } from 'kolibri.coreVue.vuex.constants'; import commonCoreStrings from 'kolibri.coreVue.mixins.commonCoreStrings'; import responsiveWindowMixin from 'kolibri.coreVue.mixins.responsiveWindowMixin'; - import { LearningActivityToIconMap, LearningActivityToLabelMap } from '../../../constants'; + import useLearningActivities from '../../../composables/useLearningActivities'; export default { name: 'ActivityFilter', mixins: [commonCoreStrings, responsiveWindowMixin], + setup() { + const { getLearningActivityLabel, getLearningActivityIcon } = useLearningActivities(); + + return { + getLearningActivityLabel, + getLearningActivityIcon, + }; + }, data() { return { activityTypes: [ @@ -55,9 +63,9 @@ LearningActivities.CREATE, LearningActivities.EXPLORE, ].map(activity => ({ - label: LearningActivityToLabelMap[activity], + label: this.getLearningActivityLabel(activity), value: activity, - icon: LearningActivityToIconMap[activity], + icon: this.getLearningActivityIcon(activity), })), ], }; diff --git a/kolibri/plugins/learn/kolibri_plugin.py b/kolibri/plugins/learn/kolibri_plugin.py index 707a00a0637..0bd50ea1b98 100644 --- a/kolibri/plugins/learn/kolibri_plugin.py +++ b/kolibri/plugins/learn/kolibri_plugin.py @@ -151,6 +151,7 @@ def on_disconnect(self, network_location): for user_id in _learner_ids(): stop_request_soud_sync(network_location.base_url, user_id) + @register_hook class MyDownloadsNavAction(NavigationHook): bundle_id = "my_downloads_side_nav"