From 554cef31163d2d7e43c5275fcd3d30c2fe51513b Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Thu, 31 Aug 2023 11:37:36 +0200 Subject: [PATCH 1/6] MOBILE-4362 behat: Improve task error message --- scripts/build-behat-plugin.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/build-behat-plugin.js b/scripts/build-behat-plugin.js index 04daa3e942d..52ec0d25951 100755 --- a/scripts/build-behat-plugin.js +++ b/scripts/build-behat-plugin.js @@ -21,7 +21,9 @@ const { mkdirSync, copySync } = require('fs-extra'); const { resolve, extname, dirname, basename, relative } = require('path'); async function main() { - const pluginPath = process.argv[2] || guessPluginPath() || fail('Folder argument missing!'); + const pluginPath = process.argv[2] + || guessPluginPath() + || fail('Folder argument missing! (you can also set the MOODLE_APP_BEHAT_PLUGIN_PATH env variable)'); const excludeFeatures = process.argv.some(arg => arg === '--exclude-features'); const exclusions = excludeFeatures ? [ From 74439956fd5539260a87efe600a7db0b35cb9470 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Thu, 31 Aug 2023 12:19:44 +0200 Subject: [PATCH 2/6] MOBILE-4362 usertours: Ensure tours order This is necessary to avoid flaky behat tests --- .../side-blocks-button/side-blocks-button.ts | 2 + .../features/usertours/services/user-tours.ts | 46 +++++++++++++++++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/core/features/block/components/side-blocks-button/side-blocks-button.ts b/src/core/features/block/components/side-blocks-button/side-blocks-button.ts index 74027b05a1c..0290aa29e33 100644 --- a/src/core/features/block/components/side-blocks-button/side-blocks-button.ts +++ b/src/core/features/block/components/side-blocks-button/side-blocks-button.ts @@ -40,6 +40,8 @@ export class CoreBlockSideBlocksButtonComponent implements OnInit, OnDestroy { component: CoreBlockSideBlocksTourComponent, side: CoreUserToursSide.Start, alignment: CoreUserToursAlignment.Center, + after: 'user-menu', + afterTimeout: 1000, getFocusedElement: nativeButton => { const innerButton = Array.from(nativeButton.shadowRoot?.children ?? []).find(child => child.tagName === 'BUTTON'); diff --git a/src/core/features/usertours/services/user-tours.ts b/src/core/features/usertours/services/user-tours.ts index a098732cb94..2dfd3fde61c 100644 --- a/src/core/features/usertours/services/user-tours.ts +++ b/src/core/features/usertours/services/user-tours.ts @@ -26,6 +26,7 @@ import { CoreDom } from '@singletons/dom'; import { CoreSubscriptions } from '@singletons/subscriptions'; import { CoreUserToursUserTourComponent } from '../components/user-tour/user-tour'; import { APP_SCHEMA, CoreUserToursDBEntry, USER_TOURS_TABLE_NAME } from './database/user-tours'; +import { CorePromisedValue } from '@classes/promised-value'; /** * Service to manage User Tours. @@ -35,6 +36,7 @@ export class CoreUserToursService { protected table = asyncInstance>(); protected tours: { component: CoreUserToursUserTourComponent; visible: boolean }[] = []; + protected toursListeners: Partial[]>> = {}; /** * Initialize database. @@ -114,6 +116,8 @@ export class CoreUserToursService { await CoreUtils.wait(delay ?? 200); + options.after && await this.waitForUserTour(options.after, options.afterTimeout); + const container = document.querySelector('ion-app') ?? document.body; const viewContainer = container.querySelector('ion-router-outlet, ion-nav, #ion-view-container-root'); const element = await AngularFrameworkDelegate.attachViewToDom( @@ -125,6 +129,8 @@ export class CoreUserToursService { viewContainer?.setAttribute('aria-hidden', 'true'); + this.toursListeners[options.id]?.forEach(listener => listener.resolve()); + return this.startTour(tour, options.watch ?? (options as CoreUserToursFocusedOptions).focus); } @@ -298,7 +304,7 @@ export class CoreUserToursService { * Is user Tour disabled? * * @param tourId Tour Id or undefined to check all user tours. - * @returns Wether a particular or all user tours are disabled. + * @returns Whether a particular or all user tours are disabled. */ isDisabled(tourId?: string): boolean { if (CoreConstants.CONFIG.disableUserTours) { @@ -319,6 +325,30 @@ export class CoreUserToursService { await this.table.delete(); } + /** + * Wait for another user tour to be shown. + * + * @param id Id of the user tour to wait for. + * @param timeout Timeout after which the waiting will end regardless of the user tour having been shown or not. + */ + async waitForUserTour(id: string, timeout?: number): Promise { + const listener = new CorePromisedValue(); + const listeners = this.toursListeners[id] = this.toursListeners[id] ?? []; + const removeListener = () => { + const index = listeners.indexOf(listener); + + if (index !== -1) { + listeners.splice(index, 1); + } + }; + + listeners.push(listener); + listener.then(removeListener).catch(removeListener); + timeout && setTimeout(() => listener.resolve(), timeout); + + await listener; + } + } export const CoreUserTours = makeSingleton(CoreUserToursService); @@ -329,8 +359,8 @@ export const CoreUserTours = makeSingleton(CoreUserToursService); export interface CoreUserToursUserTour { /** - * Cancelling a User Tours removed it from the queue if it was pending or dimisses it without - * acknowledging if it existed. + * Cancelling a User Tour removes it from the queue if it was pending or dismisses it without + * acknowledging. */ cancel(): Promise; @@ -391,6 +421,16 @@ export interface CoreUserToursBasicOptions { */ watch?: HTMLElement | false; + /** + * Whether to show this user tour only after another user tour with the given id has been shown. + */ + after?: string; + + /** + * Whether to show this user tour after the given timeout (in milliseconds) if the other user-tour hasn't been shown. + */ + afterTimeout?: number; + } /** From 469038f5965dad136c899b790b5bbba5b76cc82b Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Thu, 31 Aug 2023 13:04:52 +0200 Subject: [PATCH 3/6] MOBILE-4362 lang: Improve error message --- scripts/lang_functions.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/lang_functions.sh b/scripts/lang_functions.sh index fa7b4fab368..649f57c1a3e 100644 --- a/scripts/lang_functions.sh +++ b/scripts/lang_functions.sh @@ -14,6 +14,12 @@ function get_app_version { return fi + if ! command -v jq &> /dev/null + then + echo "You need to install the jq program in order to run this command" + exit 1 + fi + APP_VERSION=$(jq -r '.versionname' ../moodle.config.json| cut -d. -f1-2) if [ ! -z "$APP_VERSION" ]; then export LANGVERSION=$APP_VERSION From b0921795a94e4ba144410955e5475635c531b129 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Thu, 31 Aug 2023 13:05:07 +0200 Subject: [PATCH 4/6] MOBILE-4362 lang: Update langindex --- scripts/langindex.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/langindex.json b/scripts/langindex.json index 5c81137e069..2b3f8716b5c 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -338,9 +338,9 @@ "addon.mod_assign.addnewattempt": "assign", "addon.mod_assign.addnewattemptfromprevious": "assign", "addon.mod_assign.addsubmission": "assign", - "addon.mod_assign.allowsubmissionsanddescriptionfromdatesummary": "assign", + "addon.mod_assign.allowsubmissionsanddescriptionfromdatesummary": "local_moodlemobileapp", "addon.mod_assign.allowsubmissionsfromdate": "assign", - "addon.mod_assign.allowsubmissionsfromdatesummary": "assign", + "addon.mod_assign.allowsubmissionsfromdatesummary": "local_moodlemobileapp", "addon.mod_assign.applytoteam": "assign", "addon.mod_assign.assignmentisdue": "assign", "addon.mod_assign.assigntimeleft": "assign", From 549d03ed8fd6b7be0e867b0797bf1c2032917837 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Thu, 31 Aug 2023 15:28:20 +0200 Subject: [PATCH 5/6] MOBILE-4362 analytics: Strip tags from event names --- src/core/services/analytics.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/core/services/analytics.ts b/src/core/services/analytics.ts index ae4e5ad29f8..e442a6a8948 100644 --- a/src/core/services/analytics.ts +++ b/src/core/services/analytics.ts @@ -21,6 +21,7 @@ import { CoreSites } from './sites'; import { CoreConfig, CoreConfigProvider } from './config'; import { CoreConstants } from '../constants'; import { CoreUrlUtils } from './utils/url'; +import { CoreTextUtils } from '@services/utils/text'; /** * Helper service to support analytics. @@ -77,6 +78,11 @@ export class CoreAnalyticsService extends CoreDelegate { ...event, siteId: site.getId(), }; + + if (treatedEvent.type === CoreAnalyticsEventType.VIEW_ITEM || treatedEvent.type === CoreAnalyticsEventType.VIEW_ITEM_LIST) { + treatedEvent.name = CoreTextUtils.cleanTags(treatedEvent.name); + } + if ('url' in treatedEvent && treatedEvent.url) { if (!CoreUrlUtils.isAbsoluteURL(treatedEvent.url)) { treatedEvent.url = site.createSiteUrl(treatedEvent.url); From 6d8eae7dfa6b2819ca0cbdce26fbe78dbbb92e84 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Thu, 31 Aug 2023 15:28:35 +0200 Subject: [PATCH 6/6] MOBILE-4362 core: Fix docs --- src/core/features/course/classes/main-resource-component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/features/course/classes/main-resource-component.ts b/src/core/features/course/classes/main-resource-component.ts index 0e3761b1e23..80b58ad7128 100644 --- a/src/core/features/course/classes/main-resource-component.ts +++ b/src/core/features/course/classes/main-resource-component.ts @@ -493,7 +493,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, * Log activity view in analytics. * * @param wsName Name of the WS used. - * @param data Other data to send. + * @param options Other data to send. * @returns Promise resolved when done. */ async analyticsLogEvent(