diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 34f532110..2496e0fcf 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -25,11 +25,11 @@ "@ng-web-apis/resize-observer": "^2.0.0", "@start9labs/argon2": "^0.1.0", "@start9labs/emver": "^0.1.5", - "@taiga-ui/addon-charts": "3.24.0", - "@taiga-ui/cdk": "3.24.0", - "@taiga-ui/core": "3.24.0", - "@taiga-ui/icons": "3.24.0", - "@taiga-ui/kit": "3.24.0", + "@taiga-ui/addon-charts": "3.25.0", + "@taiga-ui/cdk": "3.25.0", + "@taiga-ui/core": "3.25.0", + "@taiga-ui/icons": "3.25.0", + "@taiga-ui/kit": "3.25.0", "angular-svg-round-progressbar": "^9.0.0", "ansi-to-html": "^0.7.2", "base64-js": "^1.5.1", @@ -3818,9 +3818,9 @@ } }, "node_modules/@taiga-ui/addon-charts": { - "version": "3.24.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/addon-charts/-/addon-charts-3.24.0.tgz", - "integrity": "sha512-0pbRO8n6nNllgDwLJV0fY5+KOVzfVftGWeaV4AYRIFpoBU9voT8SqnIAu2Rotk/ze+sa8WqXPjnWM1fHvX4Z+g==", + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/addon-charts/-/addon-charts-3.25.0.tgz", + "integrity": "sha512-XE5s6XYjZYgxjO8sygVRVE5Cy2cAGMsRkX+nbpVCFaf0fMLhgpaWYzT7VnuddgVqaYtpLHb+mUMYkV8H83wX5w==", "dependencies": { "tslib": ">=2.0.0" }, @@ -3828,21 +3828,21 @@ "@angular/common": ">=12.0.0", "@angular/core": ">=12.0.0", "@ng-web-apis/common": ">=2.0.0", - "@taiga-ui/cdk": ">=3.24.0", - "@taiga-ui/core": ">=3.24.0", + "@taiga-ui/cdk": ">=3.25.0", + "@taiga-ui/core": ">=3.25.0", "@tinkoff/ng-polymorpheus": ">=4.0.0" } }, "node_modules/@taiga-ui/cdk": { - "version": "3.24.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/cdk/-/cdk-3.24.0.tgz", - "integrity": "sha512-FsTWG6KchhqenGT5YOGfDO5Wy6DNfhcqZzif40cxv0kgZO7d97EdE0F5J0Tda/wJwu5cdlM4u2avUcaHGaKsHA==", + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/cdk/-/cdk-3.25.0.tgz", + "integrity": "sha512-dHV5FdYiq5qBOJRyWqu+iwc2dxHtBHGK6xQXd+yk3FRXuAsfj22cZl1i3TL8RQptQZjL+6AyHKABTga6uUMliA==", "dependencies": { "@ng-web-apis/common": "2.1.0", "@ng-web-apis/mutation-observer": "2.0.0", "@ng-web-apis/resize-observer": "2.0.0", "@tinkoff/ng-event-plugins": "3.1.0", - "@tinkoff/ng-polymorpheus": "4.0.11", + "@tinkoff/ng-polymorpheus": "4.1.0", "tslib": "2.5.0" }, "optionalDependencies": { @@ -3857,23 +3857,12 @@ "rxjs": ">=6.0.0" } }, - "node_modules/@taiga-ui/cdk/node_modules/@tinkoff/ng-polymorpheus": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/@tinkoff/ng-polymorpheus/-/ng-polymorpheus-4.0.11.tgz", - "integrity": "sha512-pRU4crK5pW4RPnEuvPq+sE3fgy5xqcdMfmfqQzd+OBRNGNJx8pFrzY1yXFEkC00pNl7/fZEVelXqe8v5MltAdw==", - "dependencies": { - "tslib": "^2.0.0" - }, - "peerDependencies": { - "@angular/core": ">=12.0.0" - } - }, "node_modules/@taiga-ui/core": { - "version": "3.24.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/core/-/core-3.24.0.tgz", - "integrity": "sha512-PPNE2I7yTZlVdis+Zd09dV21OspOPhe/VXPrWNM+J2A3vmxMAMwAR5i8qAoS6rBfUWpI/5vXImQSmvztXQQJeg==", + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/core/-/core-3.25.0.tgz", + "integrity": "sha512-I2ezwnWJcVEMqnMXKdBWQn7IPJYbTttFqPVrzW0UhmUGyp8eI++v2A8I+Ns/I8oDCSb/kwhbFIXmXCFZQBoWZg==", "dependencies": { - "@taiga-ui/i18n": "^3.24.0", + "@taiga-ui/i18n": "^3.25.0", "tslib": ">=2.0.0" }, "peerDependencies": { @@ -3885,17 +3874,17 @@ "@angular/router": ">=12.0.0", "@ng-web-apis/common": ">=2.0.0", "@ng-web-apis/mutation-observer": ">=2.0.0", - "@taiga-ui/cdk": ">=3.24.0", - "@taiga-ui/i18n": ">=3.24.0", + "@taiga-ui/cdk": ">=3.25.0", + "@taiga-ui/i18n": ">=3.25.0", "@tinkoff/ng-event-plugins": ">=3.1.0", "@tinkoff/ng-polymorpheus": ">=4.0.0", "rxjs": ">=6.0.0" } }, "node_modules/@taiga-ui/i18n": { - "version": "3.24.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/i18n/-/i18n-3.24.0.tgz", - "integrity": "sha512-fPzY18AWoQXdvt0+5E59dTFGV853A+g9j81QrzxF+YH+ToroxnkZHcL6bXj0RUi4r40j69cvs0H3FlfyvC3PNA==", + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/i18n/-/i18n-3.25.0.tgz", + "integrity": "sha512-E/lLv84soT2qgu6q3ilF1bUOriMfW052QYpORYrJQvF9O1hxTLW5yv7AYEPYHnJFXEvt7rLFyvjoI56bFeLryw==", "dependencies": { "tslib": ">=2.0.0" }, @@ -3905,17 +3894,17 @@ } }, "node_modules/@taiga-ui/icons": { - "version": "3.24.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/icons/-/icons-3.24.0.tgz", - "integrity": "sha512-3cwKEraJs0JmMrn266NYjHBGqMo1PXMHMU0U2mz9SVmenStAMn2FdXRlRB5TZWd6JksIKu2e+JPqCDW6Ge2K6w==", + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/icons/-/icons-3.25.0.tgz", + "integrity": "sha512-kXsKCifldnmrk/HcVZ8HqX68gHyZXsskaH0mrgq4CE3/8iiVmUBtqkgay1Rc6dubmzlPjD7/fr9nl/Wkf9zALA==", "dependencies": { "tslib": "^2.2.0" } }, "node_modules/@taiga-ui/kit": { - "version": "3.24.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/kit/-/kit-3.24.0.tgz", - "integrity": "sha512-8p1ithoSOhKJqJQ+dJpUiGTNz85UfukeG39lqmJjUZlnW37seiGTYQsYKxg6LD8HoVXNptUQWwAx/X1k0i6Q2g==", + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/kit/-/kit-3.25.0.tgz", + "integrity": "sha512-mLTpcwpkMrwo8WPtezhJTBcvNPvQwZOUuMD3LkEWQ9g04o3flg+W9W6TJTQeg7Eqwp8ciq/INuSMcsmzgBd2uA==", "dependencies": { "@ng-web-apis/intersection-observer": "3.0.0", "text-mask-core": "5.1.2", @@ -3929,9 +3918,9 @@ "@ng-web-apis/common": ">=2.0.0", "@ng-web-apis/mutation-observer": ">=2.0.0", "@ng-web-apis/resize-observer": ">=2.0.0", - "@taiga-ui/cdk": ">=3.24.0", - "@taiga-ui/core": ">=3.24.0", - "@taiga-ui/i18n": ">=3.24.0", + "@taiga-ui/cdk": ">=3.25.0", + "@taiga-ui/core": ">=3.25.0", + "@taiga-ui/i18n": ">=3.25.0", "@tinkoff/ng-polymorpheus": ">=4.0.0", "rxjs": ">=6.0.0" } @@ -3953,7 +3942,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/@tinkoff/ng-polymorpheus/-/ng-polymorpheus-4.1.0.tgz", "integrity": "sha512-rhe7Fe+rTK5cqfbeySy9fmwBilgMUGkSVX4rrkpmPRSTDhSh/djrRUW0q5ukbN56Rx/AKSYZ5B/nEqY+HL1jZg==", - "peer": true, "dependencies": { "tslib": "^2.0.0" }, diff --git a/frontend/package.json b/frontend/package.json index dabc529ca..90474eab2 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -50,11 +50,11 @@ "@ng-web-apis/resize-observer": "^2.0.0", "@start9labs/argon2": "^0.1.0", "@start9labs/emver": "^0.1.5", - "@taiga-ui/addon-charts": "3.24.0", - "@taiga-ui/cdk": "3.24.0", - "@taiga-ui/core": "3.24.0", - "@taiga-ui/icons": "3.24.0", - "@taiga-ui/kit": "3.24.0", + "@taiga-ui/addon-charts": "3.25.0", + "@taiga-ui/cdk": "3.25.0", + "@taiga-ui/core": "3.25.0", + "@taiga-ui/icons": "3.25.0", + "@taiga-ui/kit": "3.25.0", "angular-svg-round-progressbar": "^9.0.0", "ansi-to-html": "^0.7.2", "base64-js": "^1.5.1", diff --git a/frontend/projects/shared/src/public-api.ts b/frontend/projects/shared/src/public-api.ts index a14ff0110..3e88cd75f 100644 --- a/frontend/projects/shared/src/public-api.ts +++ b/frontend/projects/shared/src/public-api.ts @@ -40,6 +40,7 @@ export * from './pipes/unit-conversion/unit-conversion.pipe' export * from './services/download-html.service' export * from './services/emver.service' +export * from './services/error.service' export * from './services/error-toast.service' export * from './services/http.service' diff --git a/frontend/projects/shared/src/services/error.service.ts b/frontend/projects/shared/src/services/error.service.ts new file mode 100644 index 000000000..bb0221ce2 --- /dev/null +++ b/frontend/projects/shared/src/services/error.service.ts @@ -0,0 +1,43 @@ +import { ErrorHandler, inject, Injectable } from '@angular/core' +import { TuiAlertService, TuiNotification } from '@taiga-ui/core' +import { HttpError } from '../classes/http-error' + +// TODO: Enable this as ErrorHandler +@Injectable({ + providedIn: 'root', +}) +export class ErrorService extends ErrorHandler { + private readonly alerts = inject(TuiAlertService) + + override handleError(error: HttpError | string, link?: string) { + console.error(error) + + this.alerts + .open(getErrorMessage(error, link), { + label: 'Error', + autoClose: false, + status: TuiNotification.Error, + }) + .subscribe() + } +} + +function getErrorMessage(e: HttpError | string, link?: string): string { + let message = '' + + if (typeof e === 'string') { + message = e + } else if (e.code === 0) { + message = + 'Request Error. Your browser blocked the request. This is usually caused by a corrupt browser cache or an overly aggressive ad blocker. Please clear your browser cache and/or adjust your ad blocker and try again' + } else if (!e.message) { + message = 'Unknown Error' + link = 'https://docs.start9.com/latest/support/faq' + } else { + message = e.message + } + + return link + ? `${message}

Get Help` + : message +} diff --git a/frontend/projects/ui/src/app/modals/form/form.page.html b/frontend/projects/ui/src/app/modals/form/form.page.html index f845ad627..58854a691 100644 --- a/frontend/projects/ui/src/app/modals/form/form.page.html +++ b/frontend/projects/ui/src/app/modals/form/form.page.html @@ -1,5 +1,5 @@
, private readonly api: ApiService, @@ -46,26 +45,21 @@ export class DevConfigPage { try { doc = yaml.load(this.code) } catch (e: any) { - this.errToast.present(e) + this.errorHandler.handleError(e) } - const options: GenericFormOptions = { - title: 'Config Sample', - spec: JSON.parse(JSON.stringify(doc, null, 2)), - buttons: [ - { - text: 'OK', - handler: async () => true, - isSubmit: true, - }, - ], - } - - const modal = await this.modalCtrl.create({ - component: GenericFormPage, - componentProps: options, + this.formDialog.open(FormPage, { + label: 'Config Sample', + data: { + spec: JSON.parse(JSON.stringify(doc, null, 2)), + buttons: [ + { + text: 'OK', + handler: async () => true, + }, + ], + }, }) - await modal.present() } @debounce(1000) @@ -77,7 +71,7 @@ export class DevConfigPage { this.code, ) } catch (e: any) { - this.errToast.present(e) + this.errorHandler.handleError(e) } finally { this.saving = false } diff --git a/frontend/projects/ui/src/app/pages/developer-routes/developer-menu/developer-menu.page.ts b/frontend/projects/ui/src/app/pages/developer-routes/developer-menu/developer-menu.page.ts index 836d67425..7ebba9d90 100644 --- a/frontend/projects/ui/src/app/pages/developer-routes/developer-menu/developer-menu.page.ts +++ b/frontend/projects/ui/src/app/pages/developer-routes/developer-menu/developer-menu.page.ts @@ -1,16 +1,14 @@ import { ChangeDetectionStrategy, Component } from '@angular/core' import { ActivatedRoute } from '@angular/router' -import { LoadingController, ModalController } from '@ionic/angular' -import { - GenericFormPage, - GenericFormOptions, -} from 'src/app/modals/generic-form/generic-form.page' import { BasicInfo, getBasicInfoSpec } from './form-info' import { PatchDB } from 'patch-db-client' import { ApiService } from 'src/app/services/api/embassy-api.service' -import { ErrorToastService } from '@start9labs/shared' +import { ErrorService } from '@start9labs/shared' import { getProjectId } from 'src/app/util/get-project-id' import { DataModel, DevProjectData } from 'src/app/services/patch-db/data-model' +import { FormDialogService } from '../../../services/form-dialog.service' +import { FormPage } from '../../../modals/form/form.page' +import { LoadingService } from '../../../modals/loading/loading.service' @Component({ selector: 'developer-menu', @@ -23,40 +21,32 @@ export class DeveloperMenuPage { readonly projectData$ = this.patch.watch$('ui', 'dev', this.projectId) constructor( + private readonly formDialog: FormDialogService, + private readonly loader: LoadingService, + private readonly errorHandler: ErrorService, private readonly route: ActivatedRoute, - private readonly modalCtrl: ModalController, - private readonly loadingCtrl: LoadingController, private readonly api: ApiService, - private readonly errToast: ErrorToastService, private readonly patch: PatchDB, ) {} async openBasicInfoModal(data: DevProjectData) { - const options: GenericFormOptions = { - title: 'Basic Info', - spec: getBasicInfoSpec(data), - buttons: [ - { - text: 'Save', - handler: async (basicInfo: BasicInfo) => - this.saveBasicInfo(basicInfo), - isSubmit: true, - }, - ], - } - - const modal = await this.modalCtrl.create({ - component: GenericFormPage, - componentProps: options, + this.formDialog.open(FormPage, { + label: 'Basic Info', + data: { + spec: getBasicInfoSpec(data), + buttons: [ + { + text: 'Save', + handler: async (basicInfo: BasicInfo) => + this.saveBasicInfo(basicInfo), + }, + ], + }, }) - await modal.present() } async saveBasicInfo(basicInfo: BasicInfo): Promise { - const loader = await this.loadingCtrl.create({ - message: 'Saving...', - }) - await loader.present() + const loader = this.loader.open('Saving...').subscribe() try { await this.api.setDbValue( @@ -65,10 +55,10 @@ export class DeveloperMenuPage { ) return true } catch (e: any) { - this.errToast.present(e) + this.errorHandler.handleError(e) return false } finally { - loader.dismiss() + loader.unsubscribe() } } }