diff --git a/.storybook/main.js b/.storybook/main.js
deleted file mode 100644
index 6d3a8b83b..000000000
--- a/.storybook/main.js
+++ /dev/null
@@ -1,11 +0,0 @@
-module.exports = {
- framework: '@storybook/angular',
- addons: [
- '@storybook/addon-controls',
- '@storybook/addon-viewport',
- 'storybook-addon-designs',
- 'storybook-addon-rtl-direction',
- 'storybook-dark-mode',
- ],
- stories: ['../src/**/*.stories.ts'],
-}
diff --git a/.storybook/preview.js b/.storybook/preview.js
deleted file mode 100644
index c3b705822..000000000
--- a/.storybook/preview.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import '!style-loader!css-loader!sass-loader!../src/theme/theme.design-system.scss';
-import '!style-loader!css-loader!sass-loader!./styles.scss';
-
-export const parameters = {
- layout: 'centered',
- darkMode: {
- darkClass: 'dark',
- classTarget: 'html',
- stylePreview: true,
- },
-};
diff --git a/.storybook/styles.scss b/.storybook/styles.scss
deleted file mode 100644
index 8be75bade..000000000
--- a/.storybook/styles.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-storybook-dynamic-app-root {
- color: var(--ion-text-color);
-}
-
-.core-error-info {
- max-width: 300px;
-}
diff --git a/.storybook/tsconfig.json b/.storybook/tsconfig.json
deleted file mode 100644
index a8a27caf8..000000000
--- a/.storybook/tsconfig.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "extends": "../tsconfig.json",
- "include": [
- "../src/**/*"
- ],
- "exclude": [
- "../src/**/tests/**",
- "../src/testing/**",
- "../src/**/*.test.ts"
- ]
-}
diff --git a/package.json b/package.json
index 6de706636..2032c4f3f 100644
--- a/package.json
+++ b/package.json
@@ -30,7 +30,6 @@
"dev:ios": "ionic cordova run ios",
"prod:android": "npm run prod --prefix cordova-plugin-moodleapp && NODE_ENV=production ionic cordova run android --prod",
"prod:ios": "NODE_ENV=production ionic cordova run ios --prod",
- "storybook": "start-storybook -p 6006",
"test": "NODE_ENV=testing gulp && jest --verbose",
"test:ci": "NODE_ENV=testing gulp && jest -ci --runInBand --verbose",
"test:watch": "NODE_ENV=testing gulp watch & jest --watch",
diff --git a/src/assets/storybook/courses.json b/src/assets/storybook/courses.json
deleted file mode 100644
index 81b9390e0..000000000
--- a/src/assets/storybook/courses.json
+++ /dev/null
@@ -1 +0,0 @@
-[{"id":1,"courseimage":"https://picsum.photos/500/500","shortname":"Moodle and Mountaineering","summary":"This course will introduce you to the basics of Alpine Mountaineering, while at the same time highlighting some of the great features of Moodle."},{"id":2,"courseimage":"assets/storybook/geopattern.svg","shortname":"Digital Literacy","summary":"This course explores Digital Literacy and its importance for teachers and students. The course is optimised for the Moodle App. Please try it out!"},{"id":3,"shortname":"Class and Conflict in World Cinema","summary":"In this module we will analyse two very significant films - City of God and La Haine, both of which depict violent lives in poor conditions, the former in the favelas of Brazil and the latter in a Parisian banlieue. We will look at how conflict and class are portrayed, focusing particularly on the use of mise en scène."}]
diff --git a/src/assets/storybook/geopattern.svg b/src/assets/storybook/geopattern.svg
deleted file mode 100644
index 60e7e8a9d..000000000
--- a/src/assets/storybook/geopattern.svg
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
\ No newline at end of file
diff --git a/src/assets/storybook/sites/companylisa.ts b/src/assets/storybook/sites/companylisa.ts
deleted file mode 100644
index 3689523d7..000000000
--- a/src/assets/storybook/sites/companylisa.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-// (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 { CoreSiteFixture } from '@/storybook/stubs/classes/site';
-
-export const companyLisaSite: CoreSiteFixture = {
- id: 'companylisasite',
- info: {
- version: '2022041900',
- sitename: 'Company',
- username: 'lisa',
- firstname: 'Lisa',
- lastname: 'Díaz',
- fullname: 'Lisa Díaz',
- lang: 'en',
- userid: 1,
- siteurl: 'https://company.example.edu',
- userpictureurl: 'https://i.pravatar.cc/300?user=companylisa',
- functions: [],
- },
-};
diff --git a/src/assets/storybook/sites/schoolbarbara.ts b/src/assets/storybook/sites/schoolbarbara.ts
deleted file mode 100644
index c4fa3eda3..000000000
--- a/src/assets/storybook/sites/schoolbarbara.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-// (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 { CoreSiteFixture } from '@/storybook/stubs/classes/site';
-
-export const schoolBarbaraSite: CoreSiteFixture = {
- id: 'schoolbarbarasite',
- info: {
- version: '2022041900',
- sitename: 'School',
- username: 'barbara',
- firstname: 'Barbara',
- lastname: 'Gardner',
- fullname: 'Barbara Gardner',
- lang: 'en',
- userid: 1,
- siteurl: 'https://campus.example.edu',
- userpictureurl: 'https://i.pravatar.cc/300?user=schoolbarbara',
- functions: [],
- },
-};
diff --git a/src/assets/storybook/sites/schooljeffery.ts b/src/assets/storybook/sites/schooljeffery.ts
deleted file mode 100644
index c7823f2b0..000000000
--- a/src/assets/storybook/sites/schooljeffery.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-// (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 { CoreSiteFixture } from '@/storybook/stubs/classes/site';
-
-export const schoolJefferySite: CoreSiteFixture = {
- id: 'schooljefferysite',
- info: {
- version: '2022041900',
- sitename: 'School',
- username: 'jeffery',
- firstname: 'Jeffery',
- lastname: 'Sanders',
- fullname: 'Jeffery Sanders',
- lang: 'en',
- userid: 2,
- siteurl: 'https://campus.example.edu',
- userpictureurl: 'https://i.pravatar.cc/300?user=schooljeffery',
- functions: [],
- },
-};
diff --git a/src/core/classes/errors/ajaxwserror.ts b/src/core/classes/errors/ajaxwserror.ts
index 73dcfa37d..53e8b10e6 100644
--- a/src/core/classes/errors/ajaxwserror.ts
+++ b/src/core/classes/errors/ajaxwserror.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { CoreSiteError } from '@classes/errors/siteerror';
+import { CoreSiteError, CoreSiteErrorOptions } from '@classes/errors/siteerror';
/**
* Error returned by WS.
@@ -29,10 +29,7 @@ export class CoreAjaxWSError extends CoreSiteError {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
constructor(error: any, available?: number) {
- super({
- message: error.message || error.error,
- errorcode: error.errorcode,
- });
+ super(getErrorOptions(error));
this.exception = error.exception;
this.warningcode = error.warningcode;
@@ -40,15 +37,37 @@ export class CoreAjaxWSError extends CoreSiteError {
this.moreinfourl = error.moreinfourl;
this.debuginfo = error.debuginfo;
this.backtrace = error.backtrace;
-
- this.available = available;
- if (this.available === undefined) {
- if (this.errorcode) {
- this.available = this.errorcode == 'invalidrecord' ? -1 : 1;
- } else {
- this.available = 0;
- }
- }
+ this.available = available ?? (
+ this.debug
+ ? (this.debug.code == 'invalidrecord' ? -1 : 1)
+ : 0
+ );
}
}
+
+/**
+ * Get error options from unknown error instance.
+ *
+ * @param error The error.
+ * @returns Options
+ */
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+function getErrorOptions(error: any): CoreSiteErrorOptions {
+ const options: CoreSiteErrorOptions = {
+ message: error.message || error.error,
+ };
+
+ if ('debug' in error) {
+ options.debug = error.debug;
+ }
+
+ if ('errorcode' in error) {
+ options.debug = {
+ code: error.errorcode,
+ details: error.message || error.error,
+ };
+ }
+
+ return options;
+}
diff --git a/src/core/classes/errors/siteerror.ts b/src/core/classes/errors/siteerror.ts
index bb31c41b6..3eed531e6 100644
--- a/src/core/classes/errors/siteerror.ts
+++ b/src/core/classes/errors/siteerror.ts
@@ -20,24 +20,39 @@ import { CoreUserSupportConfig } from '@features/user/classes/support/support-co
*/
export class CoreSiteError extends CoreError {
- errorcode?: string;
- errorDetails?: string;
+ debug?: CoreSiteErrorDebug;
supportConfig?: CoreUserSupportConfig;
constructor(options: CoreSiteErrorOptions) {
super(options.message);
- this.errorcode = options.errorcode;
- this.errorDetails = options.errorDetails;
+ this.debug = options.debug;
this.supportConfig = options.supportConfig;
}
+ /**
+ * @deprecated This getter should not be called directly, but it's defined for backwards compatibility with many
+ * parts of the code that type errors as any and use it. We cannot rename those because the errors could also be
+ * CoreWSError instances which do have an "errorcode" property.
+ *
+ * @returns error code.
+ */
+ get errorcode(): string | undefined {
+ return this.debug?.code;
+ }
+
}
+export type CoreSiteErrorDebug = {
+ code: string; // Technical error code useful for technical assistance.
+ details: string; // Technical error details useful for technical assistance.
+};
+
export type CoreSiteErrorOptions = {
message: string;
- errorcode?: string; // Technical error code useful for technical assistance.
- errorDetails?: string; // Technical error details useful for technical assistance.
+
+ // Debugging information.
+ debug?: CoreSiteErrorDebug;
// Configuration to use to contact site support. If this attribute is present, it means
// that the error warrants contacting support.
diff --git a/src/core/classes/sites/authenticated-site.ts b/src/core/classes/sites/authenticated-site.ts
index 7769d479f..a71f28237 100644
--- a/src/core/classes/sites/authenticated-site.ts
+++ b/src/core/classes/sites/authenticated-site.ts
@@ -943,8 +943,10 @@ export class CoreAuthenticatedSite extends CoreUnauthenticatedSite {
throw new CoreSiteError({
supportConfig: new CoreUserAuthenticatedSupportConfig(this),
message: Translate.instant('core.siteunavailablehelp', { site: this.siteUrl }),
- errorcode: 'invalidresponse',
- errorDetails: Translate.instant('core.errorinvalidresponse', { method: 'tool_mobile_call_external_functions' }),
+ debug: {
+ code: 'invalidresponse',
+ details: Translate.instant('core.errorinvalidresponse', { method: 'tool_mobile_call_external_functions' }),
+ },
});
}
diff --git a/src/core/components/error-info/core-error-info.html b/src/core/components/error-info/core-error-info.html
deleted file mode 100644
index 2808ecb68..000000000
--- a/src/core/components/error-info/core-error-info.html
+++ /dev/null
@@ -1,6 +0,0 @@
-
diff --git a/src/core/components/error-info/error-info.scss b/src/core/components/error-info/error-info.scss
deleted file mode 100644
index a0723f21f..000000000
--- a/src/core/components/error-info/error-info.scss
+++ /dev/null
@@ -1,75 +0,0 @@
-.core-error-info {
- background: var(--gray-200);
- border-radius: var(--radius-xs);
- font-size: var(--body-font-size-sm);
- color: var(--gray-900);
-
- p:first-child {
- margin-top: 0;
- }
-
- p:last-child {
- margin-bottom: 0;
- }
-
- .core-error-info--code {
- padding: var(--spacing-2) var(--spacing-2) 0 var(--spacing-2);
- font-size: var(--body-font-size-md);
- }
-
- .core-error-info--details p {
- padding: var(--spacing-2) var(--spacing-2) 0 var(--spacing-2);
- color: var(--gray-500);
- }
-
- .core-error-info--checkbox {
- display: none;
-
- & + .core-error-info--details,
- & + .core-error-info--code + .core-error-info--details {
- max-height: 0;
- overflow: hidden;
- transition: max-height 600ms ease-in-out;
-
- & + .core-error-info--toggle {
- display: flex;
- padding: var(--spacing-2);
- min-height: var(--a11y-min-target-size);
- align-items: center;
-
- span {
- width: 100%;
- display: flex;
- justify-content: space-between;
- }
-
- svg {
- fill: currentColor;
- width: 11px;
- }
-
- .core-error-info--hide-content {
- display: none;
- }
-
- }
-
- }
-
- &:checked + .core-error-info--details,
- &:checked + .core-error-info--code + .core-error-info--details {
- max-height: 110px;
-
- & + .core-error-info--toggle .core-error-info--hide-content {
- display: flex;
- }
-
- & + .core-error-info--toggle .core-error-info--show-content {
- display: none;
- }
-
- }
-
- }
-
-}
diff --git a/src/core/components/error-info/error-info.ts b/src/core/components/error-info/error-info.ts
deleted file mode 100644
index 4104e7f3e..000000000
--- a/src/core/components/error-info/error-info.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-// (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 { Component, ElementRef, Input, OnChanges, OnInit } from '@angular/core';
-import { Translate } from '@singletons';
-import { CoreForms } from '@singletons/form';
-
-/**
- * Component to show error details.
- *
- * Given that this component has to be injected dynamically in some situations (for example, error alerts),
- * it can be rendered using the static render() method to get the raw HTML.
- */
-@Component({
- selector: 'core-error-info',
- templateUrl: 'core-error-info.html',
- styleUrls: ['error-info.scss'],
-})
-export class CoreErrorInfoComponent implements OnInit, OnChanges {
-
- /**
- * Render an instance of the component into an HTML string.
- *
- * @param errorDetails Error details.
- * @param errorCode Error code.
- * @returns Component HTML.
- */
- static render(errorDetails: string, errorCode?: string): string {
- const toggleId = CoreForms.uniqueId('error-info-toggle');
- const errorCodeLabel = Translate.instant('core.errorcode', { errorCode });
- const hideDetailsLabel = Translate.instant('core.errordetailshide');
- const showDetailsLabel = Translate.instant('core.errordetailsshow');
-
- return `
-
-
- ${errorCode ? `
${errorCodeLabel}
` : ''}
-
-
${errorDetails}
-
-
-
- `;
- }
-
- @Input() errorDetails!: string;
- @Input() errorCode?: string;
-
- constructor(private element: ElementRef) {}
-
- /**
- * @inheritdoc
- */
- ngOnInit(): void {
- this.render();
- }
-
- /**
- * @inheritdoc
- */
- ngOnChanges(): void {
- this.render();
- }
-
- /**
- * Render component html in the element created by Angular.
- */
- private render(): void {
- this.element.nativeElement.innerHTML = CoreErrorInfoComponent.render(this.errorDetails, this.errorCode);
- }
-
-}
diff --git a/src/core/components/stories/components/components.module.ts b/src/core/components/stories/components/components.module.ts
deleted file mode 100644
index d0648467e..000000000
--- a/src/core/components/stories/components/components.module.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-// (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 { NgModule } from '@angular/core';
-import { CoreEmptyBoxPageComponent } from './empty-box-page/empty-box-page';
-import { CoreEmptyBoxWrapperComponent } from './empty-box-wrapper/empty-box-wrapper';
-import { StorybookModule } from '@/storybook/storybook.module';
-import { CoreSearchComponentsModule } from '@features/search/components/components.module';
-import { CoreComponentsModule } from '@components/components.module';
-import { CommonModule } from '@angular/common';
-import { CoreCourseImageCardsPageComponent } from '@components/stories/components/course-image-cards-page/course-image-cards-page';
-import { CoreCourseImageListPageComponent } from '@components/stories/components/course-image-list-page/course-image-list-page';
-import { CoreSitesListWrapperComponent } from './sites-list-wrapper/sites-list-wrapper';
-import { CoreDirectivesModule } from '@directives/directives.module';
-
-@NgModule({
- declarations: [
- CoreCourseImageCardsPageComponent,
- CoreCourseImageListPageComponent,
- CoreEmptyBoxPageComponent,
- CoreEmptyBoxWrapperComponent,
- CoreSitesListWrapperComponent,
- ],
- imports: [
- CommonModule,
- StorybookModule,
- CoreDirectivesModule,
- CoreComponentsModule,
- CoreSearchComponentsModule,
- ],
-})
-export class CoreComponentsStorybookModule {}
diff --git a/src/core/components/stories/components/course-image-cards-page/course-image-cards-page.html b/src/core/components/stories/components/course-image-cards-page/course-image-cards-page.html
deleted file mode 100644
index f1ad00bca..000000000
--- a/src/core/components/stories/components/course-image-cards-page/course-image-cards-page.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
Course Cards
-
-
-
-
-
-
-
-
-
- {{ course.shortname }}
-
-
- {{ course.summary }}
-
-
-
-
diff --git a/src/core/components/stories/components/course-image-cards-page/course-image-cards-page.scss b/src/core/components/stories/components/course-image-cards-page/course-image-cards-page.scss
deleted file mode 100644
index 23f07c6fd..000000000
--- a/src/core/components/stories/components/course-image-cards-page/course-image-cards-page.scss
+++ /dev/null
@@ -1,16 +0,0 @@
-:host {
-
- ion-card {
- max-width: 350px;
- margin-right: auto;
- margin-left: auto;
- }
-
- .course-image-wrapper {
- width: 100%;
- height: 0;
- padding-top: 40%;
- position: relative;
- }
-
-}
diff --git a/src/core/components/stories/components/course-image-cards-page/course-image-cards-page.ts b/src/core/components/stories/components/course-image-cards-page/course-image-cards-page.ts
deleted file mode 100644
index f2b6b0323..000000000
--- a/src/core/components/stories/components/course-image-cards-page/course-image-cards-page.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-// (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 { Component } from '@angular/core';
-import { CoreCourseListItem } from '@features/courses/services/courses';
-import courses from '@/assets/storybook/courses.json';
-
-@Component({
- selector: 'core-course-image-cards-page',
- templateUrl: 'course-image-cards-page.html',
- styleUrls: ['./course-image-cards-page.scss'],
-})
-export class CoreCourseImageCardsPageComponent {
-
- courses: Partial[] = courses;
-
-}
diff --git a/src/core/components/stories/components/course-image-list-page/course-image-list-page.html b/src/core/components/stories/components/course-image-list-page/course-image-list-page.html
deleted file mode 100644
index f9638bea7..000000000
--- a/src/core/components/stories/components/course-image-list-page/course-image-list-page.html
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
Courses List
-
-
-
-
-
-
-
-
- {{ course.shortname }}
-
-
-
-
-
diff --git a/src/core/components/stories/components/course-image-list-page/course-image-list-page.ts b/src/core/components/stories/components/course-image-list-page/course-image-list-page.ts
deleted file mode 100644
index cf66b61f0..000000000
--- a/src/core/components/stories/components/course-image-list-page/course-image-list-page.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-// (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 { Component } from '@angular/core';
-import { CoreCourseListItem } from '@features/courses/services/courses';
-import courses from '@/assets/storybook/courses.json';
-
-@Component({
- selector: 'core-course-image-list-page',
- templateUrl: 'course-image-list-page.html',
-})
-export class CoreCourseImageListPageComponent {
-
- courses: Partial[] = courses;
-
-}
diff --git a/src/core/components/stories/components/empty-box-page/empty-box-page.html b/src/core/components/stories/components/empty-box-page/empty-box-page.html
deleted file mode 100644
index 0bd2c567a..000000000
--- a/src/core/components/stories/components/empty-box-page/empty-box-page.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
Search
-
-
-
-
-
-
-
-
-
-
diff --git a/src/core/components/stories/components/empty-box-page/empty-box-page.ts b/src/core/components/stories/components/empty-box-page/empty-box-page.ts
deleted file mode 100644
index a290850b8..000000000
--- a/src/core/components/stories/components/empty-box-page/empty-box-page.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-// (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 { Component, Input } from '@angular/core';
-
-@Component({
- selector: 'core-empty-box-page',
- templateUrl: 'empty-box-page.html',
-})
-export class CoreEmptyBoxPageComponent {
-
- @Input() icon!: string;
- @Input() content!: string;
- @Input() dimmed!: boolean;
-
-}
diff --git a/src/core/components/stories/components/empty-box-wrapper/empty-box-wrapper.html b/src/core/components/stories/components/empty-box-wrapper/empty-box-wrapper.html
deleted file mode 100644
index 10dc9fa5f..000000000
--- a/src/core/components/stories/components/empty-box-wrapper/empty-box-wrapper.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/src/core/components/stories/components/empty-box-wrapper/empty-box-wrapper.ts b/src/core/components/stories/components/empty-box-wrapper/empty-box-wrapper.ts
deleted file mode 100644
index 6b99f2a47..000000000
--- a/src/core/components/stories/components/empty-box-wrapper/empty-box-wrapper.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-// (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 { Component, Input, OnChanges } from '@angular/core';
-import { DomSanitizer } from '@singletons';
-import { SafeHtml } from '@angular/platform-browser';
-
-@Component({
- selector: 'core-empty-box-wrapper',
- templateUrl: 'empty-box-wrapper.html',
-})
-export class CoreEmptyBoxWrapperComponent implements OnChanges {
-
- @Input() icon!: string;
- @Input() content!: string;
- @Input() dimmed!: boolean;
-
- html?: SafeHtml;
-
- /**
- * @inheritdoc
- */
- ngOnChanges(): void {
- this.html = DomSanitizer.bypassSecurityTrustHtml(this.content);
- }
-
-}
diff --git a/src/core/components/stories/components/sites-list-wrapper/sites-list-wrapper.html b/src/core/components/stories/components/sites-list-wrapper/sites-list-wrapper.html
deleted file mode 100644
index a7b72397b..000000000
--- a/src/core/components/stories/components/sites-list-wrapper/sites-list-wrapper.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
Extra text for user {{ site.fullname }}
- {{ site.badge }} MB
-
-
-
-
-
-
-
-
- {{site.badge}}
-
-
-
-
-
-
diff --git a/src/core/components/stories/components/sites-list-wrapper/sites-list-wrapper.ts b/src/core/components/stories/components/sites-list-wrapper/sites-list-wrapper.ts
deleted file mode 100644
index 06dc02b22..000000000
--- a/src/core/components/stories/components/sites-list-wrapper/sites-list-wrapper.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-// (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 { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
-import { CoreAccountsList, CoreLoginHelper } from '@features/login/services/login-helper';
-import { CoreSiteBasicInfo } from '@services/sites';
-
-@Component({
- selector: 'core-sites-list-wrapper',
- templateUrl: 'sites-list-wrapper.html',
-})
-export class CoreSitesListWrapperComponent implements OnInit, OnChanges {
-
- @Input() sitesClickable = false;
- @Input() currentSiteClickableSelect = 'undefined';
- @Input() extraText: 'text' | 'badge' | 'none' = 'none';
- @Input() extraDetails: 'delete-button' | 'badge' | 'none' = 'none';
-
- accountsList?: CoreAccountsList;
- currentSiteClickable?: boolean;
-
- /**
- * @inheritdoc
- */
- async ngOnInit(): Promise {
- this.accountsList = await CoreLoginHelper.getAccountsList();
- }
-
- /**
- * @inheritdoc
- */
- async ngOnChanges(changes: SimpleChanges): Promise {
- if (changes.currentSiteClickableSelect) {
- this.currentSiteClickable = this.currentSiteClickableSelect === 'undefined' ?
- undefined :
- this.currentSiteClickableSelect === 'true';
- }
- }
-
- /**
- * Site clicked.
- *
- * @param site Site.
- */
- siteClicked(site: CoreSiteBasicInfo): void {
- alert(`clicked on ${site.id} - ${site.fullname}`);
- }
-
-}
diff --git a/src/core/components/stories/course-image.stories.ts b/src/core/components/stories/course-image.stories.ts
deleted file mode 100644
index cd919a6fe..000000000
--- a/src/core/components/stories/course-image.stories.ts
+++ /dev/null
@@ -1,104 +0,0 @@
-// (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 { Meta, moduleMetadata } from '@storybook/angular';
-
-import { story } from '@/storybook/utils/helpers';
-
-import { CoreCourseImageComponent } from '@components/course-image/course-image';
-import { APP_INITIALIZER } from '@angular/core';
-import { CoreSitesStub } from '@/storybook/stubs/services/sites';
-import { CoreCourseImageListPageComponent } from '@components/stories/components/course-image-list-page/course-image-list-page';
-import { CoreComponentsStorybookModule } from '@components/stories/components/components.module';
-import { CoreCourseImageCardsPageComponent } from '@components/stories/components/course-image-cards-page/course-image-cards-page';
-
-interface Args {
- type: 'image' | 'geopattern' | 'color';
- fill: boolean;
-}
-
-export default {
- title: 'Core/Course Image',
- component: CoreCourseImageComponent,
- decorators: [
- moduleMetadata({
- imports: [CoreComponentsStorybookModule],
- providers: [
- {
- provide: APP_INITIALIZER,
- multi: true,
- useValue: () => {
- const site = CoreSitesStub.getRequiredCurrentSite();
-
- site.stubWSResponse('tool_mobile_get_config', {
- settings: [
- { name: 'core_admin_coursecolor1', value: '#F9B000' },
- { name: 'core_admin_coursecolor2', value: '#EF4B00' },
- { name: 'core_admin_coursecolor3', value: '#4338FB' },
- { name: 'core_admin_coursecolor4', value: '#E142FB' },
- { name: 'core_admin_coursecolor5', value: '#FF0064' },
- { name: 'core_admin_coursecolor6', value: '#FF0F18' },
- { name: 'core_admin_coursecolor7', value: '#039B06' },
- { name: 'core_admin_coursecolor8', value: '#039B88' },
- { name: 'core_admin_coursecolor9', value: '#EF009B' },
- { name: 'core_admin_coursecolor10', value: '#020B6E' },
- ],
- warnings: [],
- });
- },
- },
- ],
- }),
- ],
- argTypes: {
- type: {
- control: {
- type: 'select',
- options: ['image', 'geopattern', 'color'],
- },
- },
- },
- args: {
- type: 'image',
- fill: false,
- },
-};
-
-const Template = story(({ type, ...args }) => {
- const getImageSource = () => {
- switch (type) {
- case 'image':
- return 'https://picsum.photos/500/500';
- case 'geopattern':
- return 'assets/storybook/geopattern.svg';
- case 'color':
- return undefined;
- }
- };
-
- return {
- component: CoreCourseImageComponent,
- props: {
- ...args,
- course: {
- id: 1,
- courseimage: getImageSource(),
- },
- },
- };
-});
-
-export const Primary = story(Template);
-export const ListPage = story(() => ({ component: CoreCourseImageListPageComponent }));
-export const CardsPage = story(() => ({ component: CoreCourseImageCardsPageComponent }));
diff --git a/src/core/components/stories/empty-box.stories.ts b/src/core/components/stories/empty-box.stories.ts
deleted file mode 100644
index 8b2922fa6..000000000
--- a/src/core/components/stories/empty-box.stories.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-// (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 { Meta, moduleMetadata } from '@storybook/angular';
-import { marked } from 'marked';
-
-import { story } from '@/storybook/utils/helpers';
-
-import { CoreEmptyBoxComponent } from '@components/empty-box/empty-box';
-import { CoreEmptyBoxWrapperComponent } from './components/empty-box-wrapper/empty-box-wrapper';
-import { CoreEmptyBoxPageComponent } from './components/empty-box-page/empty-box-page';
-import { CoreComponentsStorybookModule } from './components/components.module';
-
-interface Args {
- icon: string;
- content: string;
- dimmed: boolean;
-}
-
-export default > {
- title: 'Core/Empty Box',
- component: CoreEmptyBoxComponent,
- decorators: [
- moduleMetadata({ imports: [CoreComponentsStorybookModule] }),
- ],
- argTypes: {
- icon: {
- control: {
- type: 'select',
- options: ['fas-magnifying-glass', 'fas-user', 'fas-check'],
- },
- },
- },
- args: {
- icon: 'fas-user',
- content: 'No users',
- dimmed: false,
- },
-};
-
-const WrapperTemplate = story((args) => ({
- component: CoreEmptyBoxWrapperComponent,
- props: {
- ...args,
- content: marked(args.content),
- },
-}));
-
-const PageTemplate = story((args) => ({
- component: CoreEmptyBoxPageComponent,
- props: {
- ...args,
- content: marked(args.content),
- },
-}));
-
-export const Primary = story(WrapperTemplate);
-
-export const Example = story(PageTemplate, {
- icon: 'fas-magnifying-glass',
- content: '**No results for "Test Search"**\n\nCheck for typos or try using different keywords',
-});
-
-export const DimmedExample = story(PageTemplate, {
- icon: 'fas-magnifying-glass',
- content: 'What are you searching for?',
- dimmed: true,
-});
diff --git a/src/core/components/stories/error-info.stories.ts b/src/core/components/stories/error-info.stories.ts
deleted file mode 100644
index 9c67a6d13..000000000
--- a/src/core/components/stories/error-info.stories.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-// (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 { Meta, moduleMetadata, Story } from '@storybook/angular';
-
-import { story } from '@/storybook/utils/helpers';
-import { StorybookModule } from '@/storybook/storybook.module';
-
-import { CoreErrorInfoComponent } from '@components/error-info/error-info';
-
-interface Args {
- errorCode: string;
- errorDetails: string;
-}
-
-export default > {
- title: 'Core/Error Info',
- component: CoreErrorInfoComponent,
- decorators: [
- moduleMetadata({
- declarations: [CoreErrorInfoComponent],
- imports: [StorybookModule],
- }),
- ],
- args: {
- errorCode: '',
- errorDetails:
- 'AJAX endpoint not found. ' +
- 'This can happen if the Moodle site is too old or it blocks access to this endpoint. ' +
- 'The Moodle app only supports Moodle systems 3.5 onwards.',
- },
-};
-
-const Template: Story = (args) => ({
- component: CoreErrorInfoComponent,
- props: args,
-});
-
-export const Primary = story(Template);
diff --git a/src/core/components/stories/sites-list.stories.ts b/src/core/components/stories/sites-list.stories.ts
deleted file mode 100644
index 0fa75f7e5..000000000
--- a/src/core/components/stories/sites-list.stories.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-// (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 { Meta, moduleMetadata } from '@storybook/angular';
-
-import { story } from '@/storybook/utils/helpers';
-import { CoreSitesListComponent } from '@components/sites-list/sites-list';
-import { CoreSitesListWrapperComponent } from './components/sites-list-wrapper/sites-list-wrapper';
-import { CoreComponentsStorybookModule } from './components/components.module';
-
-interface Args {
- sitesClickable: boolean;
- currentSiteClickable: 'true' | 'false' | 'undefined';
- extraText: 'text' | 'badge' | 'none';
- extraDetails: 'delete-button' | 'badge' | 'none';
-}
-
-export default > {
- title: 'Core/Sites List',
- component: CoreSitesListComponent,
- decorators: [
- moduleMetadata({ imports: [CoreComponentsStorybookModule] }),
- ],
- argTypes: {
- sitesClickable: {
- control: {
- type: 'boolean',
- },
- },
- currentSiteClickable: {
- control: {
- type: 'select',
- options: ['true', 'false', 'undefined'],
- },
- },
- extraText: {
- control: {
- type: 'select',
- options: ['text', 'badge', 'none'],
- },
- },
- extraDetails: {
- control: {
- type: 'select',
- options: ['delete-button', 'badge', 'none'],
- },
- },
- },
- args: {
- sitesClickable: false,
- currentSiteClickable: 'undefined',
- extraText: 'none',
- extraDetails: 'none',
- },
-};
-
-const Template = story(({ sitesClickable, currentSiteClickable, extraText, extraDetails }) => ({
- component: CoreSitesListWrapperComponent,
- props: {
- sitesClickable,
- currentSiteClickableSelect: currentSiteClickable,
- extraText,
- extraDetails,
- },
-}));
-
-export const Primary = story(Template);
diff --git a/src/core/components/stories/user-avatar.stories.ts b/src/core/components/stories/user-avatar.stories.ts
deleted file mode 100644
index 64303d414..000000000
--- a/src/core/components/stories/user-avatar.stories.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-// (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 { Meta, moduleMetadata, Story } from '@storybook/angular';
-
-import { story } from '@/storybook/utils/helpers';
-import { StorybookModule } from '@/storybook/storybook.module';
-
-import { CoreUserAvatarComponent } from '@components/user-avatar/user-avatar';
-
-export default {
- title: 'Core/User Avatar',
- component: CoreUserAvatarComponent,
- decorators: [
- moduleMetadata({
- declarations: [CoreUserAvatarComponent],
- imports: [StorybookModule],
- }),
- ],
-};
-
-const Template: Story = () => ({
- component: CoreUserAvatarComponent,
-});
-
-export const Primary = story(Template);
diff --git a/src/core/features/login/pages/site/site.ts b/src/core/features/login/pages/site/site.ts
index cbca54a66..9cabf031a 100644
--- a/src/core/features/login/pages/site/site.ts
+++ b/src/core/features/login/pages/site/site.ts
@@ -38,9 +38,9 @@ import { CoreCustomURLSchemes, CoreCustomURLSchemesHandleError } from '@services
import { CoreTextUtils } from '@services/utils/text';
import { CoreForms } from '@singletons/form';
import { AlertButton } from '@ionic/core';
-import { CoreSiteError } from '@classes/errors/siteerror';
+import { CoreSiteError, CoreSiteErrorDebug } from '@classes/errors/siteerror';
import { CoreUserSupport } from '@features/user/services/support';
-import { CoreErrorInfoComponent } from '@components/error-info/error-info';
+import { CoreErrorAccordion } from '@services/error-accordion';
import { CoreUserSupportConfig } from '@features/user/classes/support/support-config';
import { CoreUserGuestSupportConfig } from '@features/user/classes/support/guest-support-config';
import { CoreLoginError } from '@classes/errors/loginerror';
@@ -408,22 +408,20 @@ export class CoreLoginSitePage implements OnInit {
let siteExists = false;
let supportConfig: CoreUserSupportConfig | undefined = undefined;
let errorTitle: string | undefined;
- let errorDetails: string | undefined;
- let errorCode: string | undefined;
+ let debug: CoreSiteErrorDebug | undefined;
if (error instanceof CoreSiteError) {
supportConfig = error.supportConfig;
- errorDetails = error.errorDetails;
- errorCode = error.errorcode;
siteExists = supportConfig instanceof CoreUserGuestSupportConfig;
+ debug = error.debug;
}
if (error instanceof CoreLoginError) {
errorTitle = error.title;
}
- if (errorDetails) {
- errorMessage = `
${errorMessage}
`;
+ if (debug) {
+ errorMessage = `
${errorMessage}
`;
}
const alertSupportConfig = supportConfig;
@@ -438,7 +436,7 @@ export class CoreLoginSitePage implements OnInit {
handler: () => CoreUserSupport.contact({
supportConfig: alertSupportConfig,
subject: Translate.instant('core.cannotconnect'),
- message: `Error: ${errorCode}\n\n${errorDetails}`,
+ message: `Error: ${debug?.code}\n\n${debug?.details}`,
}),
}
: (
@@ -458,11 +456,11 @@ export class CoreLoginSitePage implements OnInit {
buttons: buttons as AlertButton[],
});
- if (errorDetails) {
- // Avoid sanitizing JS.
- const containerElement = alertElement.querySelector('.core-error-info-container');
+ if (debug) {
+ const containerElement = alertElement.querySelector('.core-error-accordion-container');
+
if (containerElement) {
- containerElement.innerHTML = CoreErrorInfoComponent.render(errorDetails, errorCode);
+ await CoreErrorAccordion.render(containerElement, debug.code, debug.details);
}
}
}
diff --git a/src/core/features/login/services/login-helper.ts b/src/core/features/login/services/login-helper.ts
index 98fb1c72c..44ca38f7a 100644
--- a/src/core/features/login/services/login-helper.ts
+++ b/src/core/features/login/services/login-helper.ts
@@ -39,7 +39,6 @@ import { CorePushNotifications } from '@features/pushnotifications/services/push
import { CorePath } from '@singletons/path';
import { CorePromisedValue } from '@classes/promised-value';
import { SafeHtml } from '@angular/platform-browser';
-import { CoreLoginError } from '@classes/errors/loginerror';
import { CoreSettingsHelper } from '@features/settings/services/settings-helper';
import {
CoreSiteIdentityProvider,
@@ -916,8 +915,8 @@ export class CoreLoginHelperProvider {
/**
* Show a modal warning that the credentials introduced were not correct.
*/
- protected showInvalidLoginModal(error: CoreLoginError): void {
- CoreDomUtils.showErrorModal(error.errorDetails ?? error.message);
+ protected showInvalidLoginModal(error: CoreWSError): void {
+ CoreDomUtils.showErrorModal(error.message);
}
/**
diff --git a/src/core/features/login/tests/credentials.test.ts b/src/core/features/login/tests/credentials.test.ts
index e4ca21f81..3e8d83fbd 100644
--- a/src/core/features/login/tests/credentials.test.ts
+++ b/src/core/features/login/tests/credentials.test.ts
@@ -124,7 +124,10 @@ describe('Credentials page', () => {
getUserToken: () => {
throw new CoreLoginError({
message: '',
- errorcode: 'invalidlogin',
+ debug: {
+ code: 'invalidlogin',
+ details: 'Invalid login',
+ },
});
},
checkSite: async () => (siteCheck),
diff --git a/src/core/features/search/stories/components/components.module.ts b/src/core/features/search/stories/components/components.module.ts
deleted file mode 100644
index 1e59da784..000000000
--- a/src/core/features/search/stories/components/components.module.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-// (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 { NgModule } from '@angular/core';
-import { StorybookModule } from '@/storybook/storybook.module';
-import { CoreSearchComponentsModule } from '@features/search/components/components.module';
-import { CoreComponentsModule } from '@components/components.module';
-import { CommonModule } from '@angular/common';
-import {
- CoreSearchGlobalSearchResultsPageComponent,
-} from '@features/search/stories/components/global-search-results-page/global-search-results-page';
-import { CoreSharedModule } from '@/core/shared.module';
-
-@NgModule({
- declarations: [
- CoreSearchGlobalSearchResultsPageComponent,
- ],
- imports: [
- CoreSharedModule,
- CommonModule,
- StorybookModule,
- CoreComponentsModule,
- CoreSearchComponentsModule,
- ],
-})
-export class CoreSearchComponentsStorybookModule {}
diff --git a/src/core/features/search/stories/components/global-search-results-page/global-search-results-page.html b/src/core/features/search/stories/components/global-search-results-page/global-search-results-page.html
deleted file mode 100644
index eeb81da2c..000000000
--- a/src/core/features/search/stories/components/global-search-results-page/global-search-results-page.html
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
Search Results
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/core/features/search/stories/components/global-search-results-page/global-search-results-page.ts b/src/core/features/search/stories/components/global-search-results-page/global-search-results-page.ts
deleted file mode 100644
index 6154c5d22..000000000
--- a/src/core/features/search/stories/components/global-search-results-page/global-search-results-page.ts
+++ /dev/null
@@ -1,141 +0,0 @@
-// (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 { Component } from '@angular/core';
-import { CoreCourseListItem } from '@features/courses/services/courses';
-import { CoreUserWithAvatar } from '@components/user-avatar/user-avatar';
-import { CoreSearchGlobalSearchResult } from '@features/search/services/global-search';
-import courses from '@/assets/storybook/courses.json';
-
-@Component({
- selector: 'core-search-global-search-results-page',
- templateUrl: 'global-search-results-page.html',
-})
-export class CoreSearchGlobalSearchResultsPageComponent {
-
- results: CoreSearchGlobalSearchResult[] = [
- {
- id: 1,
- url: '',
- title: 'Activity forum test',
- content: 'this is a content test for a forum to see in the search result.',
- context: {
- courseName: 'Course 102',
- userName: 'Stephania Krovalenko',
- },
- module: {
- name: 'forum',
- iconurl: 'assets/img/mod/forum.svg',
- area: 'activity',
- },
- },
- {
- id: 2,
- url: '',
- title: 'Activity assignment test',
- content: 'this is a content test for a forum to see in the search result.',
- context: {
- courseName: 'Course 102',
- },
- module: {
- name: 'assign',
- iconurl: 'assets/img/mod/assign.svg',
- area: '',
- },
- },
- {
- id: 3,
- url: '',
- title: 'Course 101',
- course: courses[0] as CoreCourseListItem,
- },
- {
- id: 4,
- url: '',
- title: 'John the Tester',
- user: {
- fullname: 'John Doe',
- profileimageurl: 'https://placekitten.com/300/300',
- } as CoreUserWithAvatar,
- },
- {
- id: 5,
- url: '',
- title: 'Search result title',
- content: 'this is a content test for a forum to see in the search result.',
- context: {
- userName: 'Stephania Krovalenko',
- },
- module: {
- name: 'forum',
- iconurl: 'assets/img/mod/forum.svg',
- area: 'post',
- },
- },
- {
- id: 6,
- url: '',
- title: 'Side block',
- context: {
- courseName: 'Moodle Site',
- },
- component: {
- name: 'block_html',
- iconurl: 'https://master.mm.moodledemo.net/theme/image.php?theme=boost&component=core&image=e%2Fanchor',
- },
- },
- {
- id: 7,
- url: '',
- title: 'Course section',
- context: {
- courseName: 'Course 101',
- },
- component: {
- name: 'core_course',
- iconurl: 'https://master.mm.moodledemo.net/theme/image.php?theme=boost&component=core&image=i%2Fsection',
- },
- },
- {
- id: 8,
- url: '',
- title: 'This item has long text everywhere, so make sure that it looks good anyways. ' +
- 'Even if the screen you\'re using is also big, this should still be a problem because this text is *really* long.',
- content: 'You would normally see lorem ipsum here, but we decided to just write some gibberish here to make it more ' +
- 'real. We all know that lorem ipsum is fabricated text, and even though it serves its purpose, it isn\'t as ' +
- 'engaging as some real, hand-crafted text (not sure why this should be engaging, anyways).',
- context: {
- courseName: 'And it\'s not just the title, either. Other things like the Course title also take more than ' +
- 'you would expect in a normal site (or even not so normal).',
- userName: 'To top it off, it has a user name as well! What is this madness? Well, at some point you just have to ' +
- 'get creative. Honestly, I\'m surprised if you\'re even reading this. Kudos to you for being thorough.',
- },
- module: {
- name: 'book',
- iconurl: 'assets/img/mod/book.svg',
- area: '',
- },
- },
- ];
-
- /**
- * Result clicked.
- *
- * @param title Result title.
- */
- resultClicked(title: string): void {
- alert(`clicked on ${title}`);
- }
-
-}
diff --git a/src/core/features/search/stories/global-search-result.stories.ts b/src/core/features/search/stories/global-search-result.stories.ts
deleted file mode 100644
index 8bc43c2bd..000000000
--- a/src/core/features/search/stories/global-search-result.stories.ts
+++ /dev/null
@@ -1,136 +0,0 @@
-// (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 { Meta, moduleMetadata } from '@storybook/angular';
-
-import { story } from '@/storybook/utils/helpers';
-
-import { CoreSearchGlobalSearchResultComponent } from '@features/search/components/global-search-result/global-search-result';
-import { CoreSearchComponentsStorybookModule } from '@features/search/stories/components/components.module';
-import {
- CoreSearchGlobalSearchResultsPageComponent,
-} from '@features/search/stories/components/global-search-results-page/global-search-results-page';
-import { APP_INITIALIZER } from '@angular/core';
-import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate';
-import { AddonModForumModuleHandler } from '@addons/mod/forum/services/handlers/module';
-import { AddonModAssignModuleHandler } from '@addons/mod/assign/services/handlers/module';
-import { CoreSearchGlobalSearchResult } from '@features/search/services/global-search';
-import { CoreUserWithAvatar } from '@components/user-avatar/user-avatar';
-import { CoreCourseListItem } from '@features/courses/services/courses';
-import courses from '@/assets/storybook/courses.json';
-
-interface Args {
- title: string;
- content: string;
- image: 'course' | 'user' | 'none';
- module: 'forum-activity' | 'forum-post' | 'assign' | 'none';
- courseContext: boolean;
- userContext: boolean;
- showCourse: boolean;
-}
-
-export default > {
- title: 'Core/Search/Global Search Result',
- component: CoreSearchGlobalSearchResultComponent,
- decorators: [
- moduleMetadata({
- imports: [CoreSearchComponentsStorybookModule],
- providers: [
- {
- provide: APP_INITIALIZER,
- multi: true,
- useValue() {
- CoreCourseModuleDelegate.registerHandler(AddonModForumModuleHandler.instance);
- CoreCourseModuleDelegate.registerHandler(AddonModAssignModuleHandler.instance);
- CoreCourseModuleDelegate.updateHandlers();
- },
- },
- ],
- }),
- ],
- argTypes: {
- image: {
- control: {
- type: 'select',
- options: ['course', 'user', 'none'],
- },
- },
- module: {
- control: {
- type: 'select',
- options: ['forum-activity', 'forum-post', 'assign', 'none'],
- },
- },
- },
- args: {
- title: 'Result #1',
- content: 'This item seems really interesting, maybe you should click through',
- image: 'none',
- module: 'none',
- courseContext: false,
- userContext: false,
- showCourse: true,
- },
- parameters: {
- design: {
- type: 'figma',
- url: 'https://www.figma.com/file/h3E7pkfgyImJPaYmTfnwuF/Global-Search?node-id=118%3A4610',
- },
- },
-};
-
-const Template = story(({ image, courseContext, userContext, module, showCourse, ...args }) => {
- const result: CoreSearchGlobalSearchResult = {
- ...args,
- id: 1,
- url: '',
- };
-
- if (courseContext || userContext) {
- result.context = {
- courseName: courseContext ? 'Course 101' : undefined,
- userName: userContext ? 'John Doe' : undefined,
- };
- }
-
- if (module !== 'none') {
- const name = module.startsWith('forum') ? 'forum' : module;
-
- result.module = {
- name,
- iconurl: `assets/img/mod/${name}.svg`,
- area: module.startsWith('forum') ? module.substring(6) : '',
- };
- }
-
- switch (image) {
- case 'course':
- result.course = courses[0] as CoreCourseListItem;
- break;
- case 'user':
- result.user = {
- fullname: 'John Doe',
- profileimageurl: 'https://placekitten.com/300/300',
- } as CoreUserWithAvatar;
- break;
- }
-
- return {
- component: CoreSearchGlobalSearchResultComponent,
- props: { result, showCourse },
- };
-});
-
-export const Primary = story(Template);
-export const ResultsPage = story(() => ({ component: CoreSearchGlobalSearchResultsPageComponent }));
diff --git a/src/core/services/error-accordion.ts b/src/core/services/error-accordion.ts
new file mode 100644
index 000000000..33c137780
--- /dev/null
+++ b/src/core/services/error-accordion.ts
@@ -0,0 +1,123 @@
+// (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 { Translate, makeSingleton } from '@singletons';
+import { CoreUtils } from '@services/utils/utils';
+import { CoreDom } from '@singletons/dom';
+import { CoreForms } from '@singletons/form';
+import { CoreLogger } from '@singletons/logger';
+
+/**
+ * Service used to render an Error Accordion component.
+ *
+ * This is declared as a service instead of an Angular Component because the HTML
+ * has to be injected dynamically in alerts (only HTML and Ionic components work).
+ */
+@Injectable({ providedIn: 'root' })
+export class CoreErrorAccordionService {
+
+ private logger: CoreLogger;
+
+ constructor() {
+ this.logger = CoreLogger.getInstance('CoreErrorAccordion');
+ }
+
+ /**
+ * Render an instance of the component into an HTML string.
+ *
+ * @param element Root element.
+ * @param errorCode Error code.
+ * @param errorDetails Error details.
+ */
+ async render(element: Element, errorCode: string, errorDetails: string): Promise {
+ const html = this.html(errorCode, errorDetails);
+
+ element.innerHTML = html;
+
+ await this.hydrate(element);
+ }
+
+ /**
+ * Get component html.
+ *
+ * @param errorCode Error code.
+ * @param errorDetails Error details.
+ * @returns HTML.
+ */
+ private html(errorCode: string, errorDetails: string): string {
+ const contentId = CoreForms.uniqueId('error-accordion-content');
+ const errorCodeLabel = Translate.instant('core.errorcode', { errorCode });
+ const hideDetailsLabel = Translate.instant('core.errordetailshide');
+ const showDetailsLabel = Translate.instant('core.errordetailsshow');
+
+ return `
+