From 045d81f4820bdcc4fdf30ce67ef5e790cc438d02 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 5 May 2021 17:37:38 +0200 Subject: [PATCH 01/13] MOBILE-3320 DX: Fix config files naming --- .gitignore | 4 ++-- .vscode/settings.json | 2 +- gulp/task-build-env.js | 2 +- gulpfile.js | 2 +- moodle.example.config.json => moodle.config.example.json | 0 5 files changed, 5 insertions(+), 5 deletions(-) rename moodle.example.config.json => moodle.config.example.json (100%) diff --git a/.gitignore b/.gitignore index e120915ae..d3b41f8be 100644 --- a/.gitignore +++ b/.gitignore @@ -30,8 +30,8 @@ npm-debug.log* /www /src/assets/lib -/moodle.*.config.json -!/moodle.example.config.json +/moodle.config.*.json +!/moodle.config.example.json /src/assets/lang/* /src/assets/env.json diff --git a/.vscode/settings.json b/.vscode/settings.json index d8b699e18..e2f79e54b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,7 +2,7 @@ "files.associations": { "moodle.config.json": "jsonc", - "moodle.*.config.json": "jsonc", + "moodle.config.*.json": "jsonc", }, } diff --git a/gulp/task-build-env.js b/gulp/task-build-env.js index 1ccb8dec0..b580a230b 100644 --- a/gulp/task-build-env.js +++ b/gulp/task-build-env.js @@ -25,7 +25,7 @@ function getConfig(environment) { }; const config = parseJsonc(readFileSync(resolve(__dirname, '../moodle.config.json')).toString()); const envSuffixes = (envSuffixesMap[environment] || []); - const envConfigPath = envSuffixes.map(suffix => resolve(__dirname, `../moodle.${suffix}.config.json`)).find(existsSync); + const envConfigPath = envSuffixes.map(suffix => resolve(__dirname, `../moodle.config.${suffix}.json`)).find(existsSync); if (envConfigPath) { const envConfig = parseJsonc(readFileSync(envConfigPath).toString()); diff --git a/gulpfile.js b/gulpfile.js index 2115bad2e..605ac7e40 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -48,5 +48,5 @@ gulp.task('default', gulp.parallel(['lang', 'env'])); gulp.task('watch', () => { gulp.watch(paths.lang, { interval: 500 }, gulp.parallel('lang')); - gulp.watch(['./moodle.config.json', './moodle.*.config.json'], { interval: 500 }, gulp.parallel('env')); + gulp.watch(['./moodle.config.json', './moodle.config.*.json'], { interval: 500 }, gulp.parallel('env')); }); diff --git a/moodle.example.config.json b/moodle.config.example.json similarity index 100% rename from moodle.example.config.json rename to moodle.config.example.json From 477daeb0567629a21ebf0460267c05fb280a75e9 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 5 May 2021 17:38:05 +0200 Subject: [PATCH 02/13] MOBILE-3320 DX: Add module snippets --- .vscode/moodle.code-snippets | 37 +++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/.vscode/moodle.code-snippets b/.vscode/moodle.code-snippets index 6c7a7923c..6028e1f1d 100644 --- a/.vscode/moodle.code-snippets +++ b/.vscode/moodle.code-snippets @@ -37,6 +37,41 @@ ], "description": "[Moodle] Create a Page class" }, + "[Moodle] Module class": { + "scope": "typescript", + "prefix": "mamodule", + "body": [ + "import { NgModule } from '@angular/core';", + "", + "@NgModule({", + " $0", + "})", + "export class ${1}Module {}", + "" + ], + "description": "[Moodle] Create a Module class" + }, + "[Moodle] Lazy Module class": { + "scope": "typescript", + "prefix": "malazymodule", + "body": [ + "import { NgModule } from '@angular/core';", + "import { RouterModule, Routes } from '@angular/router';", + "", + "const routes: Routes = [", + " $0", + "];", + "", + "@NgModule({", + " imports: [", + " RouterModule.forChild(routes),", + " ],", + "})", + "export class ${1}LazyModule {}", + "" + ], + "description": "[Moodle] Create a Lazy Module class" + }, "[Moodle] Service Singleton": { "scope": "typescript", "prefix": "massingleton", @@ -74,5 +109,5 @@ "" ], "description": "[Moodle] Create a Pure Singleton" - } + }, } From 193be52ffaed499fc48a6ab0626a3885e3a66749 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 5 May 2021 17:40:08 +0200 Subject: [PATCH 03/13] MOBILE-3320 login: Fix sites list --- src/assets/icon/icon.png | Bin 0 -> 18809 bytes src/core/features/login/pages/site/site.html | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 src/assets/icon/icon.png diff --git a/src/assets/icon/icon.png b/src/assets/icon/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f41b1f803f81f000f94f0c185431034ab3a96a35 GIT binary patch literal 18809 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 - + @@ -118,7 +118,7 @@ - + From 25edf4a3aa1c5fe307421643ef4f0dc16c85823f Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 5 May 2021 17:41:37 +0200 Subject: [PATCH 04/13] MOBILE-3320 chore: Fix typos and missing files --- src/assets/img/group-avatar.png | Bin 0 -> 972 bytes src/core/directives/supress-events.ts | 2 +- src/theme/theme.light.scss | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 src/assets/img/group-avatar.png diff --git a/src/assets/img/group-avatar.png b/src/assets/img/group-avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..2e336c95ca87f61a6fa1309231e138b520c8a771 GIT binary patch literal 972 zcmV;-12g=IP)+J08?(XjO z_4V`f^X28`-QC^l>gws~>Ez_(i_vXf0000LbW%=J0RR90|NsC0|NsC0|NsC0|NsC0 z|4^{{F8}}l32;bRa{vH2T>t<%T>(QO5DEYQ0|iM$K~#90?U~zxs~`+TM*&4ts-5}& zZ#~{>B^L;tp3V#Vtu?STge2%!^#OeqNP!ecffPuA{8vb=v@u%M={b^?9HeQ@p|*)5 z1eOe>w&s+LK8(bYhIA%S$1_BhB*fWpsC67eW=TSN1JrX6nI#F)aH!@WGD`~5z>&r< zaU-;(ARQjcEWOY&6VeQWQp3=sEnkH=buNJ(-7g^y4_&7mf^fA1Zz+LPEgab{^LhB^ z&C!-ZNDYThl|$1l6FSOL3aP+dd*YUl+s2k+hzmBEcGXBRj2W?|91?hE@d~l&b~Vs4 z2U5BIh$Y)Q628=n`S6opG8S>wB1?s6V9dM`z8 zzpz<7mtr|Bx?>PEU-XC_#;5dhBTtzf9rU7Y|D$%|OABXR^n zZ)Q&Hi7yU`G(wq=5`jc|6iVcwAq9!FjkJi?F$u}^7HTF%5ZqEEgnBvwBrCR7@$tn% zB6Xb;yX#p9(S)SLzD!~vS=)UVyHi*Q+o14b-zEJmggNiN7ZPc*IkD;fZy}LRp3|5O z`N+b5WS@K_t>iBXY)&PRIdUAOWM3&-xhXR8u07TgH5nyE$G%O(Kho5~W}=OMWl4Pr udbGGvMSD~M + * */ @Directive({ selector: '[core-suppress-events]', diff --git a/src/theme/theme.light.scss b/src/theme/theme.light.scss index 1e7ca7425..13f04e715 100644 --- a/src/theme/theme.light.scss +++ b/src/theme/theme.light.scss @@ -122,7 +122,7 @@ ion-slide { --background: var(--core-tab-background); --color: var(--core-tab-color); - --border-color: var(--core-tab-border-colo); + --border-color: var(--core-tab-border-color); --color-active: var(--core-tab-color-active); --border-color-active: var(--core-tab-border-color-active); } From 2c01a3c4aac5057900a51bfc3eea4488dedeacfe Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 5 May 2021 17:43:40 +0200 Subject: [PATCH 05/13] MOBILE-3320 utils: Add helper methods and classes --- src/core/constants.ts | 12 ++++++++++-- src/core/singletons/math.ts | 32 ++++++++++++++++++++++++++++++++ src/core/singletons/object.ts | 11 +++++++++++ src/theme/globals.variables.scss | 9 +++++++++ src/theme/theme.base.scss | 8 ++++++++ 5 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 src/core/singletons/math.ts diff --git a/src/core/constants.ts b/src/core/constants.ts index 7e6f45e98..8330e31d9 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -38,10 +38,18 @@ export class CoreConstants { /* eslint-disable max-len */ static readonly SECONDS_YEAR = 31536000; + static readonly SECONDS_MONTH = 2592000; static readonly SECONDS_WEEK = 604800; static readonly SECONDS_DAY = 86400; static readonly SECONDS_HOUR = 3600; static readonly SECONDS_MINUTE = 60; + static readonly MILLISECONDS_YEAR = 31536000000; + static readonly MILLISECONDS_MONTH = 2592000000; + static readonly MILLISECONDS_WEEK = 604800000; + static readonly MILLISECONDS_DAY = 86400000; + static readonly MILLISECONDS_HOUR = 3600000; + static readonly MILLISECONDS_MINUTE = 60000; + static readonly MILLISECONDS_SECOND = 1000; static readonly WIFI_DOWNLOAD_THRESHOLD = 104857600; // 100MB. static readonly DOWNLOAD_THRESHOLD = 10485760; // 10MB. static readonly MINIMUM_FREE_SPACE = 10485760; // 10MB. @@ -131,7 +139,7 @@ export class CoreConstants { } -type EnvironmentConfig = { +export interface EnvironmentConfig { app_id: string; appname: string; versioncode: number; @@ -167,7 +175,7 @@ type EnvironmentConfig = { forceOpenLinksIn: 'app' | 'browser'; }; -type EnvironmentBuild = { +export interface EnvironmentBuild { version: string; isProduction: boolean; isTesting: boolean; diff --git a/src/core/singletons/math.ts b/src/core/singletons/math.ts new file mode 100644 index 000000000..1c32c947f --- /dev/null +++ b/src/core/singletons/math.ts @@ -0,0 +1,32 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * Singleton with helper functions for math operations. + */ +export class CoreMath { + + /** + * Clamp a value between a minimum and a maximum. + * + * @param value Original value. + * @param min Minimum value. + * @param max Maximum value. + * @return Clamped value. + */ + static clamp(value: number, min: number, max: number): number { + return Math.min(Math.max(value, min), max); + } + +} diff --git a/src/core/singletons/object.ts b/src/core/singletons/object.ts index 8f6bf1fa3..0b3dbbc38 100644 --- a/src/core/singletons/object.ts +++ b/src/core/singletons/object.ts @@ -21,6 +21,17 @@ export type CoreObjectWithoutEmpty = { */ export class CoreObject { + /** + * Check if two objects have the same shape and the same leaf values. + * + * @param a First object. + * @param b Second object. + * @return Whether objects are equal. + */ + static deepEquals(a: unknown, b: unknown): boolean { + return JSON.stringify(a) === JSON.stringify(b); + } + /** * Check whether the given object is empty. * diff --git a/src/theme/globals.variables.scss b/src/theme/globals.variables.scss index c0c8e0eb4..327dd8f23 100644 --- a/src/theme/globals.variables.scss +++ b/src/theme/globals.variables.scss @@ -161,3 +161,12 @@ $screen-breakpoints: ( ) !default; $breakpoint-tablet: map-get($screen-breakpoints, tablet), !default; + +/* + * Z-indexes. + * + * https://github.com/ionic-team/ionic-framework/blob/master/core/src/themes/ionic.globals.scss + */ + +$z-index-overlay: 1001; +$z-index-overlay-wrapper: 10; diff --git a/src/theme/theme.base.scss b/src/theme/theme.base.scss index 1e33ab0ef..a3b41bb81 100644 --- a/src/theme/theme.base.scss +++ b/src/theme/theme.base.scss @@ -37,6 +37,14 @@ flex-direction: row; } +.margin-bottom-sm { margin-bottom: 8px; } +.margin-bottom-md { margin-bottom: 12px; } + +.font-bold { font-weight: bold; } +.font-italic { font-style: italic; } +.font-lg { font-size: 1.7rem; } +.font-sm { font-size: 1.2rem; } + // Correctly inherit ion-text-wrap onto labels. ion-item.ion-text-wrap ion-label { white-space: normal !important; From 68e5312c73707c6dca173ec52b5341a650b23107 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 5 May 2021 17:44:47 +0200 Subject: [PATCH 06/13] MOBILE-3320 remotethemes: Expose tmp site id --- src/addons/remotethemes/services/remotethemes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/addons/remotethemes/services/remotethemes.ts b/src/addons/remotethemes/services/remotethemes.ts index eea64fc8e..6dc82e1e4 100644 --- a/src/addons/remotethemes/services/remotethemes.ts +++ b/src/addons/remotethemes/services/remotethemes.ts @@ -29,7 +29,7 @@ import { makeSingleton } from '@singletons'; import { CoreEvents } from '@singletons/events'; const SEPARATOR_35 = /\/\*\*? *3\.5(\.0)? *styles? *\*\//i; // A comment like "/* 3.5 styles */". -const TMP_SITE_ID = 'tmpsite'; +export const TMP_SITE_ID = 'tmpsite'; /** * Service to handle remote themes. A remote theme is a CSS sheet stored in the site that allows customising the Mobile app. From 201ddac693bdf356ccadeb92718ccd1e57f94367 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 5 May 2021 17:45:35 +0200 Subject: [PATCH 07/13] MOBILE-3320 courses: Download from course progress --- .../components/course-progress/course-progress.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/core/features/courses/components/course-progress/course-progress.ts b/src/core/features/courses/components/course-progress/course-progress.ts index dff808d28..75f0b9ce3 100644 --- a/src/core/features/courses/components/course-progress/course-progress.ts +++ b/src/core/features/courses/components/course-progress/course-progress.ts @@ -140,17 +140,17 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy { * * @param e Click event. */ - prefetchCourse(e: Event): void { - e.preventDefault(); - e.stopPropagation(); + async prefetchCourse(e?: Event): Promise { + e?.preventDefault(); + e?.stopPropagation(); - /* @ todo try { - CoreCourseHelper.confirmAndPrefetchCourse(this.prefetchCourseData, this.course); + try { + await CoreCourseHelper.confirmAndPrefetchCourse(this.prefetchCourseData, this.course); } catch (error) { if (!this.isDestroyed) { CoreDomUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true); } - }*/ + } } /** From 9ad4fe5d7ee496533c6361e33c22ffc26f18f142 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 5 May 2021 17:46:43 +0200 Subject: [PATCH 08/13] MOBILE-3320 docs: Update upgrade notes --- upgrade.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/upgrade.txt b/upgrade.txt index 0f6b475e9..4ee9ede3e 100644 --- a/upgrade.txt +++ b/upgrade.txt @@ -4,6 +4,7 @@ information provided here is intended especially for developers. === 3.9.5 === - Several functions inside AddonNotificationsProvider have been modified to accept an "options" parameter instead of having several optional parameters. +- Schemas are now registered using Angular providers with the CORE_SITE_SCHEMAS injection token instead of CoreSitesProvider.registerSiteSchema. === 3.9.3 === From d9b55440dfda680d4ecc45e05c12e38a8699f4cb Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 5 May 2021 17:49:21 +0200 Subject: [PATCH 09/13] MOBILE-3320 sites: Create sites factory --- .../services/pushnotifications.ts | 3 +- src/core/services/sites-factory.ts | 52 +++++++++++++++++++ src/core/services/sites.ts | 17 ++++-- 3 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 src/core/services/sites-factory.ts diff --git a/src/core/features/pushnotifications/services/pushnotifications.ts b/src/core/features/pushnotifications/services/pushnotifications.ts index 40090c253..5460402fa 100644 --- a/src/core/features/pushnotifications/services/pushnotifications.ts +++ b/src/core/features/pushnotifications/services/pushnotifications.ts @@ -40,6 +40,7 @@ import { } from './database/pushnotifications'; import { CoreError } from '@classes/errors/error'; import { CoreWSExternalWarning } from '@services/ws'; +import { CoreSitesFactory } from '@services/sites-factory'; /** * Service to handle push notifications. @@ -751,7 +752,7 @@ export class CorePushNotificationsProvider { await Promise.all(results.map(async (result) => { // Create a temporary site to unregister. - const tmpSite = new CoreSite( + const tmpSite = CoreSitesFactory.makeSite( result.siteid, result.siteurl, result.token, diff --git a/src/core/services/sites-factory.ts b/src/core/services/sites-factory.ts new file mode 100644 index 000000000..395494ea8 --- /dev/null +++ b/src/core/services/sites-factory.ts @@ -0,0 +1,52 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Injectable } from '@angular/core'; + +import { CoreSite, CoreSiteConfig, CoreSiteInfo } from '@classes/site'; +import { makeSingleton } from '@singletons'; + +/* + * Provider to create sites instances. +*/ +@Injectable({ providedIn: 'root' }) +export class CoreSitesFactoryService { + + /** + * Make a site object. + * + * @param id Site ID. + * @param siteUrl Site URL. + * @param token Site's WS token. + * @param info Site info. + * @param privateToken Private token. + * @param config Site public config. + * @param loggedOut Whether user is logged out. + * @return Site instance. + */ + makeSite( + id: string | undefined, + siteUrl: string, + token?: string, + info?: CoreSiteInfo, + privateToken?: string, + config?: CoreSiteConfig, + loggedOut?: boolean, + ): CoreSite { + return new CoreSite(id, siteUrl, token, info, privateToken, config, loggedOut); + } + +} + +export const CoreSitesFactory = makeSingleton(CoreSitesFactoryService); diff --git a/src/core/services/sites.ts b/src/core/services/sites.ts index f2385dd70..b85663783 100644 --- a/src/core/services/sites.ts +++ b/src/core/services/sites.ts @@ -51,6 +51,7 @@ import { import { CoreArray } from '../singletons/array'; import { CoreNetworkError } from '@classes/errors/network-error'; import { CoreNavigationOptions } from './navigator'; +import { CoreSitesFactory } from './sites-factory'; export const CORE_SITE_SCHEMAS = new InjectionToken('CORE_SITE_SCHEMAS'); @@ -220,7 +221,7 @@ export class CoreSitesProvider { } // Site exists. Create a temporary site to check if local_mobile is installed. - const temporarySite = new CoreSite(undefined, siteUrl); + const temporarySite = CoreSitesFactory.makeSite(undefined, siteUrl); let data: LocalMobileResponse; try { @@ -438,7 +439,7 @@ export class CoreSitesProvider { } // Create a "candidate" site to fetch the site info. - let candidateSite = new CoreSite(undefined, siteUrl, token, undefined, privateToken, undefined, undefined); + let candidateSite = CoreSitesFactory.makeSite(undefined, siteUrl, token, undefined, privateToken, undefined, undefined); let isNewSite = true; try { @@ -1004,7 +1005,15 @@ export class CoreSitesProvider { const info = entry.info ? CoreTextUtils.parseJSON(entry.info) : undefined; const config = entry.config ? CoreTextUtils.parseJSON(entry.config) : undefined; - const site = new CoreSite(entry.id, entry.siteUrl, entry.token, info, entry.privateToken, config, entry.loggedOut == 1); + const site = CoreSitesFactory.makeSite( + entry.id, + entry.siteUrl, + entry.token, + info, + entry.privateToken, + config, + entry.loggedOut == 1, + ); site.setOAuthId(entry.oauthId || undefined); return this.migrateSiteSchemas(site).then(() => { @@ -1430,7 +1439,7 @@ export class CoreSitesProvider { * @return Promise resolved with the public config. */ getSitePublicConfig(siteUrl: string): Promise { - const temporarySite = new CoreSite(undefined, siteUrl); + const temporarySite = CoreSitesFactory.makeSite(undefined, siteUrl); return temporarySite.getPublicConfig(); } From a16c3d3ce6bf8c5dce2af0b6aa2a4a4521db3ab3 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 5 May 2021 17:52:40 +0200 Subject: [PATCH 10/13] MOBILE-3320 login: Fix application check --- src/core/features/login/pages/site/site.ts | 48 ++++++++++++---------- src/core/services/sites.ts | 33 ++++++++------- 2 files changed, 42 insertions(+), 39 deletions(-) diff --git a/src/core/features/login/pages/site/site.ts b/src/core/features/login/pages/site/site.ts index 0bbdc4939..7eb62e9c8 100644 --- a/src/core/features/login/pages/site/site.ts +++ b/src/core/features/login/pages/site/site.ts @@ -348,32 +348,36 @@ export class CoreLoginSitePage implements OnInit { * @return Promise resolved after logging in. */ protected async login(response: CoreSiteCheckResponse, foundSite?: CoreLoginSiteInfoExtended): Promise { - await CoreUtils.ignoreErrors(CoreSites.checkApplication(response)); + try { + await CoreSites.checkApplication(response); - CoreForms.triggerFormSubmittedEvent(this.formElement, true); + CoreForms.triggerFormSubmittedEvent(this.formElement, true); - if (response.warning) { - CoreDomUtils.showErrorModal(response.warning, true, 4000); - } - - if (CoreLoginHelper.isSSOLoginNeeded(response.code)) { - // SSO. User needs to authenticate in a browser. - CoreLoginHelper.confirmAndOpenBrowserForSSOLogin( - response.siteUrl, - response.code, - response.service, - response.config?.launchurl, - ); - } else { - const pageParams = { siteUrl: response.siteUrl, siteConfig: response.config }; - if (foundSite && !this.fixedSites) { - pageParams['siteName'] = foundSite.name; - pageParams['logoUrl'] = foundSite.imageurl; + if (response.warning) { + CoreDomUtils.showErrorModal(response.warning, true, 4000); } - CoreNavigator.navigate('/login/credentials', { - params: pageParams, - }); + if (CoreLoginHelper.isSSOLoginNeeded(response.code)) { + // SSO. User needs to authenticate in a browser. + CoreLoginHelper.confirmAndOpenBrowserForSSOLogin( + response.siteUrl, + response.code, + response.service, + response.config?.launchurl, + ); + } else { + const pageParams = { siteUrl: response.siteUrl, siteConfig: response.config }; + if (foundSite && !this.fixedSites) { + pageParams['siteName'] = foundSite.name; + pageParams['logoUrl'] = foundSite.imageurl; + } + + CoreNavigator.navigate('/login/credentials', { + params: pageParams, + }); + } + } catch (error) { + // Ignore errors. } } diff --git a/src/core/services/sites.ts b/src/core/services/sites.ts index b85663783..a022d4783 100644 --- a/src/core/services/sites.ts +++ b/src/core/services/sites.ts @@ -1174,28 +1174,27 @@ export class CoreSitesProvider { * @return Promise resolved when the user is logged out. */ async logout(): Promise { - let siteId: string | undefined; + if (!this.currentSite) { + return; + } + + const db = await this.appDB; + const promises: Promise[] = []; + const siteConfig = this.currentSite.getStoredConfig(); + const siteId = this.currentSite.getId(); - if (this.currentSite) { - const db = await this.appDB; - const siteConfig = this.currentSite.getStoredConfig(); - siteId = this.currentSite.getId(); + this.currentSite = undefined; - this.currentSite = undefined; - - if (siteConfig && siteConfig.tool_mobile_forcelogout == '1') { - promises.push(this.setSiteLoggedOut(siteId, true)); - } - - promises.push(db.deleteRecords(CURRENT_SITE_TABLE_NAME, { id: 1 })); + if (siteConfig && siteConfig.tool_mobile_forcelogout == '1') { + promises.push(this.setSiteLoggedOut(siteId, true)); } - try { - await Promise.all(promises); - } finally { - CoreEvents.trigger(CoreEvents.LOGOUT, {}, siteId); - } + promises.push(db.deleteRecords(CURRENT_SITE_TABLE_NAME, { id: 1 })); + + await CoreUtils.ignoreErrors(Promise.all(promises)); + + CoreEvents.trigger(CoreEvents.LOGOUT, {}, siteId); } /** From ca8b223e784bc14bbfcb269afd3547644a1c29c3 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 5 May 2021 17:57:17 +0200 Subject: [PATCH 11/13] MOBILE-3320 login: Check application everywhere --- .../features/login/pages/reconnect/reconnect.ts | 2 +- src/core/features/login/pages/site/site.ts | 4 ++-- .../features/login/services/handlers/cron.ts | 5 ++--- src/core/services/sites.ts | 17 ++++++++--------- src/core/services/urlschemes.ts | 2 +- 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/core/features/login/pages/reconnect/reconnect.ts b/src/core/features/login/pages/reconnect/reconnect.ts index 275b52e71..8eeb846b1 100644 --- a/src/core/features/login/pages/reconnect/reconnect.ts +++ b/src/core/features/login/pages/reconnect/reconnect.ts @@ -112,7 +112,7 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy { this.siteConfig = config; - await CoreSites.checkRequiredMinimumVersion(config); + await CoreSites.checkApplication(config); // Check logoURL if user avatar is not set. if (this.userAvatar.startsWith(this.siteUrl + '/theme/image.php')) { diff --git a/src/core/features/login/pages/site/site.ts b/src/core/features/login/pages/site/site.ts index 7eb62e9c8..7f94f447c 100644 --- a/src/core/features/login/pages/site/site.ts +++ b/src/core/features/login/pages/site/site.ts @@ -349,7 +349,7 @@ export class CoreLoginSitePage implements OnInit { */ protected async login(response: CoreSiteCheckResponse, foundSite?: CoreLoginSiteInfoExtended): Promise { try { - await CoreSites.checkApplication(response); + await CoreSites.checkApplication(response.config); CoreForms.triggerFormSubmittedEvent(this.formElement, true); @@ -545,7 +545,7 @@ export class CoreLoginSitePage implements OnInit { // Check if site uses SSO. const response = await CoreSites.checkSite(siteUrl); - await CoreSites.checkApplication(response); + await CoreSites.checkApplication(response.config); if (!CoreLoginHelper.isSSOLoginNeeded(response.code)) { // No SSO, go to credentials page. diff --git a/src/core/features/login/services/handlers/cron.ts b/src/core/features/login/services/handlers/cron.ts index 826306c60..2add95869 100644 --- a/src/core/features/login/services/handlers/cron.ts +++ b/src/core/features/login/services/handlers/cron.ts @@ -13,7 +13,6 @@ // limitations under the License. import { Injectable } from '@angular/core'; -import { CoreSitePublicConfigResponse } from '@classes/site'; import { CoreCronHandler } from '@services/cron'; import { CoreSites } from '@services/sites'; import { CoreUtils } from '@services/utils/utils'; @@ -40,9 +39,9 @@ export class CoreLoginCronHandlerService implements CoreCronHandler { // Do not check twice in the same 10 minutes. const site = await CoreSites.getSite(siteId); - const config = await CoreUtils.ignoreErrors(site.getPublicConfig(), > {}); + const config = await CoreUtils.ignoreErrors(site.getPublicConfig()); - CoreUtils.ignoreErrors(CoreSites.checkApplication( config)); + CoreUtils.ignoreErrors(CoreSites.checkApplication(config)); } /** diff --git a/src/core/services/sites.ts b/src/core/services/sites.ts index a022d4783..21f4eea6c 100644 --- a/src/core/services/sites.ts +++ b/src/core/services/sites.ts @@ -707,20 +707,19 @@ export class CoreSitesProvider { /** * Check the app for a site and show a download dialogs if necessary. * - * @param response Data obtained during site check. + * @param config Config object of the site. */ - async checkApplication(response: CoreSiteCheckResponse): Promise { - await this.checkRequiredMinimumVersion(response.config); + async checkApplication(config?: CoreSitePublicConfigResponse): Promise { + await this.checkRequiredMinimumVersion(config); } /** * Check the required minimum version of the app for a site and shows a download dialog. * - * @param config Config object of the site. - * @param siteId ID of the site to check. Current site id will be used otherwise. + * @param config Config object of the site. * @return Resolved with if meets the requirements, rejected otherwise. */ - async checkRequiredMinimumVersion(config?: CoreSitePublicConfigResponse, siteId?: string): Promise { + protected async checkRequiredMinimumVersion(config?: CoreSitePublicConfigResponse): Promise { if (!config || !config.tool_mobile_minimumversion) { return; } @@ -736,7 +735,7 @@ export class CoreSitesProvider { default: config.tool_mobile_setuplink, }; - siteId = siteId || this.getCurrentSiteId(); + const siteId = this.getCurrentSiteId(); const downloadUrl = CoreApp.getAppStoreUrl(storesConfig); @@ -838,7 +837,7 @@ export class CoreSitesProvider { } try { - await this.checkRequiredMinimumVersion(config); + await this.checkApplication(config); this.login(siteId); // Update site info. We don't block the UI. @@ -1301,7 +1300,7 @@ export class CoreSitesProvider { * @param siteid Site's ID. * @return A promise resolved when the site is updated. */ - async updateSiteInfo(siteId: string): Promise { + async updateSiteInfo(siteId?: string): Promise { const site = await this.getSite(siteId); try { diff --git a/src/core/services/urlschemes.ts b/src/core/services/urlschemes.ts index c5f40582d..7cbe49670 100644 --- a/src/core/services/urlschemes.ts +++ b/src/core/services/urlschemes.ts @@ -66,7 +66,7 @@ export class CoreCustomURLSchemesProvider { data.siteUrl = result.siteUrl; - await CoreSites.checkApplication(result); + await CoreSites.checkApplication(result.config); } return CoreSites.newSite( From 5b6897723238b8d15cedfe5b3904967858ad2508 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Thu, 6 May 2021 08:30:29 +0200 Subject: [PATCH 12/13] MOBILE-3320 DX: Warn about logs disabled only once --- src/core/services/utils/utils.ts | 2 +- src/core/singletons/logger.ts | 13 +++++++++-- src/core/singletons/time.ts | 39 ++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 src/core/singletons/time.ts diff --git a/src/core/services/utils/utils.ts b/src/core/services/utils/utils.ts index 1d267b7ce..75e68885f 100644 --- a/src/core/services/utils/utils.ts +++ b/src/core/services/utils/utils.ts @@ -1491,7 +1491,7 @@ export class CoreUtilsProvider { debounce(fn: (...args: T) => unknown, delay: number): (...args: T) => void { let timeoutID: number; - const debounced = (...args: unknown[]): void => { + const debounced = (...args: T): void => { clearTimeout(timeoutID); timeoutID = window.setTimeout(() => fn.apply(null, args), delay); diff --git a/src/core/singletons/logger.ts b/src/core/singletons/logger.ts index 88e1dd93d..be7209703 100644 --- a/src/core/singletons/logger.ts +++ b/src/core/singletons/logger.ts @@ -16,6 +16,16 @@ import moment from 'moment'; import { CoreConstants } from '@/core/constants'; +import { CoreTime } from './time'; + +/** + * Method to warn that logs are disabled, called only once. + */ +const warnLogsDisabled = CoreTime.once(() => { + // eslint-disable-next-line no-console + console.warn('Log is disabled in production app'); +}); + /** * Log function type. */ @@ -59,8 +69,7 @@ export class CoreLogger { // Disable log on production and testing. if (CoreConstants.BUILD.isProduction || CoreConstants.BUILD.isTesting) { if (CoreConstants.BUILD.isProduction) { - // eslint-disable-next-line no-console - console.warn('Log is disabled in production app'); + warnLogsDisabled(); } // eslint-disable-next-line @typescript-eslint/no-empty-function diff --git a/src/core/singletons/time.ts b/src/core/singletons/time.ts new file mode 100644 index 000000000..8e8f92018 --- /dev/null +++ b/src/core/singletons/time.ts @@ -0,0 +1,39 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * Singleton with helper functions for time operations. + */ +export class CoreTime { + + /** + * Wrap a function so that it is called only once. + * + * @param fn Function. + * @return Wrapper that will call the underlying function only once. + */ + static once(fn: (...args: T) => unknown): (...args: T) => void { + let called = false; + + return (...args: T) => { + if (called) { + return; + } + + called = true; + fn.apply(null, args); + }; + } + +} From 61789f5550137694476e373d5eafe779fe263dec Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Thu, 6 May 2021 08:57:10 +0200 Subject: [PATCH 13/13] MOBILE-3320 DX: Fix lint warnings --- .../mod/forum/components/index/index.ts | 4 +++- src/addons/mod/forum/components/post/post.ts | 14 +++++------ .../forum/pages/discussion/discussion.page.ts | 11 +++++---- src/addons/mod/forum/services/forum-helper.ts | 20 ++++++++++++---- src/addons/mod/forum/services/forum.ts | 9 ++++--- .../services/handlers/discussion-link.ts | 10 ++++---- .../resource/services/handlers/prefetch.ts | 2 +- src/core/classes/site.ts | 24 +++++++++++-------- .../features/block/components/block/block.ts | 4 ++-- src/core/services/navigator.ts | 1 + src/types/angular.d.ts | 1 + 11 files changed, 61 insertions(+), 39 deletions(-) diff --git a/src/addons/mod/forum/components/index/index.ts b/src/addons/mod/forum/components/index/index.ts index 4562d9917..802085a89 100644 --- a/src/addons/mod/forum/components/index/index.ts +++ b/src/addons/mod/forum/components/index/index.ts @@ -380,7 +380,9 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom } // Fill user data for Offline discussions (should be already cached). - const promises = offlineDiscussions.map(async (discussion: any) => { + const promises = offlineDiscussions.map(async (offlineDiscussion) => { + const discussion = offlineDiscussion as unknown as AddonModForumDiscussion; + if (discussion.parent === 0 || forum.type === 'single') { // Do not show author for first post and type single. return; diff --git a/src/addons/mod/forum/components/post/post.ts b/src/addons/mod/forum/components/post/post.ts index 7a0405051..7d174bb9b 100644 --- a/src/addons/mod/forum/components/post/post.ts +++ b/src/addons/mod/forum/components/post/post.ts @@ -71,8 +71,8 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges @Input() discussion?: AddonModForumDiscussion; // Post's' discussion, only for starting posts. @Input() component!: string; // Component this post belong to. @Input() componentId!: number; // Component ID. - @Input() replyData: any; // Object with the new post data. Usually shared between posts. - @Input() originalData: any; // Object with the original post data. Usually shared between posts. + @Input() replyData!: AddonModForumReply; // Object with the new post data. Usually shared between posts. + @Input() originalData!: Omit; // Object with the original post data. Usually shared between posts. @Input() trackPosts!: boolean; // True if post is being tracked. @Input() forum!: AddonModForumData; // The forum the post belongs to. Required for attachments and offline posts. @Input() accessInfo!: AddonModForumAccessInformation; // Forum access information. @@ -103,7 +103,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges get showForm(): boolean { return this.post.id > 0 ? !this.replyData.isEditing && this.replyData.replyingTo === this.post.id - : this.replyData.isEditing && this.replyData.replyingTo === this.post.parentid; + : !!this.replyData.isEditing && this.replyData.replyingTo === this.post.parentid; } /** @@ -275,7 +275,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges } // Add some HTML to the message if needed. - const message = CoreTextUtils.formatHtmlLines(data.message); + const message = CoreTextUtils.formatHtmlLines(data.message!); const files = data.files; const options: AddonModForumUpdateDiscussionPostWSOptionsObject = {}; @@ -295,14 +295,14 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges } // Try to send it to server. - const sent = await AddonModForum.updatePost(this.post.id, data.subject, message, options); + const sent = await AddonModForum.updatePost(this.post.id, data.subject!, message, options); if (sent && this.forum.id) { // Data sent to server, delete stored files (if any). AddonModForumHelper.deleteReplyStoredFiles(this.forum.id, this.post.id); this.onPostChange.emit(); - this.post.subject = data.subject; + this.post.subject = data.subject!; this.post.message = message; this.post.attachments = data.files; } @@ -419,7 +419,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges let saveOffline = false; let message = this.replyData.message; const subject = this.replyData.subject; - const replyingTo = this.replyData.replyingTo; + const replyingTo = this.replyData.replyingTo!; const files = this.replyData.files || []; const options: AddonModForumReplyOptions = {}; const modal = await CoreDomUtils.showModalLoading('core.sending', true); diff --git a/src/addons/mod/forum/pages/discussion/discussion.page.ts b/src/addons/mod/forum/pages/discussion/discussion.page.ts index edf8d9fdd..b059151df 100644 --- a/src/addons/mod/forum/pages/discussion/discussion.page.ts +++ b/src/addons/mod/forum/pages/discussion/discussion.page.ts @@ -38,6 +38,7 @@ import { AddonModForumDiscussion, AddonModForumPost, AddonModForumProvider, + AddonModForumReply, } from '../../services/forum'; import { AddonModForumHelper } from '../../services/forum-helper'; import { AddonModForumOffline } from '../../services/forum-offline'; @@ -72,18 +73,18 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes postHasOffline!: boolean; sort: SortType = 'nested'; trackPosts!: boolean; - replyData = { + replyData: Omit = { replyingTo: 0, isEditing: false, subject: '', - message: null, // Null means empty or just white space. + message: null, files: [], isprivatereply: false, }; - originalData = { - subject: null, // Null means original data is not set. - message: null, // Null means empty or just white space. + originalData: Omit = { + subject: null, + message: null, files: [], isprivatereply: false, }; diff --git a/src/addons/mod/forum/services/forum-helper.ts b/src/addons/mod/forum/services/forum-helper.ts index 140853e36..0519efe28 100644 --- a/src/addons/mod/forum/services/forum-helper.ts +++ b/src/addons/mod/forum/services/forum-helper.ts @@ -368,25 +368,25 @@ export class AddonModForumHelperProvider { /** * Check if the data of a post/discussion has changed. * - * @param post Current data. + * @param reply Current data. * @param original Original ata. * @return True if data has changed, false otherwise. */ - hasPostDataChanged(post: any, original?: any): boolean { + hasPostDataChanged(reply: AddonModForumPostData, original?: AddonModForumPostData): boolean { if (!original || original.subject == null) { // There is no original data, assume it hasn't changed. return false; } - if (post.subject != original.subject || post.message != original.message) { + if (reply.subject != original.subject || reply.message != original.message) { return true; } - if (post.isprivatereply != original.isprivatereply) { + if (reply.isprivatereply != original.isprivatereply) { return true; } - return CoreFileUploader.areFileListDifferent(post.files, original.files); + return CoreFileUploader.areFileListDifferent(reply.files ?? [], original.files ?? []); } /** @@ -541,3 +541,13 @@ export class AddonModForumHelperProvider { } export const AddonModForumHelper = makeSingleton(AddonModForumHelperProvider); + +/** + * Forum post data used to check changes. + */ +type AddonModForumPostData = { + subject?: string | null; + message?: string | null; + isprivatereply?: boolean; + files?: CoreFileEntry[]; +}; diff --git a/src/addons/mod/forum/services/forum.ts b/src/addons/mod/forum/services/forum.ts index 582c13e65..c12f4be48 100644 --- a/src/addons/mod/forum/services/forum.ts +++ b/src/addons/mod/forum/services/forum.ts @@ -1407,7 +1407,7 @@ export type AddonModForumDiscussion = { mailnow: number; // Mail now?. userfullname: string | boolean; // Post author full name. usermodifiedfullname: string; // Post modifier full name. - userpictureurl: string; // Post author picture. + userpictureurl?: string; // Post author picture. usermodifiedpictureurl: string; // Post modifier picture. numreplies: number; // The number of replies in the discussion. numunread: number; // The number of unread discussions. @@ -1564,9 +1564,12 @@ export type AddonModForumAccessInformation = { */ export type AddonModForumReply = { id: number; - subject: string; - message: string; + subject: string | null; // Null means original data is not set. + message: string | null; // Null means empty or just white space. files: CoreFileEntry[]; + replyingTo?: number; + isEditing?: boolean; + isprivatereply?: boolean; }; /** diff --git a/src/addons/mod/forum/services/handlers/discussion-link.ts b/src/addons/mod/forum/services/handlers/discussion-link.ts index 245d7c558..8e821ed80 100644 --- a/src/addons/mod/forum/services/handlers/discussion-link.ts +++ b/src/addons/mod/forum/services/handlers/discussion-link.ts @@ -45,7 +45,7 @@ export class AddonModForumDiscussionLinkHandlerService extends CoreContentLinksH url: string, params: Params, courseId?: number, - data?: any, + data?: { instance?: string; cmid?: string; postid?: string }, ): CoreContentLinksAction[] | Promise { data = data || {}; @@ -56,13 +56,13 @@ export class AddonModForumDiscussionLinkHandlerService extends CoreContentLinksH action: (siteId): void => { const discussionId = parseInt(params.d, 10); const pageParams: Params = { - forumId: data.instance && parseInt(data.instance, 10), - cmId: data.cmid && parseInt(data.cmid, 10), + forumId: data?.instance && parseInt(data.instance, 10), + cmId: data?.cmid && parseInt(data.cmid, 10), courseId: courseId || parseInt(params.courseid, 10) || parseInt(params.cid, 10), }; - if (data.postid || params.urlHash) { - pageParams.postId = parseInt(data.postid || params.urlHash.replace('p', '')); + if (data?.postid || params.urlHash) { + pageParams.postId = parseInt(data?.postid || params.urlHash.replace('p', '')); } if (params.parent) { diff --git a/src/addons/mod/resource/services/handlers/prefetch.ts b/src/addons/mod/resource/services/handlers/prefetch.ts index 15886949e..f93df9fac 100644 --- a/src/addons/mod/resource/services/handlers/prefetch.ts +++ b/src/addons/mod/resource/services/handlers/prefetch.ts @@ -64,7 +64,7 @@ export class AddonModResourcePrefetchHandlerService extends CoreCourseResourcePr dirPath = await CoreFilepool.getPackageDirPathByUrl(CoreSites.getCurrentSiteId(), module.url!); } - const promises: Promise[] = []; + const promises: Promise[] = []; promises.push(super.downloadOrPrefetch(module, courseId, prefetch, dirPath)); diff --git a/src/core/classes/site.ts b/src/core/classes/site.ts index 549ac2dcf..7fe336b26 100644 --- a/src/core/classes/site.ts +++ b/src/core/classes/site.ts @@ -560,7 +560,7 @@ export class CoreSite { return CoreUtils.clone(response); } - const promise = this.getFromCache(method, data, preSets, false).catch(() => { + const promise = this.getFromCache(method, data, preSets, false).catch(async () => { if (preSets.forceOffline) { // Don't call the WS, just fail. throw new CoreError( @@ -569,13 +569,15 @@ export class CoreSite { } // Call the WS. - return this.callOrEnqueueRequest(method, data, preSets, wsPreSets).then((response) => { + try { + const response = await this.callOrEnqueueRequest(method, data, preSets, wsPreSets); + if (preSets.saveToCache) { this.saveToCache(method, data, response, preSets); } return response; - }).catch((error) => { + } catch (error) { if (error.errorcode == 'invalidtoken' || (error.errorcode == 'accessexception' && error.message.indexOf('Invalid token - token expired') > -1)) { if (initialToken !== this.token && !retrying) { @@ -585,7 +587,9 @@ export class CoreSite { return this.request(method, data, preSets, true); } else if (CoreApp.isSSOAuthenticationOngoing()) { // There's an SSO authentication ongoing, wait for it to finish and try again. - return CoreApp.waitForSSOAuthentication().then(() => this.request(method, data, preSets, true)); + await CoreApp.waitForSSOAuthentication(); + + return this.request(method, data, preSets, true); } // Session expired, trigger event. @@ -649,9 +653,7 @@ export class CoreSite { if (preSets.deleteCacheIfWSError && CoreUtils.isWebServiceError(error)) { // Delete the cache entry and return the entry. Don't block the user with the delete. - this.deleteFromCache(method, data, preSets).catch(() => { - // Ignore errors. - }); + CoreUtils.ignoreErrors(this.deleteFromCache(method, data, preSets)); throw new CoreWSError(error); } @@ -660,10 +662,12 @@ export class CoreSite { preSets.omitExpires = true; preSets.getFromCache = true; - return this.getFromCache(method, data, preSets, true).catch(() => { + try { + return await this.getFromCache(method, data, preSets, true); + } catch (e) { throw new CoreWSError(error); - }); - }); + } + } // eslint-disable-next-line @typescript-eslint/no-explicit-any }).then((response: any) => { // Check if the response is an error, this happens if the error was stored in the cache. diff --git a/src/core/features/block/components/block/block.ts b/src/core/features/block/components/block/block.ts index 05ee91cc0..2fe6f2a44 100644 --- a/src/core/features/block/components/block/block.ts +++ b/src/core/features/block/components/block/block.ts @@ -34,10 +34,10 @@ export class CoreBlockComponent implements OnInit, OnDestroy, DoCheck { @Input() block!: CoreCourseBlock; // The block to render. @Input() contextLevel!: string; // The context where the block will be used. @Input() instanceId!: number; // The instance ID associated with the context level. - @Input() extraData: any; // Any extra data to be passed to the block. + @Input() extraData!: Record; // Any extra data to be passed to the block. componentClass?: Type; // The class of the component to render. - data: any = {}; // Data to pass to the component. + data: Record = {}; // Data to pass to the component. class?: string; // CSS class to apply to the block. loaded = false; diff --git a/src/core/services/navigator.ts b/src/core/services/navigator.ts index c5e380113..d543aac00 100644 --- a/src/core/services/navigator.ts +++ b/src/core/services/navigator.ts @@ -309,6 +309,7 @@ export class CoreNavigatorService { * @return Value of the parameter, undefined if not found. */ getRouteParam(name: string, routeOptions: CoreNavigatorCurrentRouteOptions = {}): T | undefined { + // eslint-disable-next-line @typescript-eslint/no-explicit-any let value: any; if (!routeOptions.params) { diff --git a/src/types/angular.d.ts b/src/types/angular.d.ts index ab158dc8c..4f63bb656 100644 --- a/src/types/angular.d.ts +++ b/src/types/angular.d.ts @@ -19,6 +19,7 @@ declare module '@ionic/angular' { export class NavController { + // eslint-disable-next-line @typescript-eslint/no-explicit-any navigateForward(url: string | UrlTree | any[], options?: NavigationOptions): Promise; }