forked from EVOgeek/Vmeda.Online
		
	MOBILE-4451 settings: Create error log page
This commit is contained in:
		
							parent
							
								
									99c1eb5376
								
							
						
					
					
						commit
						6da2742bd3
					
				| @ -64,6 +64,7 @@ import { CoreSiteError } from '@classes/errors/siteerror'; | |||||||
| import { CoreUserAuthenticatedSupportConfig } from '@features/user/classes/support/authenticated-support-config'; | import { CoreUserAuthenticatedSupportConfig } from '@features/user/classes/support/authenticated-support-config'; | ||||||
| import { CoreLoginHelper } from '@features/login/services/login-helper'; | import { CoreLoginHelper } from '@features/login/services/login-helper'; | ||||||
| import { CorePath } from '@singletons/path'; | import { CorePath } from '@singletons/path'; | ||||||
|  | import { CoreErrorLogs } from '@singletons/error-logs'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * QR Code type enumeration. |  * QR Code type enumeration. | ||||||
| @ -1156,7 +1157,15 @@ export class CoreSite { | |||||||
|                     // Request not executed, enqueue again.
 |                     // Request not executed, enqueue again.
 | ||||||
|                     this.enqueueRequest(request); |                     this.enqueueRequest(request); | ||||||
|                 } else if (response.error) { |                 } else if (response.error) { | ||||||
|                     request.deferred.reject(CoreTextUtils.parseJSON(response.exception || '')); |                     const rejectReason = CoreTextUtils.parseJSON(response.exception || '') as Error | undefined; | ||||||
|  |                     request.deferred.reject(rejectReason); | ||||||
|  |                     CoreErrorLogs.addErrorLog({ | ||||||
|  |                         method: request.method, | ||||||
|  |                         type: 'CoreSiteError', | ||||||
|  |                         message: response.exception ?? '', | ||||||
|  |                         time: new Date().getTime(), | ||||||
|  |                         data: request.data, | ||||||
|  |                     }); | ||||||
|                 } else { |                 } else { | ||||||
|                     let responseData = response.data ? CoreTextUtils.parseJSON(response.data) : {}; |                     let responseData = response.data ? CoreTextUtils.parseJSON(response.data) : {}; | ||||||
|                     // Match the behaviour of CoreWSProvider.call when no response is expected.
 |                     // Match the behaviour of CoreWSProvider.call when no response is expected.
 | ||||||
| @ -1170,6 +1179,13 @@ export class CoreSite { | |||||||
|         } catch (error) { |         } catch (error) { | ||||||
|             // Error not specific to a single request, reject all promises.
 |             // Error not specific to a single request, reject all promises.
 | ||||||
|             requests.forEach((request) => { |             requests.forEach((request) => { | ||||||
|  |                 CoreErrorLogs.addErrorLog({ | ||||||
|  |                     method: request.method, | ||||||
|  |                     type: 'CoreSiteError', | ||||||
|  |                     message: String(error) ?? '', | ||||||
|  |                     time: new Date().getTime(), | ||||||
|  |                     data: request.data, | ||||||
|  |                 }); | ||||||
|                 request.deferred.reject(error); |                 request.deferred.reject(error); | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -34,8 +34,9 @@ | |||||||
|             <ion-label> |             <ion-label> | ||||||
|                 <h2>Enable staging sites ({{stagingSitesCount}})</h2> |                 <h2>Enable staging sites ({{stagingSitesCount}})</h2> | ||||||
|             </ion-label> |             </ion-label> | ||||||
|             <ion-toggle [(ngModel)]="enableStagingSites" (ionChange)="setEnabledStagingSites($event.detail.checked)" |             <ion-toggle [(ngModel)]="enableStagingSites" (ionChange)="setEnabledStagingSites($event.detail.checked)" slot="end"> | ||||||
|                 slot="end"></ion-toggle> |             </ion-toggle> | ||||||
|  | 
 | ||||||
|         </ion-item> |         </ion-item> | ||||||
|         <ng-container *ngIf="siteId"> |         <ng-container *ngIf="siteId"> | ||||||
|             <ion-item class="ion-text-wrap"> |             <ion-item class="ion-text-wrap"> | ||||||
| @ -61,6 +62,12 @@ | |||||||
|                 </ion-button> |                 </ion-button> | ||||||
|             </ion-item> |             </ion-item> | ||||||
| 
 | 
 | ||||||
|  |             <ion-item class="ion-text-wrap" (click)="openErrorLog()" [detail]="true" button> | ||||||
|  |                 <ion-label> | ||||||
|  |                     <p class="item-heading">Error log</p> | ||||||
|  |                 </ion-label> | ||||||
|  |             </ion-item> | ||||||
|  | 
 | ||||||
|             <ion-item-divider> |             <ion-item-divider> | ||||||
|                 <ion-label> |                 <ion-label> | ||||||
|                     <h2>Disabled features</h2> |                     <h2>Disabled features</h2> | ||||||
|  | |||||||
| @ -19,6 +19,7 @@ import { CoreSettingsHelper } from '@features/settings/services/settings-helper' | |||||||
| import { CoreSitePlugins } from '@features/siteplugins/services/siteplugins'; | import { CoreSitePlugins } from '@features/siteplugins/services/siteplugins'; | ||||||
| import { CoreUserTours } from '@features/usertours/services/user-tours'; | import { CoreUserTours } from '@features/usertours/services/user-tours'; | ||||||
| import { CoreConfig } from '@services/config'; | import { CoreConfig } from '@services/config'; | ||||||
|  | import { CoreNavigator } from '@services/navigator'; | ||||||
| import { CorePlatform } from '@services/platform'; | import { CorePlatform } from '@services/platform'; | ||||||
| import { CoreSites } from '@services/sites'; | import { CoreSites } from '@services/sites'; | ||||||
| import { CoreDomUtils } from '@services/utils/dom'; | import { CoreDomUtils } from '@services/utils/dom'; | ||||||
| @ -151,6 +152,13 @@ export class CoreSettingsDevPage implements OnInit { | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Open error log. | ||||||
|  |      */ | ||||||
|  |     openErrorLog(): void { | ||||||
|  |         CoreNavigator.navigate('error-log'); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Copies site info. |      * Copies site info. | ||||||
|      */ |      */ | ||||||
|  | |||||||
							
								
								
									
										51
									
								
								src/core/features/settings/pages/error-log/error-log.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/core/features/settings/pages/error-log/error-log.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | |||||||
|  | <ion-header> | ||||||
|  |     <ion-toolbar> | ||||||
|  |         <ion-buttons slot="start"> | ||||||
|  |             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||||
|  |         </ion-buttons> | ||||||
|  | 
 | ||||||
|  |         <ion-title> | ||||||
|  |             <h1>Error log</h1> | ||||||
|  |         </ion-title> | ||||||
|  | 
 | ||||||
|  |         <ion-buttons slot="end" *ngIf="errorLogs.length"> | ||||||
|  |             <ion-button fill="clear" (click)="copyInfo()" [attr.aria-label]="'core.settings.copyinfo' | translate"> | ||||||
|  |                 <ion-icon slot="icon-only" name="fas-clipboard" aria-hidden="true"></ion-icon> | ||||||
|  |             </ion-button> | ||||||
|  |         </ion-buttons> | ||||||
|  |     </ion-toolbar> | ||||||
|  | </ion-header> | ||||||
|  | 
 | ||||||
|  | <ion-content> | ||||||
|  |     <ion-list *ngIf="errorLogs.length; else noLogs"> | ||||||
|  |         <ion-item button lines="full" class="ion-text-wrap" *ngFor="let error of errorLogs"> | ||||||
|  |             <div class="ion-padding" [collapsible-item]="96"> | ||||||
|  |                 <p class="item-heading">Trace</p> | ||||||
|  |                 <p class="ion-text-wrap">{{ error.message }}</p> | ||||||
|  | 
 | ||||||
|  |                 <ng-container *ngIf="error.method"> | ||||||
|  |                     <p class="item-heading">Method</p> | ||||||
|  |                     <p class="ion-text-wrap">{{ error.method }}</p> | ||||||
|  |                 </ng-container> | ||||||
|  | 
 | ||||||
|  |                 <ng-container *ngIf="error.type"> | ||||||
|  |                     <p class="item-heading">Type</p> | ||||||
|  |                     <p class="ion-text-wrap">{{ error.type }}</p> | ||||||
|  |                 </ng-container> | ||||||
|  | 
 | ||||||
|  |                 <ng-container *ngIf="error.data"> | ||||||
|  |                     <p class="item-heading">Data</p> | ||||||
|  |                     <p class="ion-text-wrap">{{ error.data | json }}</p> | ||||||
|  |                 </ng-container> | ||||||
|  | 
 | ||||||
|  |                 <div *ngIf="error.time"> | ||||||
|  |                     <span class="ion-text-end">{{ error.time | coreFormatDate :'strftimedatetimeshort' }}</span> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </ion-item> | ||||||
|  |     </ion-list> | ||||||
|  |     <ng-template #noLogs> | ||||||
|  |         <core-empty-box message="No logs available" icon="fas-clipboard-question"> | ||||||
|  |         </core-empty-box> | ||||||
|  |     </ng-template> | ||||||
|  | </ion-content> | ||||||
| @ -0,0 +1,4 @@ | |||||||
|  | .timestamp { | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: end; | ||||||
|  | } | ||||||
							
								
								
									
										39
									
								
								src/core/features/settings/pages/error-log/error-log.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/core/features/settings/pages/error-log/error-log.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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.
 | ||||||
|  | 
 | ||||||
|  | import { Component, OnInit } from '@angular/core'; | ||||||
|  | import { CoreUtils } from '@services/utils/utils'; | ||||||
|  | import { CoreErrorLogs, CoreSettingsErrorLog } from '@singletons/error-logs'; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Page that displays the error logs. | ||||||
|  |  */ | ||||||
|  | @Component({ | ||||||
|  |     selector: 'page-core-app-settings-error-log', | ||||||
|  |     templateUrl: 'error-log.html', | ||||||
|  |     styleUrls: ['./error-log.scss'], | ||||||
|  | }) | ||||||
|  | export class CoreSettingsErrorLogPage implements OnInit { | ||||||
|  | 
 | ||||||
|  |     errorLogs: CoreSettingsErrorLog[] = []; | ||||||
|  | 
 | ||||||
|  |     ngOnInit(): void { | ||||||
|  |         this.errorLogs = CoreErrorLogs.getErrorLogs(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     copyInfo(): void { | ||||||
|  |         CoreUtils.copyToClipboard(JSON.stringify({ errors: this.errorLogs })); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -28,6 +28,7 @@ import { CoreSettingsAboutPage } from '@features/settings/pages/about/about'; | |||||||
| import { CoreSettingsLicensesPage } from '@features/settings/pages/licenses/licenses'; | import { CoreSettingsLicensesPage } from '@features/settings/pages/licenses/licenses'; | ||||||
| import { CoreSettingsDeviceInfoPage } from '@features/settings/pages/deviceinfo/deviceinfo'; | import { CoreSettingsDeviceInfoPage } from '@features/settings/pages/deviceinfo/deviceinfo'; | ||||||
| import { CoreSettingsDevPage } from '@features/settings/pages/dev/dev'; | import { CoreSettingsDevPage } from '@features/settings/pages/dev/dev'; | ||||||
|  | import { CoreSettingsErrorLogPage } from '@features/settings/pages/error-log/error-log'; | ||||||
| 
 | 
 | ||||||
| const sectionRoutes: Routes = [ | const sectionRoutes: Routes = [ | ||||||
|     { |     { | ||||||
| @ -86,6 +87,10 @@ const routes: Routes = [ | |||||||
|         path: 'about/deviceinfo/dev', |         path: 'about/deviceinfo/dev', | ||||||
|         component: CoreSettingsDevPage, |         component: CoreSettingsDevPage, | ||||||
|     }, |     }, | ||||||
|  |     { | ||||||
|  |         path: 'about/deviceinfo/dev/error-log', | ||||||
|  |         component: CoreSettingsErrorLogPage, | ||||||
|  |     }, | ||||||
|     { |     { | ||||||
|         path: 'about/licenses', |         path: 'about/licenses', | ||||||
|         component: CoreSettingsLicensesPage, |         component: CoreSettingsLicensesPage, | ||||||
| @ -106,6 +111,7 @@ const routes: Routes = [ | |||||||
|         CoreSettingsLicensesPage, |         CoreSettingsLicensesPage, | ||||||
|         CoreSettingsDeviceInfoPage, |         CoreSettingsDeviceInfoPage, | ||||||
|         CoreSettingsDevPage, |         CoreSettingsDevPage, | ||||||
|  |         CoreSettingsErrorLogPage, | ||||||
|     ], |     ], | ||||||
| }) | }) | ||||||
| export class CoreSettingsLazyModule {} | export class CoreSettingsLazyModule {} | ||||||
|  | |||||||
| @ -60,6 +60,7 @@ import { CoreCancellablePromise } from '@classes/cancellable-promise'; | |||||||
| import { CoreLang } from '@services/lang'; | import { CoreLang } from '@services/lang'; | ||||||
| import { CorePasswordModalParams, CorePasswordModalResponse } from '@components/password-modal/password-modal'; | import { CorePasswordModalParams, CorePasswordModalResponse } from '@components/password-modal/password-modal'; | ||||||
| import { CoreWSError } from '@classes/errors/wserror'; | import { CoreWSError } from '@classes/errors/wserror'; | ||||||
|  | import { CoreErrorLogs } from '@singletons/error-logs'; | ||||||
| 
 | 
 | ||||||
| /* | /* | ||||||
|  * "Utils" service with helper functions for UI, DOM elements and HTML code. |  * "Utils" service with helper functions for UI, DOM elements and HTML code. | ||||||
| @ -613,6 +614,7 @@ export class CoreDomUtilsProvider { | |||||||
| 
 | 
 | ||||||
|             // We received an object instead of a string. Search for common properties.
 |             // We received an object instead of a string. Search for common properties.
 | ||||||
|             errorMessage = CoreTextUtils.getErrorMessageFromError(error); |             errorMessage = CoreTextUtils.getErrorMessageFromError(error); | ||||||
|  |             CoreErrorLogs.addErrorLog({ message: JSON.stringify(error), type: errorMessage || '', time: new Date().getTime() }); | ||||||
|             if (!errorMessage) { |             if (!errorMessage) { | ||||||
|                 // No common properties found, just stringify it.
 |                 // No common properties found, just stringify it.
 | ||||||
|                 errorMessage = JSON.stringify(error); |                 errorMessage = JSON.stringify(error); | ||||||
|  | |||||||
| @ -43,6 +43,7 @@ import { CoreSiteError, CoreSiteErrorOptions } from '@classes/errors/siteerror'; | |||||||
| import { CoreUserGuestSupportConfig } from '@features/user/classes/support/guest-support-config'; | import { CoreUserGuestSupportConfig } from '@features/user/classes/support/guest-support-config'; | ||||||
| import { CoreSites } from '@services/sites'; | import { CoreSites } from '@services/sites'; | ||||||
| import { CoreLang, CoreLangFormat } from './lang'; | import { CoreLang, CoreLangFormat } from './lang'; | ||||||
|  | import { CoreErrorLogs } from '@singletons/error-logs'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * This service allows performing WS calls and download/upload files. |  * This service allows performing WS calls and download/upload files. | ||||||
| @ -412,9 +413,25 @@ export class CoreWSProvider { | |||||||
|         let promise: Promise<HttpResponse<any>>; |         let promise: Promise<HttpResponse<any>>; | ||||||
| 
 | 
 | ||||||
|         if (preSets.siteUrl === undefined) { |         if (preSets.siteUrl === undefined) { | ||||||
|             throw new CoreAjaxError(Translate.instant('core.unexpectederror')); |             const unexpectedError = new CoreAjaxError(Translate.instant('core.unexpectederror')); | ||||||
|  |             CoreErrorLogs.addErrorLog({ | ||||||
|  |                 method, | ||||||
|  |                 type: 'CoreAjaxError', | ||||||
|  |                 message: Translate.instant('core.unexpectederror'), | ||||||
|  |                 time: new Date().getTime(), | ||||||
|  |                 data, | ||||||
|  |             }); | ||||||
|  |             throw unexpectedError; | ||||||
|         } else if (!CoreNetwork.isOnline()) { |         } else if (!CoreNetwork.isOnline()) { | ||||||
|             throw new CoreAjaxError(Translate.instant('core.networkerrormsg')); |             const networkError = new CoreAjaxError(Translate.instant('core.networkerrormsg')); | ||||||
|  |             CoreErrorLogs.addErrorLog({ | ||||||
|  |                 method, | ||||||
|  |                 type: 'CoreAjaxError', | ||||||
|  |                 message: Translate.instant('core.networkerrormsg'), | ||||||
|  |                 time: new Date().getTime(), | ||||||
|  |                 data, | ||||||
|  |             }); | ||||||
|  |             throw networkError; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (preSets.responseExpected === undefined) { |         if (preSets.responseExpected === undefined) { | ||||||
| @ -552,6 +569,10 @@ export class CoreWSProvider { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             throw new CoreAjaxError(options, 1, data.status); |             throw new CoreAjaxError(options, 1, data.status); | ||||||
|  |         }).catch(error => { | ||||||
|  |             const type = `CoreAjaxError - ${error.errorcode}`; | ||||||
|  |             CoreErrorLogs.addErrorLog({ method, type, message: error, time: new Date().getTime(), data }); | ||||||
|  |             throw error; | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -782,6 +803,15 @@ export class CoreWSProvider { | |||||||
|             throw new CoreError(Translate.instant('core.serverconnection', { |             throw new CoreError(Translate.instant('core.serverconnection', { | ||||||
|                 details: CoreTextUtils.getErrorMessageFromError(error) ?? 'Unknown error', |                 details: CoreTextUtils.getErrorMessageFromError(error) ?? 'Unknown error', | ||||||
|             })); |             })); | ||||||
|  |         }).catch(err => { | ||||||
|  |             CoreErrorLogs.addErrorLog({ | ||||||
|  |                 method, | ||||||
|  |                 type: String(err), | ||||||
|  |                 message: String(err.exception), | ||||||
|  |                 time: new Date().getTime(), | ||||||
|  |                 data: ajaxData, | ||||||
|  |             }); | ||||||
|  |             throw err; | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -847,6 +877,7 @@ export class CoreWSProvider { | |||||||
|      */ |      */ | ||||||
|     // eslint-disable-next-line @typescript-eslint/no-explicit-any
 |     // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | ||||||
|     syncCall<T = unknown>(method: string, data: any, preSets: CoreWSPreSets): T { |     syncCall<T = unknown>(method: string, data: any, preSets: CoreWSPreSets): T { | ||||||
|  |         try { | ||||||
|             if (!preSets) { |             if (!preSets) { | ||||||
|                 throw new CoreError(Translate.instant('core.unexpectederror')); |                 throw new CoreError(Translate.instant('core.unexpectederror')); | ||||||
|             } else if (!CoreNetwork.isOnline()) { |             } else if (!CoreNetwork.isOnline()) { | ||||||
| @ -912,6 +943,18 @@ export class CoreWSProvider { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             return data; |             return data; | ||||||
|  |         } catch (err) { | ||||||
|  |             let errorType = ''; | ||||||
|  | 
 | ||||||
|  |             if (err instanceof CoreError) { | ||||||
|  |                 errorType = 'CoreError'; | ||||||
|  |             } else if (err instanceof CoreWSError) { | ||||||
|  |                 errorType = 'CoreWSError'; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             CoreErrorLogs.addErrorLog({ method, type: errorType, message: String(err), time: new Date().getTime(), data }); | ||||||
|  |             throw err; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* |     /* | ||||||
|  | |||||||
							
								
								
									
										53
									
								
								src/core/singletons/error-logs.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/core/singletons/error-logs.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | |||||||
|  | // (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 { makeSingleton } from '@singletons'; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Service that stores error logs in memory. | ||||||
|  |  */ | ||||||
|  | @Injectable({ providedIn: 'root' }) | ||||||
|  | export class CoreErrorLogsService { | ||||||
|  | 
 | ||||||
|  |     protected errorLogs: CoreSettingsErrorLog[] = []; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Retrieve error logs displayed in the DOM. | ||||||
|  |      * | ||||||
|  |      * @returns Error logs | ||||||
|  |      */ | ||||||
|  |     getErrorLogs(): CoreSettingsErrorLog[] { | ||||||
|  |         return this.errorLogs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Add an error to error logs list. | ||||||
|  |      * | ||||||
|  |      * @param error Error. | ||||||
|  |      */ | ||||||
|  |     addErrorLog(error: CoreSettingsErrorLog): void { | ||||||
|  |         this.errorLogs.push(error); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const CoreErrorLogs = makeSingleton(CoreErrorLogsService); | ||||||
|  | 
 | ||||||
|  | export type CoreSettingsErrorLog = { | ||||||
|  |     data?: unknown; | ||||||
|  |     message: string; | ||||||
|  |     method?: string; | ||||||
|  |     time: number; | ||||||
|  |     type: string; | ||||||
|  | }; | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user