(str): name of method to execute
+ :param error_return_value --> (any): value to return if error occur
+ :param *args: positional arguments for method
+ :param *kwargs: keyword arguments for method
+ :return: The return value of the executed method if successful,
+ otherwise returns error_return_value
+ """
+ try:
+ method = getattr(super(CustomDjangoCache, self), method_name)
+ if method is None:
+ raise ValueError(
+ "{method_name} is not a valid method".format(
+ method_name=method_name
+ )
+ )
+ return method(*args, **kwargs)
+ except self.ERRORS_TO_HANDLE:
+ return error_return_value
+
def add(
self,
key,
@@ -23,12 +47,17 @@ def add(
tag=None,
retry=True,
):
- try:
- return super(CustomDjangoCache, self).add(
- key, value, timeout, version, read, tag, retry
- )
- except sqlite3.OperationalError:
- return False
+ return self.try_execute(
+ "add",
+ False,
+ key=key,
+ value=value,
+ timeout=timeout,
+ version=version,
+ read=read,
+ tag=tag,
+ retry=retry,
+ )
def has_key(self, key, version=None):
"""Returns True if the key is in the cache and has not expired.
@@ -38,12 +67,7 @@ def has_key(self, key, version=None):
:return: True if key is found
"""
- try:
- return super(CustomDjangoCache, self).has_key( # noqa: W601
- key, version=version
- )
- except sqlite3.OperationalError:
- return False
+ return self.try_execute("has_key", False, key=key, version=version)
def get(
self,
@@ -55,12 +79,17 @@ def get(
tag=False,
retry=False,
):
- try:
- return super(CustomDjangoCache, self).get(
- key, default, version, read, expire_time, tag, retry
- )
- except sqlite3.OperationalError:
- return None
+ return self.try_execute(
+ "get",
+ None,
+ key=key,
+ default=default,
+ version=version,
+ read=read,
+ expire_time=expire_time,
+ tag=tag,
+ retry=retry,
+ )
def set(
self,
@@ -72,95 +101,93 @@ def set(
tag=None,
retry=True,
):
- try:
- return super(CustomDjangoCache, self).set(
- key, value, timeout, version, read, tag, retry
- )
- except sqlite3.OperationalError:
- return False
+ return self.try_execute(
+ "set",
+ False,
+ key=key,
+ value=value,
+ timeout=timeout,
+ version=version,
+ read=read,
+ tag=tag,
+ retry=retry,
+ )
def touch(self, key, timeout=DEFAULT_TIMEOUT, version=None, retry=True):
- try:
- return super(CustomDjangoCache, self).touch(key, timeout, version, retry)
- except sqlite3.OperationalError:
- return False
+ return self.try_execute(
+ "touch",
+ False,
+ key=key,
+ timeout=timeout,
+ version=version,
+ retry=retry,
+ )
def pop(
self, key, default=None, version=None, expire_time=False, tag=False, retry=True
):
- try:
- return super(CustomDjangoCache, self).pop(
- key, default, version, expire_time, tag, retry
- )
- except sqlite3.OperationalError:
- return None
+ return self.try_execute(
+ "pop",
+ None,
+ key=key,
+ default=default,
+ version=version,
+ expire_time=expire_time,
+ tag=tag,
+ retry=retry,
+ )
def delete(self, key, version=None, retry=True):
- try:
- super(CustomDjangoCache, self).delete(key, version, retry)
- except sqlite3.OperationalError:
- pass
+ self.try_execute(
+ "delete",
+ None,
+ key=key,
+ version=version,
+ retry=retry,
+ )
def incr(self, key, delta=1, version=None, default=None, retry=True):
- try:
- return super(CustomDjangoCache, self).incr(
- key, delta, version, default, retry
- )
- except sqlite3.OperationalError:
- return None
+ return self.try_execute(
+ "incr",
+ None,
+ key=key,
+ delta=delta,
+ version=version,
+ default=default,
+ retry=retry,
+ )
def decr(self, key, delta=1, version=None, default=None, retry=True):
- try:
- return super(CustomDjangoCache, self).decr(
- key, delta, version, default, retry
- )
- except sqlite3.OperationalError:
- return None
+ return self.try_execute(
+ "decr",
+ None,
+ key=key,
+ delta=delta,
+ version=version,
+ default=default,
+ retry=retry,
+ )
def expire(self, retry=False):
- try:
- return super(CustomDjangoCache, self).expire(retry)
- except sqlite3.OperationalError:
- return 0
+ return self.try_execute("expire", 0, retry=retry)
def stats(self, enable=True, reset=False):
- try:
- return super(CustomDjangoCache, self).stats(enable, reset)
- except sqlite3.OperationalError:
- return 0, 0
+ return self.try_execute("stats", (0, 0), enable=enable, reset=reset)
def create_tag_index(self):
- try:
- super(CustomDjangoCache, self).create_tag_index()
- except sqlite3.OperationalError:
- pass
+ return self.try_execute("create_tag_index", None)
def drop_tag_index(self):
- try:
- super(CustomDjangoCache, self).drop_tag_index()
- except sqlite3.OperationalError:
- pass
+ return self.try_execute("drop_tag_index", None)
def evict(self, tag):
- try:
- return super(CustomDjangoCache, self).evict(tag)
- except sqlite3.OperationalError:
- return 0
+ return self.try_execute("evict", 0, tag=tag)
def cull(self):
- try:
- return super(CustomDjangoCache, self).cull()
- except sqlite3.OperationalError:
- return 0
+ return self.try_execute("cull", 0)
def clear(self):
- try:
- return super(CustomDjangoCache, self).clear()
- except sqlite3.OperationalError:
- return 0
+ return self.try_execute("clear", 0)
def close(self, **kwargs):
- try:
- super(CustomDjangoCache, self).close(**kwargs)
- except sqlite3.OperationalError:
- pass
+ return self.try_execute("close", None, **kwargs)
diff --git a/kolibri/plugins/coach/assets/src/app.js b/kolibri/plugins/coach/assets/src/app.js
index 8eaf764fbb..7fc73dbec7 100644
--- a/kolibri/plugins/coach/assets/src/app.js
+++ b/kolibri/plugins/coach/assets/src/app.js
@@ -3,7 +3,6 @@ import useUser from 'kolibri.coreVue.composables.useUser';
import redirectBrowser from 'kolibri.utils.redirectBrowser';
import { setChannelInfo } from 'kolibri.coreVue.vuex.actions';
import router from 'kolibri.coreVue.router';
-import PageRoot from 'kolibri.coreVue.components.PageRoot';
import KolibriApp from 'kolibri_app';
import { PageNames } from './constants';
import routes from './routes';
@@ -21,9 +20,6 @@ class CoachToolsModule extends KolibriApp {
get routes() {
return routes;
}
- get RootVue() {
- return PageRoot;
- }
get pluginModule() {
return pluginModule;
}
diff --git a/kolibri/plugins/learn/assets/src/app.js b/kolibri/plugins/learn/assets/src/app.js
index 4f11411117..0634d4314a 100644
--- a/kolibri/plugins/learn/assets/src/app.js
+++ b/kolibri/plugins/learn/assets/src/app.js
@@ -43,7 +43,6 @@ class LearnModule extends KolibriApp {
// after every navigation, block double-clicks
router.afterEach((toRoute, fromRoute) => {
- this.store.dispatch('blockDoubleClicks');
this.store.dispatch('resetModuleState', { toRoute, fromRoute });
});
super.ready();
diff --git a/kolibri/plugins/learn/assets/src/my_downloads/app.js b/kolibri/plugins/learn/assets/src/my_downloads/app.js
index 49bae640f2..41d208ccf3 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 PageRoot from 'kolibri.coreVue.components.PageRoot';
import KolibriApp from 'kolibri_app';
import routes from './routes';
import pluginModule from './modules/pluginModule';
@@ -7,9 +6,6 @@ class MyDownloadsModule extends KolibriApp {
get routes() {
return routes;
}
- get RootVue() {
- return PageRoot;
- }
get pluginModule() {
return 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 4bbfdb6e4b..6cf577e87e 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
@@ -63,10 +63,13 @@
:color="download.status === 'PENDING' ? $themeTokens.annotation : null"
class="icon"
/>
-
+
+
+
{{ formattedDownloadStatus(download) }}
@@ -83,10 +86,13 @@
:color="download.status === 'PENDING' ? $themeTokens.annotation : null"
class="icon"
/>
-
+
+
+
{{ formattedDownloadStatus(download) }}
@@ -425,8 +431,14 @@
}
.small-screen-status {
- margin: 0 48px;
+ margin: 0 0 0 48px;
font-size: 12px;
}
+ .inline-loader {
+ display: inline-block;
+ margin-left: 0;
+ vertical-align: bottom;
+ }
+
diff --git a/kolibri/plugins/learn/assets/src/views/LibraryPage/index.vue b/kolibri/plugins/learn/assets/src/views/LibraryPage/index.vue
index aacf98e5ba..f28bc48de0 100644
--- a/kolibri/plugins/learn/assets/src/views/LibraryPage/index.vue
+++ b/kolibri/plugins/learn/assets/src/views/LibraryPage/index.vue
@@ -458,11 +458,11 @@
}
},
gridOffset() {
- const marginTop =
+ const paddingTop =
!this.windowIsLarge && (this.isLocalLibraryEmpty || this.deviceId) ? '140px' : '110px';
return this.isRtl
- ? { marginRight: `${this.sidePanelWidth + 24}px`, marginTop }
- : { marginLeft: `${this.sidePanelWidth + 24}px`, marginTop };
+ ? { paddingRight: `${this.sidePanelWidth + 24}px`, paddingTop }
+ : { paddingLeft: `${this.sidePanelWidth + 24}px`, paddingTop };
},
sidePanelWidth() {
if (
@@ -605,9 +605,9 @@
}
.main-grid {
- margin-top: 110px;
- margin-right: 24px;
- margin-bottom: 96px;
+ padding-top: 110px;
+ padding-right: 24px;
+ padding-bottom: 96px;
}
.channels-label {
diff --git a/kolibri/plugins/learn/assets/src/views/TopicsContentPage.vue b/kolibri/plugins/learn/assets/src/views/TopicsContentPage.vue
index b1a8e18001..875293ff54 100644
--- a/kolibri/plugins/learn/assets/src/views/TopicsContentPage.vue
+++ b/kolibri/plugins/learn/assets/src/views/TopicsContentPage.vue
@@ -5,8 +5,6 @@
class="main-wrapper"
>
-
-
state.core.error,
- blockDoubleClicks: state => state.core.blockDoubleClicks,
}),
isCoachContent() {
return this.content && this.content.coach_content ? 1 : 0;
@@ -734,15 +731,6 @@
outline-style: none !important;
}
- .click-mask {
- position: fixed;
- top: 0;
- left: 0;
- z-index: 24;
- width: 100%;
- height: 100%;
- }
-
.loader {
position: fixed;
right: 0;
diff --git a/kolibri/plugins/pdf_viewer/assets/src/views/PdfRendererIndex.vue b/kolibri/plugins/pdf_viewer/assets/src/views/PdfRendererIndex.vue
index 1f3599e7da..07fdbc8dff 100644
--- a/kolibri/plugins/pdf_viewer/assets/src/views/PdfRendererIndex.vue
+++ b/kolibri/plugins/pdf_viewer/assets/src/views/PdfRendererIndex.vue
@@ -84,11 +84,11 @@
:layout8="{ span: showSideBar ? 6 : 8 }"
:layout12="{ span: showSideBar ? 9 : 12 }"
>
-
-
+
@@ -123,8 +123,6 @@
import throttle from 'lodash/throttle';
import debounce from 'lodash/debounce';
import logger from 'kolibri.lib.logging';
- import { RecycleList } from 'vue-virtual-scroller';
- import 'vue-virtual-scroller/dist/vue-virtual-scroller.css';
// polyfill necessary for recycle list
import 'intersection-observer';
import commonCoreStrings from 'kolibri.coreVue.mixins.commonCoreStrings';
@@ -132,6 +130,7 @@
import CoreFullscreen from 'kolibri.coreVue.components.CoreFullscreen';
import '../utils/domPolyfills';
import { EventBus } from '../utils/event_utils';
+ import RecyclableScroller from './RecyclableScroller';
import PdfPage from './PdfPage';
import SideBar from './SideBar';
@@ -146,8 +145,8 @@
components: {
SideBar,
PdfPage,
- RecycleList,
CoreFullscreen,
+ RecyclableScroller,
},
mixins: [commonCoreStrings],
setup() {
@@ -296,42 +295,38 @@
};
this.eventBus = new EventBus();
this.prepComponentData = loadingPdf.promise
- .then(pdfDocument => {
+ .then(async pdfDocument => {
// Get initial info from the loaded pdf document
this.pdfDocument = pdfDocument;
this.totalPages = this.pdfDocument.numPages;
+ // Is either the first page or the saved last page visited
+ const firstPageToRender = parseInt(this.getSavedPosition() * this.totalPages);
+
+ const firstPage = await this.getPage(firstPageToRender + 1);
+ const viewPort = firstPage.getViewport({ scale: 1 });
+ this.firstPageHeight = viewPort.height;
+ this.firstPageWidth = viewPort.width;
+ this.scale = this.$el.clientWidth / (this.firstPageWidth * this.screenSizeMultiplier);
+
// init pdfPages array
+ // ensuring that firstPageToRender is resolved so that we do not refetch the page
for (let i = 0; i < this.totalPages; i++) {
this.pdfPages.push({
- page: null,
- resolved: false,
+ page: i == firstPageToRender ? firstPage : null,
+ resolved: i == firstPageToRender,
+ size: () => {
+ return this.firstPageHeight * this.scale + MARGIN;
+ },
index: i,
});
}
- // Is either the first page or the saved last page visited
- const firstPageToRender = parseInt(this.getSavedPosition() * this.totalPages);
- return this.getPage(firstPageToRender + 1).then(firstPage => {
- const viewPort = firstPage.getViewport({ scale: 1 });
- this.firstPageHeight = viewPort.height;
- this.firstPageWidth = viewPort.width;
- this.scale = this.$el.clientWidth / (this.firstPageWidth * this.screenSizeMultiplier);
-
- // Set the firstPageToRender into the pdfPages object so that we do not refetch the page
- // from PDFJS when we do our initial render
- // splice so changes are detected
- this.pdfPages.splice(firstPageToRender, 1, {
- ...this.pdfPages[firstPageToRender],
- page: firstPage,
- resolved: true,
- });
- pdfDocument.getOutline().then(outline => {
- this.outline = outline;
- this.showSideBar = outline && outline.length > 0 && this.windowIsLarge; // Remove if other tabs are already implemented
- // Reduce the scale slightly if we are showing the sidebar
- // at first load.
- this.scale = this.showSideBar ? 0.75 * this.scale : this.scale;
- });
- });
+
+ const outline = await pdfDocument.getOutline();
+ this.outline = outline;
+ this.showSideBar = outline && outline.length > 0 && this.windowIsLarge; // Remove if other tabs are already implemented
+ // Reduce the scale slightly if we are showing the sidebar
+ // at first load.
+ this.scale = this.showSideBar ? 0.75 * this.scale : this.scale;
})
.catch(error => {
this.reportLoadingError(error);
@@ -379,11 +374,16 @@
if (pageNum > 0 && pageNum <= this.totalPages && !this.pdfPages[pageNum - 1].resolved) {
const pageIndex = pageNum - 1;
this.getPage(pageNum).then(pdfPage => {
+ const { height } = pdfPage.getViewport({ scale: 1 });
+
// splice so changes are detected
this.pdfPages.splice(pageIndex, 1, {
...this.pdfPages[pageIndex],
page: pdfPage,
resolved: true,
+ size: () => {
+ return height * this.scale + MARGIN;
+ },
});
});
}
@@ -703,8 +703,8 @@
margin: 0 auto;
}
// enable horizontal scrolling
- /deep/ .recycle-list {
- .item-wrapper {
+ /deep/ .vue-recycle-scroller {
+ .vue-recycle-scroller-item-wrapper {
overflow-x: auto;
}
}
@@ -748,4 +748,19 @@
height: 100%;
}
+ /deep/ .resize-observer {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: -1;
+ display: block;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ pointer-events: none;
+ background-color: transparent;
+ border: 0;
+ opacity: 0;
+ }
+
diff --git a/kolibri/plugins/pdf_viewer/assets/src/views/RecyclableScroller.vue b/kolibri/plugins/pdf_viewer/assets/src/views/RecyclableScroller.vue
new file mode 100644
index 0000000000..308e89a50a
--- /dev/null
+++ b/kolibri/plugins/pdf_viewer/assets/src/views/RecyclableScroller.vue
@@ -0,0 +1,887 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/kolibri/plugins/pdf_viewer/package.json b/kolibri/plugins/pdf_viewer/package.json
index 14b2e9dc31..764765a6c1 100644
--- a/kolibri/plugins/pdf_viewer/package.json
+++ b/kolibri/plugins/pdf_viewer/package.json
@@ -6,7 +6,7 @@
"dependencies": {
"intersection-observer": "0.12.2",
"pdfjs-dist": "^2.16.105",
- "vue-virtual-scroller": "0.12.0",
+ "vue-virtual-scroller": "1.1.2",
"web-streams-polyfill": "^4.0.0"
}
}
diff --git a/kolibri/plugins/policies/assets/src/app.js b/kolibri/plugins/policies/assets/src/app.js
index b48824c7f2..08912ebb37 100644
--- a/kolibri/plugins/policies/assets/src/app.js
+++ b/kolibri/plugins/policies/assets/src/app.js
@@ -1,4 +1,3 @@
-import PageRoot from 'kolibri.coreVue.components.PageRoot';
import routes from './routes';
import pluginModule from './modules/pluginModule';
import KolibriApp from 'kolibri_app';
@@ -7,9 +6,6 @@ class PoliciesModule extends KolibriApp {
get routes() {
return routes;
}
- get RootVue() {
- return PageRoot;
- }
get pluginModule() {
return pluginModule;
}
diff --git a/kolibri/plugins/setup_wizard/assets/src/views/onboarding-forms/DefaultLanguageForm.vue b/kolibri/plugins/setup_wizard/assets/src/views/onboarding-forms/DefaultLanguageForm.vue
index ef1854ca6c..24cda2f506 100644
--- a/kolibri/plugins/setup_wizard/assets/src/views/onboarding-forms/DefaultLanguageForm.vue
+++ b/kolibri/plugins/setup_wizard/assets/src/views/onboarding-forms/DefaultLanguageForm.vue
@@ -1,10 +1,12 @@
-
+
@@ -21,11 +23,41 @@
OnboardingStepBase,
LanguageSwitcherList,
},
+ data() {
+ return {
+ parentBreakpoint: 4,
+ };
+ },
+ mounted() {
+ this.updateWidth();
+ window.addEventListener('resize', this.updateWidth);
+ },
+ beforeDestroy() {
+ window.removeEventListener('resize', this.updateWidth);
+ },
inject: ['wizardService'],
methods: {
handleSubmit() {
this.wizardService.send('CONTINUE');
},
+ updateWidth() {
+ const element = this.$refs.container.$el;
+ const width = element.offsetWidth;
+ let num = 4;
+
+ if (width < 440) {
+ num = 0;
+ } else if (width < 520) {
+ num = 1;
+ } else if (width < 600) {
+ num = 2;
+ } else if (width < 660) {
+ num = 3;
+ } else {
+ num = 4;
+ }
+ this.parentBreakpoint = num;
+ },
},
$trs: {
languageFormHeader: {
diff --git a/kolibri/plugins/user_auth/assets/src/views/SignInPage/index.vue b/kolibri/plugins/user_auth/assets/src/views/SignInPage/index.vue
index 0c3d19daf0..6c04e1511f 100644
--- a/kolibri/plugins/user_auth/assets/src/views/SignInPage/index.vue
+++ b/kolibri/plugins/user_auth/assets/src/views/SignInPage/index.vue
@@ -339,6 +339,7 @@
// and forth
this.usernameBlurred = false;
this.passwordBlurred = false;
+ this.usernameSubmittedWithoutPassword = false;
this.loginError = null;
},
// Sets the selected list user and/or logs them in
diff --git a/kolibri/plugins/user_auth/assets/src/views/UserAuthLayout.vue b/kolibri/plugins/user_auth/assets/src/views/UserAuthLayout.vue
index fbdb18373c..bac2199e5e 100644
--- a/kolibri/plugins/user_auth/assets/src/views/UserAuthLayout.vue
+++ b/kolibri/plugins/user_auth/assets/src/views/UserAuthLayout.vue
@@ -6,8 +6,6 @@
:style="mainWrapperStyles"
>
-
-
state.core.error,
loading: state => state.core.loading,
- blockDoubleClicks: state => state.core.blockDoubleClicks,
}),
isAuthorized() {
return !(
@@ -168,15 +165,6 @@
overflow-x: auto;
}
- .click-mask {
- position: fixed;
- top: 0;
- left: 0;
- z-index: 24;
- width: 100%;
- height: 100%;
- }
-
.debug {
font-family: monospace;
font-size: large;
diff --git a/kolibri/plugins/user_profile/assets/src/app.js b/kolibri/plugins/user_profile/assets/src/app.js
index 0fce9ef7fb..522dd1aa59 100644
--- a/kolibri/plugins/user_profile/assets/src/app.js
+++ b/kolibri/plugins/user_profile/assets/src/app.js
@@ -1,5 +1,4 @@
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';
@@ -8,9 +7,6 @@ class UserProfileModule extends KolibriApp {
get routes() {
return routes;
}
- get RootVue() {
- return PageRoot;
- }
get pluginModule() {
return pluginModule;
}
diff --git a/kolibri/utils/conf.py b/kolibri/utils/conf.py
index 1b86834c21..e6eb04500c 100644
--- a/kolibri/utils/conf.py
+++ b/kolibri/utils/conf.py
@@ -25,6 +25,7 @@
#: Absolute path of the main user data directory.
#: Will be created automatically if it doesn't exist.
KOLIBRI_HOME = os.path.abspath(os.path.expanduser(os.environ["KOLIBRI_HOME"]))
+NO_FILE_BASED_LOGGING = os.environ.get("KOLIBRI_NO_FILE_BASED_LOGGING", False)
# Creating KOLIBRI_HOME atm. has to happen here as for instance utils.cli is not
# called through py.test. This file is the first basic entry point of
@@ -39,7 +40,7 @@
# Create a folder named logs inside KOLIBRI_HOME to store all the log files.
LOG_ROOT = os.path.join(KOLIBRI_HOME, "logs")
-if not os.path.exists(LOG_ROOT):
+if not os.path.exists(LOG_ROOT) and not NO_FILE_BASED_LOGGING:
os.mkdir(LOG_ROOT)
diff --git a/kolibri/utils/logger.py b/kolibri/utils/logger.py
index fcfa1688a5..d8c0ba68c9 100644
--- a/kolibri/utils/logger.py
+++ b/kolibri/utils/logger.py
@@ -205,6 +205,43 @@ def get_default_logging_config(LOG_ROOT, debug=False, debug_database=False):
DEFAULT_LEVEL = "INFO" if not debug else "DEBUG"
DATABASE_LEVEL = "INFO" if not debug_database else "DEBUG"
+ handlers = {
+ "console-error": {
+ "level": "ERROR",
+ "class": "kolibri.utils.logger.EncodingStreamHandler",
+ "formatter": "color",
+ "stream": "ext://sys.stderr",
+ },
+ "console": {
+ "level": DEFAULT_LEVEL,
+ "filters": ["no_exceptions"],
+ "class": "kolibri.utils.logger.EncodingStreamHandler",
+ "formatter": "color",
+ "stream": "ext://sys.stdout",
+ },
+ }
+
+ if not NO_FILE_BASED_LOGGING:
+ handlers["file"] = {
+ "level": "INFO",
+ "filters": [],
+ "class": "kolibri.utils.logger.KolibriTimedRotatingFileHandler",
+ "filename": os.path.join(LOG_ROOT, "kolibri.txt"),
+ "formatter": "simple_date",
+ "when": "midnight",
+ "backupCount": 30,
+ "encoding": "utf-8",
+ }
+
+ handlers["file_debug"] = {
+ "level": "DEBUG",
+ "filters": ["require_debug_true"],
+ "class": "logging.FileHandler",
+ "filename": os.path.join(LOG_ROOT, "debug.txt"),
+ "formatter": "simple_date",
+ "encoding": "utf-8",
+ }
+
return {
"version": 1,
"disable_existing_loggers": False,
@@ -223,39 +260,7 @@ def get_default_logging_config(LOG_ROOT, debug=False, debug_database=False):
"log_colors": LOG_COLORS,
},
},
- "handlers": {
- "console-error": {
- "level": "ERROR",
- "class": "kolibri.utils.logger.EncodingStreamHandler",
- "formatter": "color",
- "stream": "ext://sys.stderr",
- },
- "console": {
- "level": DEFAULT_LEVEL,
- "filters": ["no_exceptions"],
- "class": "kolibri.utils.logger.EncodingStreamHandler",
- "formatter": "color",
- "stream": "ext://sys.stdout",
- },
- "file": {
- "level": "INFO",
- "filters": [],
- "class": "kolibri.utils.logger.KolibriTimedRotatingFileHandler",
- "filename": os.path.join(LOG_ROOT, "kolibri.txt"),
- "formatter": "simple_date",
- "when": "midnight",
- "backupCount": 30,
- "encoding": "utf-8",
- },
- "file_debug": {
- "level": "DEBUG",
- "filters": ["require_debug_true"],
- "class": "logging.FileHandler",
- "filename": os.path.join(LOG_ROOT, "debug.txt"),
- "formatter": "simple_date",
- "encoding": "utf-8",
- },
- },
+ "handlers": handlers,
"loggers": {
"": {
"handlers": DEFAULT_HANDLERS,
diff --git a/packages/browserslist-config-kolibri/package.json b/packages/browserslist-config-kolibri/package.json
index 284b10b055..cdeeac9898 100644
--- a/packages/browserslist-config-kolibri/package.json
+++ b/packages/browserslist-config-kolibri/package.json
@@ -1,6 +1,6 @@
{
"name": "browserslist-config-kolibri",
- "version": "0.16.0-dev.7",
+ "version": "0.16.1-dev.1",
"description": "Browsers list configuration for Kolibri",
"main": "index.js",
"repository": "github.com/learningequality/kolibri",
diff --git a/packages/eslint-plugin-kolibri/package.json b/packages/eslint-plugin-kolibri/package.json
index 97bd968e82..66a53df236 100644
--- a/packages/eslint-plugin-kolibri/package.json
+++ b/packages/eslint-plugin-kolibri/package.json
@@ -1,6 +1,6 @@
{
"name": "eslint-plugin-kolibri",
- "version": "0.16.0-dev.7",
+ "version": "0.16.1-dev.1",
"description": "Custom rules.",
"author": "Learning Equality",
"main": "lib/index.js",
diff --git a/packages/kolibri-common/components/MeteredConnectionNotificationModal.vue b/packages/kolibri-common/components/MeteredConnectionNotificationModal.vue
index e4d498d016..3943f77a03 100644
--- a/packages/kolibri-common/components/MeteredConnectionNotificationModal.vue
+++ b/packages/kolibri-common/components/MeteredConnectionNotificationModal.vue
@@ -90,8 +90,8 @@
// if we only include one of the keys for the extra_settings object
client({ method: 'GET', url: this.settingsUrl })
.then(({ data }) => {
- logging.log('mounted', isMetered);
- logging.log(data);
+ logging.info('mounted', isMetered);
+ logging.info(data);
this.extra_settings = data.extra_settings;
this.selected = this.extra_settings.allow_download_on_metered_connection
? Options.USE_METERED
diff --git a/packages/kolibri-core-for-export/package.json b/packages/kolibri-core-for-export/package.json
index fbb843b419..7836906168 100644
--- a/packages/kolibri-core-for-export/package.json
+++ b/packages/kolibri-core-for-export/package.json
@@ -1,6 +1,6 @@
{
"name": "kolibri",
- "version": "0.16.0-dev.7",
+ "version": "0.16.1-dev.1",
"description": "The Kolibri core API",
"repository": "github.com/learningequality/kolibri",
"author": "Learning Equality",
@@ -33,7 +33,7 @@
"screenfull": "^5.2.0",
"tinycolor2": "^1.6.0",
"ua-parser-js": "^1.0.37",
- "vue": "^2.6.14",
+ "vue": "2.6.14",
"vue-intl": "3.1.0",
"vue-meta": "^2.4.0",
"vue-router": "^3.6.5",
diff --git a/packages/kolibri-tools/lib/cli.js b/packages/kolibri-tools/lib/cli.js
index 67788c24eb..5a7b161a2d 100755
--- a/packages/kolibri-tools/lib/cli.js
+++ b/packages/kolibri-tools/lib/cli.js
@@ -287,6 +287,10 @@ program
}
if (options.watchonly.length) {
const unwatchedBundles = [];
+ // Watch core for changes if KDS option is provided; all KDS components are linked to core.
+ if (options.requireKdsPath && !options.watchonly.includes('core')) {
+ options.watchonly.push('core');
+ }
const findModuleName = bundleDatum => {
return !options.watchonly.some(m => bundleDatum.module_path.includes(m));
};
@@ -366,7 +370,7 @@ program
const Minimatch = require('minimatch').Minimatch;
patternCheck = new Minimatch(options.pattern, {});
}
- const glob = require('glob');
+ const glob = require('./glob');
const { logging, lint, noChange } = require('./lint');
const chokidar = require('chokidar');
const watchMode = options.monitor;
@@ -457,7 +461,7 @@ program
if (!files.length) {
program.command('compress').help();
} else {
- const glob = require('glob');
+ const glob = require('./glob');
const compressFile = require('./compress');
Promise.all(
files.map(file => {
diff --git a/packages/kolibri-tools/lib/glob.js b/packages/kolibri-tools/lib/glob.js
new file mode 100644
index 0000000000..671527aa65
--- /dev/null
+++ b/packages/kolibri-tools/lib/glob.js
@@ -0,0 +1,35 @@
+const fastGlob = require('fast-glob');
+
+const defaultOptions = {
+ ignore: [],
+ expandDirectories: true,
+ braceExpansion: true,
+ dot: false,
+ extglob: true,
+ globstar: true,
+ caseSensitiveMatch: true,
+};
+
+/**
+ * Small wrapper around glob dependency to make it easier to switch to a different library
+ */
+module.exports = {
+ /**
+ * Synchronously search for files that match a glob pattern
+ * @param {string|string[]} globPaths
+ * @param {object} options - see fast-glob options
+ * @returns {string[]}
+ */
+ sync(globPaths, options = {}) {
+ if (Array.isArray(globPaths)) {
+ globPaths = [...new Set(globPaths)];
+ } else {
+ globPaths = [globPaths];
+ }
+
+ return fastGlob.sync(globPaths, {
+ ...defaultOptions,
+ ...options,
+ });
+ },
+};
diff --git a/packages/kolibri-tools/lib/i18n/SyncContext.js b/packages/kolibri-tools/lib/i18n/SyncContext.js
index 527b571534..87014e84e9 100644
--- a/packages/kolibri-tools/lib/i18n/SyncContext.js
+++ b/packages/kolibri-tools/lib/i18n/SyncContext.js
@@ -1,10 +1,10 @@
// Import packages
const fs = require('fs');
const path = require('path');
-const glob = require('glob');
const traverse = require('ast-traverse');
const get = require('lodash/get');
const vueCompiler = require('vue-template-compiler');
+const glob = require('../glob');
const logging = require('../logging');
const { insertContent } = require('../vueTools');
const {
diff --git a/packages/kolibri-tools/lib/i18n/astUtils.js b/packages/kolibri-tools/lib/i18n/astUtils.js
index 308e1d84c8..5a0540a262 100644
--- a/packages/kolibri-tools/lib/i18n/astUtils.js
+++ b/packages/kolibri-tools/lib/i18n/astUtils.js
@@ -8,7 +8,7 @@ const get = require('lodash/get');
const isPlainObject = require('lodash/isPlainObject');
const isString = require('lodash/isString');
const isArray = require('lodash/isArray');
-const { glob } = require('glob');
+const glob = require('../glob');
const logging = require('../logging');
const { resolve } = require('../alias_import_resolver');
const { CONTEXT_LINE } = require('./constants');
diff --git a/packages/kolibri-tools/lib/i18n/utils.js b/packages/kolibri-tools/lib/i18n/utils.js
index f82ef57b3c..912aea9c7e 100644
--- a/packages/kolibri-tools/lib/i18n/utils.js
+++ b/packages/kolibri-tools/lib/i18n/utils.js
@@ -1,10 +1,10 @@
const fs = require('fs');
const path = require('path');
-const glob = require('glob');
const intersection = require('lodash/intersection');
const { parse } = require('csv-parse/sync');
const { lint } = require('kolibri-tools/lib/lint');
const { addAliases, resetAliases } = require('kolibri-tools/lib/alias_import_resolver');
+const glob = require('../glob');
const logging = require('../logging');
/*
diff --git a/packages/kolibri-tools/package.json b/packages/kolibri-tools/package.json
index 984394b3e2..cdf9bbd226 100644
--- a/packages/kolibri-tools/package.json
+++ b/packages/kolibri-tools/package.json
@@ -1,6 +1,6 @@
{
"name": "kolibri-tools",
- "version": "0.16.0-dev.7",
+ "version": "0.16.1-dev.1",
"description": "Tools for building Kolibri frontend plugins",
"main": "lib/cli.js",
"repository": "github.com/learningequality/kolibri",
@@ -24,7 +24,7 @@
"babel-core": "7.0.0-bridge.0",
"babel-jest": "^29.7.0",
"babel-loader": "^9.1.3",
- "browserslist-config-kolibri": "0.16.0-dev.7",
+ "browserslist-config-kolibri": "0.16.1-dev.1",
"chalk": "4.1.2",
"check-node-version": "^4.2.1",
"chokidar": "^3.6.0",
@@ -42,13 +42,13 @@
"eslint-config-vue": "^2.0.2",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jest": "^23.3.0",
- "eslint-plugin-kolibri": "0.16.0-dev.7",
+ "eslint-plugin-kolibri": "0.16.1-dev.1",
"eslint-plugin-jest-dom": "^5.1.0",
"eslint-plugin-vue": "^7.3.0",
"espree": "10.0.1",
"esquery": "^1.5.0",
"express": "^4.18.3",
- "glob": "^10.3.10",
+ "fast-glob": "^3.3.2",
"htmlhint": "^1.1.4",
"ini": "^4.1.2",
"jest": "^29.7.0",
@@ -89,7 +89,7 @@
"vue-jest": "^3.0.0",
"vue-loader": "^15.11.1",
"vue-style-loader": "^4.1.3",
- "vue-template-compiler": "^2.6.11",
+ "vue-template-compiler": "2.6.14",
"webpack": "^5.90.3",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.4",
diff --git a/yarn.lock b/yarn.lock
index 2086de5d3e..833adf2bfa 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5550,7 +5550,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
-fast-glob@^3.2.12, fast-glob@^3.2.9:
+fast-glob@^3.2.12, fast-glob@^3.2.9, fast-glob@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
@@ -5981,7 +5981,7 @@ glob-to-regexp@^0.4.1:
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
-glob@^10.3.10, glob@^10.3.7:
+glob@^10.3.7:
version "10.3.10"
resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b"
integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==
@@ -7139,9 +7139,9 @@ istanbul-reports@^3.1.3:
istanbul-lib-report "^3.0.0"
jackspeak@^2.3.5:
- version "2.3.5"
- resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.5.tgz#443f237f9eeeb0d7c6ec34835ef5289bb4acb068"
- integrity sha512-Ratx+B8WeXLAtRJn26hrhY8S1+Jz6pxPMrkrdkgb/NstTNiqMhX0/oFVu5wX+g5n6JlEu2LPsDJmY8nRP4+alw==
+ version "2.3.6"
+ resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8"
+ integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==
dependencies:
"@isaacs/cliui" "^8.0.2"
optionalDependencies:
@@ -8253,9 +8253,9 @@ minimatch@^5.0.1:
brace-expansion "^2.0.1"
minimatch@^9.0.1:
- version "9.0.1"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.1.tgz#8a555f541cf976c622daf078bb28f29fb927c253"
- integrity sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==
+ version "9.0.3"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825"
+ integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==
dependencies:
brace-expansion "^2.0.1"
@@ -8345,9 +8345,9 @@ minipass@^4.0.0:
yallist "^4.0.0"
"minipass@^5.0.0 || ^6.0.2 || ^7.0.0":
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.1.tgz#dff63464407cd8b83d7f008c0f116fa8c9b77ebf"
- integrity sha512-NQ8MCKimInjVlaIqx51RKJJB7mINVkLTJbsZKmto4UAAOC/CWXES8PGaOgoBZyqoUsUA/U3DToGK7GJkkHbjJw==
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c"
+ integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==
minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2:
version "2.1.2"
@@ -10186,9 +10186,9 @@ screenfull@^5.2.0:
integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==
scrollparent@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/scrollparent/-/scrollparent-2.0.1.tgz#715d5b9cc57760fb22bdccc3befb5bfe06b1a317"
- integrity sha1-cV1bnMV3YPsivczDvvtb/gaxoxc=
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/scrollparent/-/scrollparent-2.1.0.tgz#6cae915c953835886a6ba0d77fdc2bb1ed09076d"
+ integrity sha512-bnnvJL28/Rtz/kz2+4wpBjHzWoEzXhVg/TE8BeVGJHUqE8THNIRnDxDWMktwM+qahvlRdvlLdsQfYe+cuqfZeA==
scss-parser@^1.0.6:
version "1.0.6"
@@ -10395,9 +10395,9 @@ signal-exit@^3.0.7:
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
signal-exit@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.0.1.tgz#96a61033896120ec9335d96851d902cc98f0ba2a"
- integrity sha512-uUWsN4aOxJAS8KOuf3QMyFtgm1pkb6I+KRZbRF/ghdf5T7sM+B1lLLzPDxswUjkmHyxQAVzEgG35E3NzDM9GVw==
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
+ integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
simple-markdown@^0.2.1:
version "0.2.2"
@@ -10796,9 +10796,9 @@ strip-ansi@^5.1.0, strip-ansi@^5.2.0:
ansi-regex "^4.1.0"
strip-ansi@^7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2"
- integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
+ integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==
dependencies:
ansi-regex "^6.0.1"
@@ -11734,12 +11734,12 @@ vue-meta@^2.4.0:
dependencies:
deepmerge "^4.2.2"
-vue-observe-visibility@^0.4.1:
+vue-observe-visibility@^0.4.4:
version "0.4.6"
resolved "https://registry.yarnpkg.com/vue-observe-visibility/-/vue-observe-visibility-0.4.6.tgz#878cb8ebcf3078e40807af29774e97105ebd519e"
integrity sha512-xo0CEVdkjSjhJoDdLSvoZoQrw/H2BlzB5jrCBKGZNXN2zdZgMuZ9BKrxXDjNP2AxlcCoKc8OahI3F3r3JGLv2Q==
-vue-resize@^0.4.4:
+vue-resize@^0.4.5:
version "0.4.5"
resolved "https://registry.yarnpkg.com/vue-resize/-/vue-resize-0.4.5.tgz#4777a23042e3c05620d9cbda01c0b3cc5e32dcea"
integrity sha512-bhP7MlgJQ8TIkZJXAfDf78uJO+mEI3CaLABLjv0WNzr4CcGRGPIAItyWYnP6LsPA4Oq0WE+suidNs6dgpO4RHg==
@@ -11757,7 +11757,7 @@ vue-style-loader@^4.1.0, vue-style-loader@^4.1.3:
hash-sum "^1.0.2"
loader-utils "^1.0.2"
-vue-template-compiler@^2.6.11:
+vue-template-compiler@2.6.14:
version "2.6.14"
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.14.tgz#a2f0e7d985670d42c9c9ee0d044fed7690f4f763"
integrity sha512-ODQS1SyMbjKoO1JBJZojSw6FE4qnh9rIpUZn2EUT86FKizx9uH5z6uXiIrm4/Nb/gwxTi/o17ZDEGWAXHvtC7g==
@@ -11770,21 +11770,21 @@ vue-template-es2015-compiler@^1.6.0, vue-template-es2015-compiler@^1.9.0:
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
-vue-virtual-scroller@0.12.0:
- version "0.12.0"
- resolved "https://registry.yarnpkg.com/vue-virtual-scroller/-/vue-virtual-scroller-0.12.0.tgz#42f8fd7b299cd4d4fd1f5e14676792c229b890e2"
- integrity sha512-01hKN99psA9Hq6zJajQc8H63sgqjpytHC8IyO+WKm6JzdVi8LeJQQqMrz5iUAFW6ZDGk+hvxaAqqcnJv+X8vYg==
+vue-virtual-scroller@1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/vue-virtual-scroller/-/vue-virtual-scroller-1.1.2.tgz#b8a6362f177abf3f2149ce1eac18013c71fe353b"
+ integrity sha512-SkUyc7QHCJFB5h1Fya7LxVizlVzOZZuFVipBGHYoTK8dwLs08bIz/tclvRApYhksaJIm/nn51inzO2UjpGJPMQ==
dependencies:
scrollparent "^2.0.1"
- vue-observe-visibility "^0.4.1"
- vue-resize "^0.4.4"
+ vue-observe-visibility "^0.4.4"
+ vue-resize "^0.4.5"
vue2-teleport@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/vue2-teleport/-/vue2-teleport-1.0.1.tgz#1b7f9f69c1223f522cf6cd81c39b8d6019e1cf66"
integrity sha512-hbY/Q0x8qXGFxo6h4KU4YYesUcN+uUjliqqC0PoNSgpcbS2QRb3qXi+7XMTgLYs0a8i7o1H6Mu43UV4Vbgkhgw==
-vue@^2.6.14:
+vue@2.6.14:
version "2.6.14"
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.14.tgz#e51aa5250250d569a3fbad3a8a5a687d6036e235"
integrity sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==
|