diff --git a/apps/back-office/src/app/app-preview/pages/dashboard/dashboard.component.ts b/apps/back-office/src/app/app-preview/pages/dashboard/dashboard.component.ts index 2fadac1366..226ff819fb 100644 --- a/apps/back-office/src/app/app-preview/pages/dashboard/dashboard.component.ts +++ b/apps/back-office/src/app/app-preview/pages/dashboard/dashboard.component.ts @@ -84,25 +84,20 @@ export class DashboardComponent this.widgets = cloneDeep( data.dashboard.structure ? data.dashboard.structure : [] ); - this.loading = loading; - } else { - this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.accessNotProvided', - { - type: this.translate - .instant('common.dashboard.one') - .toLowerCase(), - error: '', - } - ), - { error: true } - ); - this.router.navigate(['/dashboards']); } + this.loading = loading; }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: () => { + this.loading = false; + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.accessNotProvided', { + type: this.translate + .instant('common.dashboard.one') + .toLowerCase(), + error: '', + }), + { error: true } + ); this.router.navigate(['/dashboards']); }, }); diff --git a/apps/back-office/src/app/app-preview/pages/form/form.component.ts b/apps/back-office/src/app/app-preview/pages/form/form.component.ts index f7fb9f917d..a1b16bc2d0 100644 --- a/apps/back-office/src/app/app-preview/pages/form/form.component.ts +++ b/apps/back-office/src/app/app-preview/pages/form/form.component.ts @@ -96,9 +96,14 @@ export class FormComponent extends UnsubscribeComponent implements OnInit { }); }) ) - .subscribe(({ data, loading }) => { - this.form = data.form; - this.loading = loading; + .subscribe({ + next: ({ data, loading }) => { + this.form = data.form; + this.loading = loading; + }, + error: () => { + this.loading = false; + }, }); } else { this.apollo @@ -119,11 +124,16 @@ export class FormComponent extends UnsubscribeComponent implements OnInit { }); }) ) - .subscribe(({ data, loading }) => { - if (data) { - this.form = data.form; - } - this.loading = loading; + .subscribe({ + next: ({ data, loading }) => { + if (data) { + this.form = data.form; + } + this.loading = loading; + }, + error: () => { + this.loading = false; + }, }); } }); diff --git a/apps/back-office/src/app/app-preview/pages/workflow/workflow.component.ts b/apps/back-office/src/app/app-preview/pages/workflow/workflow.component.ts index df2433f367..2a3d50ead6 100644 --- a/apps/back-office/src/app/app-preview/pages/workflow/workflow.component.ts +++ b/apps/back-office/src/app/app-preview/pages/workflow/workflow.component.ts @@ -108,20 +108,17 @@ export class WorkflowComponent extends UnsubscribeComponent implements OnInit { if (this.steps.length > 0) { this.onOpenStep(0); } - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.accessNotProvided', { - type: this.translate - .instant('common.workflow.one') - .toLowerCase(), - error: '', - }), - { error: true } - ); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: () => { + this.loading = false; + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.accessNotProvided', { + type: this.translate.instant('common.workflow.one').toLowerCase(), + error: '', + }), + { error: true } + ); }, }); } diff --git a/apps/back-office/src/app/app.module.ts b/apps/back-office/src/app/app.module.ts index 533f0b2fe0..a5fae78dd4 100644 --- a/apps/back-office/src/app/app.module.ts +++ b/apps/back-office/src/app/app.module.ts @@ -29,6 +29,7 @@ import { AppAbility, FormService, DatePipe, + ErrorHandlerInterceptorService, } from '@oort-front/shared'; import { registerLocaleData } from '@angular/common'; import localeFr from '@angular/common/locales/fr'; @@ -146,6 +147,11 @@ export const httpTranslateLoader = (http: HttpClient) => useClass: AuthInterceptorService, multi: true, }, + { + provide: HTTP_INTERCEPTORS, + useClass: ErrorHandlerInterceptorService, + multi: true, + }, { provide: AppAbility, useValue: new AppAbility(), diff --git a/apps/back-office/src/app/application/pages/add-page/add-page.component.ts b/apps/back-office/src/app/application/pages/add-page/add-page.component.ts index 3077bf8842..0a390965c5 100644 --- a/apps/back-office/src/app/application/pages/add-page/add-page.component.ts +++ b/apps/back-office/src/app/application/pages/add-page/add-page.component.ts @@ -9,6 +9,7 @@ import { UnsubscribeComponent, FormsQueryResponse, AddFormMutationResponse, + errorMessageFormatter, } from '@oort-front/shared'; import { takeUntil } from 'rxjs'; import { ADD_FORM } from './graphql/mutations'; @@ -180,35 +181,31 @@ export class AddPageComponent extends UnsubscribeComponent implements OnInit { variables: variablesData, }) .subscribe({ - next: ({ errors, data }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.objectNotCreated', - { - type: this.translate - .instant('common.form.one') - .toLowerCase(), - error: errors ? errors[0].message : '', - } - ), - { error: true } - ); - } else { - const id = data?.addForm.id || ''; - this.pageForm.controls.content.setValue(id); - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectCreated', { - type: this.translate.instant('common.page.one'), - value: value.name, - }) - ); + next: ({ data }) => { + const id = data?.addForm.id || ''; + this.pageForm.controls.content.setValue(id); + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectCreated', { + type: this.translate.instant('common.page.one'), + value: value.name, + }) + ); - this.onSubmit(); - } + this.onSubmit(); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant( + 'common.notifications.objectNotCreated', + { + type: this.translate + .instant('common.form.one') + .toLowerCase(), + error: errorMessageFormatter(errors), + } + ), + { error: true } + ); }, }); } diff --git a/apps/back-office/src/app/application/pages/archive/archive.component.ts b/apps/back-office/src/app/application/pages/archive/archive.component.ts index 7644c31f79..4eca0cabe8 100644 --- a/apps/back-office/src/app/application/pages/archive/archive.component.ts +++ b/apps/back-office/src/app/application/pages/archive/archive.component.ts @@ -89,22 +89,18 @@ export class ArchiveComponent extends UnsubscribeComponent implements OnInit { autoDeletedAt: page.autoDeletedAt, } as ArchivePage; }) ?? []; - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.accessNotProvided', { - type: this.translate - .instant('common.workflow.one') - .toLowerCase(), - error: '', - }), - { error: true } - ); } this.loading = false; }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: () => { this.loading = false; + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.accessNotProvided', { + type: this.translate.instant('common.workflow.one').toLowerCase(), + error: '', + }), + { error: true } + ); }, }); } diff --git a/apps/back-office/src/app/application/pages/form/form.component.ts b/apps/back-office/src/app/application/pages/form/form.component.ts index 9a348d80a7..9c83f36835 100644 --- a/apps/back-office/src/app/application/pages/form/form.component.ts +++ b/apps/back-office/src/app/application/pages/form/form.component.ts @@ -127,18 +127,23 @@ export class FormComponent extends UnsubscribeComponent implements OnInit { }), takeUntil(this.destroy$) ) - .subscribe((res: any) => { - // If a query is already loading, cancel it - if (this.querySubscription) { - this.querySubscription.unsubscribe(); - } - if (this.isStep) { - this.handleFormQueryResponse(res.data, 'step'); - this.loading = res.loading; - } else { - this.handleFormQueryResponse(res.data, 'page'); - this.loading = res.loading; - } + .subscribe({ + next: (res: any) => { + // If a query is already loading, cancel it + if (this.querySubscription) { + this.querySubscription.unsubscribe(); + } + if (this.isStep) { + this.handleFormQueryResponse(res.data, 'step'); + this.loading = res.loading; + } else { + this.handleFormQueryResponse(res.data, 'page'); + this.loading = res.loading; + } + }, + error: () => { + this.loading = false; + }, }); } diff --git a/apps/back-office/src/app/application/pages/position-attributes/position-attributes.component.ts b/apps/back-office/src/app/application/pages/position-attributes/position-attributes.component.ts index 1844b89574..9807feb2e8 100644 --- a/apps/back-office/src/app/application/pages/position-attributes/position-attributes.component.ts +++ b/apps/back-office/src/app/application/pages/position-attributes/position-attributes.component.ts @@ -56,13 +56,22 @@ export class PositionAttributesComponent implements OnInit { id: this.id, }, }) - .subscribe(({ data, loading }) => { - this.positionAttributes = data.positionAttributes; - if (this.positionAttributes.length > 0) { - this.categoryName = this.positionAttributes[0].category?.title || ''; - this.breadcrumbService.setBreadcrumb('@attribute', this.categoryName); - } - this.loading = loading; + .subscribe({ + next: ({ data, loading }) => { + this.positionAttributes = data.positionAttributes; + if (this.positionAttributes.length > 0) { + this.categoryName = + this.positionAttributes[0].category?.title || ''; + this.breadcrumbService.setBreadcrumb( + '@attribute', + this.categoryName + ); + } + this.loading = loading; + }, + error: () => { + this.loading = false; + }, }); } } diff --git a/apps/back-office/src/app/application/pages/settings/settings.component.ts b/apps/back-office/src/app/application/pages/settings/settings.component.ts index dad98feeef..66737ca2b6 100644 --- a/apps/back-office/src/app/application/pages/settings/settings.component.ts +++ b/apps/back-office/src/app/application/pages/settings/settings.component.ts @@ -8,6 +8,7 @@ import { UnsubscribeComponent, DeleteApplicationMutationResponse, status, + errorMessageFormatter, } from '@oort-front/shared'; import { Dialog } from '@angular/cdk/dialog'; import { DELETE_APPLICATION } from './graphql/mutations'; @@ -168,28 +169,21 @@ export class SettingsComponent extends UnsubscribeComponent implements OnInit { takeUntil(this.destroy$) ) .subscribe({ - next: ({ errors }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.objectNotDeleted', - { - value: this.translate.instant('common.application.one'), - error: errors ? errors[0].message : '', - } - ), - { error: true } - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectDeleted', { - value: this.translate.instant('common.application.one'), - }) - ); - } + next: () => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectDeleted', { + value: this.translate.instant('common.application.one'), + }) + ); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotDeleted', { + value: this.translate.instant('common.application.one'), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, complete: () => this.router.navigate(['/applications']), }); diff --git a/apps/back-office/src/app/application/pages/subscriptions/components/subscription-modal/subscription-modal.component.ts b/apps/back-office/src/app/application/pages/subscriptions/components/subscription-modal/subscription-modal.component.ts index 1342220808..d6a638b8bc 100644 --- a/apps/back-office/src/app/application/pages/subscriptions/components/subscription-modal/subscription-modal.component.ts +++ b/apps/back-office/src/app/application/pages/subscriptions/components/subscription-modal/subscription-modal.component.ts @@ -165,8 +165,13 @@ export class SubscriptionModalComponent // this.applications$ = this.applications.asObservable(); this.applicationsQuery.valueChanges .pipe(takeUntil(this.destroy$)) - .subscribe((results) => { - this.updateValues(results.data, results.loading); + .subscribe({ + next: (results) => { + this.updateValues(results.data, results.loading); + }, + error: () => { + this.applicationsLoading = false; + }, }); this.formsQuery = this.apollo.watchQuery({ diff --git a/apps/back-office/src/app/application/pages/workflow/workflow.component.ts b/apps/back-office/src/app/application/pages/workflow/workflow.component.ts index a1ab1afecf..39063d869a 100644 --- a/apps/back-office/src/app/application/pages/workflow/workflow.component.ts +++ b/apps/back-office/src/app/application/pages/workflow/workflow.component.ts @@ -14,6 +14,7 @@ import { UnsubscribeComponent, DeleteStepMutationResponse, EditWorkflowMutationResponse, + errorMessageFormatter, } from '@oort-front/shared'; import { DELETE_STEP, EDIT_WORKFLOW } from './graphql/mutations'; import { TranslateService } from '@ngx-translate/core'; @@ -247,42 +248,35 @@ export class WorkflowComponent extends UnsubscribeComponent implements OnInit { takeUntil(this.destroy$) ) .subscribe({ - next: ({ errors, data }) => { - if (errors) { + next: ({ data }) => { + if (data) { this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.objectNotDeleted', - { - value: this.translate.instant('common.step.one'), - error: errors ? errors[0].message : '', - } - ), - { error: true } + this.translate.instant('common.notifications.objectDeleted', { + value: this.translate.instant('common.step.one'), + }) ); - } else { - if (data) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectDeleted', { - value: this.translate.instant('common.step.one'), - }) - ); - this.steps = this.steps.filter( - (x) => x.id !== data?.deleteStep.id - ); - if (index === this.activeStep) { - this.onOpenStep(-1); - } else { - if (currentStep) { - this.activeStep = this.steps.findIndex( - (x) => x.id === currentStep.id - ); - } + this.steps = this.steps.filter( + (x) => x.id !== data?.deleteStep.id + ); + if (index === this.activeStep) { + this.onOpenStep(-1); + } else { + if (currentStep) { + this.activeStep = this.steps.findIndex( + (x) => x.id === currentStep.id + ); } } } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotDeleted', { + value: this.translate.instant('common.step.one'), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } @@ -338,7 +332,7 @@ export class WorkflowComponent extends UnsubscribeComponent implements OnInit { }, }) .subscribe({ - next: ({ errors, data }) => { + next: ({ data }) => { if (data) { this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectReordered', { @@ -350,18 +344,16 @@ export class WorkflowComponent extends UnsubscribeComponent implements OnInit { this.activeStep = index; } this.steps = steps; - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotUpdated', { - type: this.translate.instant('common.workflow.one'), - error: errors ? errors[0].message : '', - }), - { error: true } - ); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotUpdated', { + type: this.translate.instant('common.workflow.one'), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } diff --git a/apps/back-office/src/app/components/add-form-modal/add-form-modal.component.ts b/apps/back-office/src/app/components/add-form-modal/add-form-modal.component.ts index 81a53fc9d0..f13c2a2da9 100644 --- a/apps/back-office/src/app/components/add-form-modal/add-form-modal.component.ts +++ b/apps/back-office/src/app/components/add-form-modal/add-form-modal.component.ts @@ -155,8 +155,10 @@ export class AddFormModalComponent id, }, }) - .subscribe(({ data }) => { - this.templates = data.resource.forms || []; + .subscribe({ + next: ({ data }) => { + this.templates = data.resource.forms || []; + }, }); } } diff --git a/apps/back-office/src/app/components/dashboard-filter-settings/dashboard-filter-settings.component.ts b/apps/back-office/src/app/components/dashboard-filter-settings/dashboard-filter-settings.component.ts index 55a98fb986..90c4103334 100644 --- a/apps/back-office/src/app/components/dashboard-filter-settings/dashboard-filter-settings.component.ts +++ b/apps/back-office/src/app/components/dashboard-filter-settings/dashboard-filter-settings.component.ts @@ -139,21 +139,32 @@ export class DashboardFilterSettingsComponent }, }) .subscribe({ - next: ({ errors }) => { + next: () => { + this.dashboardService.handleEditionMutationResponse( + [], + this.translate.instant('common.dashboard.one') + ); + const filter = value; + this.dashboard = { + ...this.dashboard, + filter, + }; + // Updates parent component + const updates = { filter }; + this.parentComponent.onUpdate.emit(updates); + }, + error: (errors) => { this.dashboardService.handleEditionMutationResponse( errors, this.translate.instant('common.dashboard.one') ); - if (!errors) { - const filter = value; - this.dashboard = { - ...this.dashboard, - filter, - }; - // Updates parent component - const updates = { filter }; - this.parentComponent.onUpdate.emit(updates); - } + this.contextService.isFilterEnabled.next(value.show); + this.contextService.filterPosition.next({ + position: + (this.dashboard.filter?.position as FilterPosition) || + FilterPosition.BOTTOM, + dashboardId: this.dashboard.id ?? '', + }); }, complete: () => { this.contextService.isFilterEnabled.next(value.show); diff --git a/apps/back-office/src/app/components/duplicate-application-modal/duplicate-application-modal.component.ts b/apps/back-office/src/app/components/duplicate-application-modal/duplicate-application-modal.component.ts index 5570af4e4c..2f6294a7a3 100644 --- a/apps/back-office/src/app/components/duplicate-application-modal/duplicate-application-modal.component.ts +++ b/apps/back-office/src/app/components/duplicate-application-modal/duplicate-application-modal.component.ts @@ -6,6 +6,7 @@ import { Application, DuplicateApplicationMutationResponse, SnackbarSpinnerComponent, + errorMessageFormatter, } from '@oort-front/shared'; import { TranslateService } from '@ngx-translate/core'; import { CommonModule } from '@angular/common'; @@ -94,35 +95,32 @@ export class DuplicateApplicationModalComponent { }, }) .subscribe({ - next: ({ errors, data }) => { - if (errors) { - snackBarSpinner.instance.message = this.translateService.instant( - 'common.notifications.objectNotDuplicated', - { - type: this.translateService - .instant('common.application.one') - .toLowerCase(), - error: errors ? errors[0].message : '', - } - ); - snackBarSpinner.instance.error = true; - } else { - snackBarSpinner.instance.message = this.translateService.instant( - 'common.notifications.objectDuplicated', - { - type: this.translateService - .instant('common.application.one') - .toLowerCase(), - value: this.currentApp.name, - } - ); - } + next: ({ data }) => { snackBarSpinner.instance.loading = false; + snackBarSpinner.instance.message = this.translateService.instant( + 'common.notifications.objectDuplicated', + { + type: this.translateService + .instant('common.application.one') + .toLowerCase(), + value: this.currentApp.name, + } + ); + this.loading = false; this.dialogRef.close(data?.duplicateApplication as any); }, - error: (err) => { - snackBarSpinner.instance.message = err.message; + error: (errors) => { + this.loading = false; snackBarSpinner.instance.loading = false; + snackBarSpinner.instance.message = this.translateService.instant( + 'common.notifications.objectNotDuplicated', + { + type: this.translateService + .instant('common.application.one') + .toLowerCase(), + error: errorMessageFormatter(errors), + } + ); snackBarSpinner.instance.error = true; }, }); diff --git a/apps/back-office/src/app/dashboard/pages/api-configuration/api-configuration.component.ts b/apps/back-office/src/app/dashboard/pages/api-configuration/api-configuration.component.ts index 992499bbc7..193115d0bf 100644 --- a/apps/back-office/src/app/dashboard/pages/api-configuration/api-configuration.component.ts +++ b/apps/back-office/src/app/dashboard/pages/api-configuration/api-configuration.component.ts @@ -11,6 +11,7 @@ import { UnsubscribeComponent, ApiConfigurationQueryResponse, EditApiConfigurationMutationResponse, + errorMessageFormatter, } from '@oort-front/shared'; import { Apollo } from 'apollo-angular'; import { takeUntil } from 'rxjs/operators'; @@ -117,24 +118,18 @@ export class ApiConfigurationComponent this.resetFormSettings(value); }); this.loading = loading; - } else { - this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.accessNotProvided', - { - type: this.translate - .instant('common.resource.one') - .toLowerCase(), - error: '', - } - ), - { error: true } - ); - this.router.navigate(['/settings/apiconfigurations']); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: () => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.accessNotProvided', { + type: this.translate + .instant('common.resource.one') + .toLowerCase(), + error: '', + }), + { error: true } + ); this.router.navigate(['/settings/apiconfigurations']); }, }); @@ -241,21 +236,23 @@ export class ApiConfigurationComponent permissions: e, }, }) - .subscribe(({ errors, data, loading }) => { - if (errors) { + .subscribe({ + next: ({ data, loading }) => { + if (data) { + this.apiConfiguration = data.editApiConfiguration; + } + this.loading = loading; + }, + error: (errors) => { + this.loading = false; this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectNotUpdated', { type: this.translate.instant('common.apiConfiguration.one'), - error: errors ? errors[0].message : '', + error: errorMessageFormatter(errors), }), { error: true } ); - } else { - if (data) { - this.apiConfiguration = data.editApiConfiguration; - } - } - this.loading = loading; + }, }); } @@ -315,21 +312,22 @@ export class ApiConfigurationComponent mutation: EDIT_API_CONFIGURATION, variables, }) - .subscribe(({ errors, data, loading }) => { - if (errors) { + .subscribe({ + next: ({ data, loading }) => { + this.apiConfiguration = data?.editApiConfiguration; + this.resetFormSettings(this.apiConfiguration?.authType as string); + this.loading = loading || false; + }, + error: (errors) => { + this.loading = false; this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectNotUpdated', { type: this.translate.instant('common.apiConfiguration.one'), - error: errors ? errors[0].message : '', + error: errorMessageFormatter(errors), }), { error: true } ); - } else { - this.apiConfiguration = data?.editApiConfiguration; - this.resetFormSettings(this.apiConfiguration?.authType as string); - this.loading = loading || false; - } - this.loading = loading; + }, }); } diff --git a/apps/back-office/src/app/dashboard/pages/api-configurations/api-configurations.component.ts b/apps/back-office/src/app/dashboard/pages/api-configurations/api-configurations.component.ts index 831fc8bfea..95609bddfd 100644 --- a/apps/back-office/src/app/dashboard/pages/api-configurations/api-configurations.component.ts +++ b/apps/back-office/src/app/dashboard/pages/api-configurations/api-configurations.component.ts @@ -10,6 +10,7 @@ import { DeleteApiConfigurationMutationResponse, getCachedValues, updateQueryUniqueValues, + errorMessageFormatter, } from '@oort-front/shared'; import { ADD_API_CONFIGURATION, @@ -185,36 +186,32 @@ export class ApiConfigurationsComponent takeUntil(this.destroy$) ) .subscribe({ - next: ({ errors, data }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotCreated', { - type: this.translate - .instant('common.apiConfiguration.one') - .toLowerCase(), - error: errors ? errors[0].message : '', - }), - { error: true } - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectCreated', { - type: this.translate - .instant('common.apiConfiguration.one') - .toLowerCase(), - value: data?.addApiConfiguration.name, - }) - ); - if (data) { - this.router.navigate([ - '/settings/apiconfigurations', - data.addApiConfiguration.id, - ]); - } + next: ({ data }) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectCreated', { + type: this.translate + .instant('common.apiConfiguration.one') + .toLowerCase(), + value: data?.addApiConfiguration.name, + }) + ); + if (data) { + this.router.navigate([ + '/settings/apiconfigurations', + data.addApiConfiguration.id, + ]); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotCreated', { + type: this.translate + .instant('common.apiConfiguration.one') + .toLowerCase(), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } @@ -253,7 +250,7 @@ export class ApiConfigurationsComponent ) .subscribe({ next: (res) => { - if (res && !res.errors) { + if (res) { this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectDeleted', { value: this.translate.instant('common.apiConfiguration.one'), @@ -262,18 +259,16 @@ export class ApiConfigurationsComponent this.dataSource = this.dataSource.filter( (x) => x.id !== element.id ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotDeleted', { - value: this.translate.instant('common.apiConfiguration.one'), - error: res.errors ? res.errors[0].message : '', - }), - { error: true } - ); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotDeleted', { + value: this.translate.instant('common.apiConfiguration.one'), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } diff --git a/apps/back-office/src/app/dashboard/pages/applications/applications.component.ts b/apps/back-office/src/app/dashboard/pages/applications/applications.component.ts index 523787ace8..8b5bd24958 100644 --- a/apps/back-office/src/app/dashboard/pages/applications/applications.component.ts +++ b/apps/back-office/src/app/dashboard/pages/applications/applications.component.ts @@ -12,6 +12,7 @@ import { EditApplicationMutationResponse, getCachedValues, updateQueryUniqueValues, + errorMessageFormatter, } from '@oort-front/shared'; import { DELETE_APPLICATION, @@ -130,18 +131,24 @@ export class ApplicationsComponent }, }) .pipe(takeUntil(this.destroy$)) - .subscribe(({ data }) => { - this.newApplications = data.applications.edges.map((x) => x.node); + .subscribe({ + next: ({ data }) => { + this.newApplications = data.applications.edges.map((x) => x.node); + }, }); this.applicationsQuery.valueChanges .pipe(takeUntil(this.destroy$)) - .subscribe( - ( + .subscribe({ + next: ( results: ApolloQueryResult ) => { this.updateValues(results.data, results.loading); - } - ); + }, + error: () => { + this.loading = false; + this.updating = false; + }, + }); } /** @@ -261,31 +268,27 @@ export class ApplicationsComponent takeUntil(this.destroy$) ) .subscribe({ - next: ({ errors, data }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotDeleted', { - value: this.translate.instant('common.application.one'), - error: errors ? errors[0].message : '', - }), - { error: true } - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectDeleted', { - value: this.translate.instant('common.application.one'), - }) - ); - this.applications = this.applications.filter( - (x) => x.id !== data?.deleteApplication.id - ); - this.newApplications = this.newApplications.filter( - (x) => x.id !== data?.deleteApplication.id - ); - } + next: ({ data }) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectDeleted', { + value: this.translate.instant('common.application.one'), + }) + ); + this.applications = this.applications.filter( + (x) => x.id !== data?.deleteApplication.id + ); + this.newApplications = this.newApplications.filter( + (x) => x.id !== data?.deleteApplication.id + ); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotDeleted', { + value: this.translate.instant('common.application.one'), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } @@ -300,32 +303,28 @@ export class ApplicationsComponent mutation: ADD_APPLICATION, }) .subscribe({ - next: ({ errors, data }) => { - if (errors?.length) { + next: ({ data }) => { + if (data) { this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotCreated', { - type: this.translate - .instant('common.application.one') - .toLowerCase(), - error: errors ? errors[0].message : '', - }), - { error: true } + this.translate.instant('common.notifications.objectCreated', { + type: this.translate.instant('common.application.one'), + value: data.addApplication.name, + }) ); - } else { - if (data) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectCreated', { - type: this.translate.instant('common.application.one'), - value: data.addApplication.name, - }) - ); - const id = data.addApplication.id; - this.router.navigate(['/applications', id]); - } + const id = data.addApplication.id; + this.router.navigate(['/applications', id]); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotCreated', { + type: this.translate + .instant('common.application.one') + .toLowerCase(), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } @@ -346,34 +345,30 @@ export class ApplicationsComponent }, }) .subscribe({ - next: ({ errors, data }) => { - if (errors) { + next: ({ data }) => { + if (data) { this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotUpdated', { + this.translate.instant('common.notifications.objectUpdated', { type: this.translate.instant('common.access'), - error: errors ? errors[0].message : '', - }), - { error: true } + value: element.name, + }) ); - } else { - if (data) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectUpdated', { - type: this.translate.instant('common.access'), - value: element.name, - }) - ); - const index = this.applications.findIndex( - (x) => x.id === element.id - ); - this.applications[index] = data.editApplication; - // eslint-disable-next-line no-self-assign - this.applications = this.applications; - } + const index = this.applications.findIndex( + (x) => x.id === element.id + ); + this.applications[index] = data.editApplication; + // eslint-disable-next-line no-self-assign + this.applications = this.applications; } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotUpdated', { + type: this.translate.instant('common.access'), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } diff --git a/apps/back-office/src/app/dashboard/pages/applications/components/chose-role/chose-role.component.ts b/apps/back-office/src/app/dashboard/pages/applications/components/chose-role/chose-role.component.ts index 2ab318a9f0..718806471e 100644 --- a/apps/back-office/src/app/dashboard/pages/applications/components/chose-role/chose-role.component.ts +++ b/apps/back-office/src/app/dashboard/pages/applications/components/chose-role/chose-role.component.ts @@ -59,10 +59,13 @@ export class ChoseRoleComponent extends UnsubscribeComponent implements OnInit { }, }); - this.rolesQuery.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe(({ loading }) => { + this.rolesQuery.valueChanges.pipe(takeUntil(this.destroy$)).subscribe({ + next: ({ loading }) => { this.loading = loading; - }); + }, + error: () => { + this.loading = false; + }, + }); } } diff --git a/apps/back-office/src/app/dashboard/pages/dashboard/components/context-datasource/context-datasource.component.ts b/apps/back-office/src/app/dashboard/pages/dashboard/components/context-datasource/context-datasource.component.ts index 5c7c8cd506..34ea1e0d8f 100644 --- a/apps/back-office/src/app/dashboard/pages/dashboard/components/context-datasource/context-datasource.component.ts +++ b/apps/back-office/src/app/dashboard/pages/dashboard/components/context-datasource/context-datasource.component.ts @@ -174,9 +174,11 @@ export class ContextDatasourceComponent id, }, }) - .subscribe(({ data }) => { - this.refData = data.referenceData; - this.updateDisplayFieldOptions(); + .subscribe({ + next: ({ data }) => { + this.refData = data.referenceData; + this.updateDisplayFieldOptions(); + }, }); } @@ -193,9 +195,11 @@ export class ContextDatasourceComponent id, }, }) - .subscribe(({ data }) => { - this.resource = data.resource; - this.updateDisplayFieldOptions(); + .subscribe({ + next: ({ data }) => { + this.resource = data.resource; + this.updateDisplayFieldOptions(); + }, }); } diff --git a/apps/back-office/src/app/dashboard/pages/dashboard/dashboard.component.ts b/apps/back-office/src/app/dashboard/pages/dashboard/dashboard.component.ts index c2621be44a..26d383af13 100644 --- a/apps/back-office/src/app/dashboard/pages/dashboard/dashboard.component.ts +++ b/apps/back-office/src/app/dashboard/pages/dashboard/dashboard.component.ts @@ -486,7 +486,15 @@ export class DashboardComponent }, }) .subscribe({ - next: ({ errors }) => { + next: () => { + this.loading = false; + this.applicationService.handleEditionMutationResponse( + [], + this.translate.instant('common.dashboard.one') + ); + }, + error: (errors) => { + this.loading = false; this.applicationService.handleEditionMutationResponse( errors, this.translate.instant('common.dashboard.one') @@ -582,8 +590,10 @@ export class DashboardComponent }), takeUntil(this.destroy$) ) - .subscribe((button) => { - this.buttonActions.push(button); + .subscribe({ + next: (button) => { + this.buttonActions.push(button); + }, }); } @@ -699,11 +709,13 @@ export class DashboardComponent if (this.dashboard?.id) { this.dashboardService .saveDashboardButtons(this.dashboard.id, this.buttonActions) - .subscribe(() => { - this.dashboard = { - ...this.dashboard, - buttons: this.buttonActions, - }; + .subscribe({ + next: () => { + this.dashboard = { + ...this.dashboard, + buttons: this.buttonActions, + }; + }, }); } } diff --git a/apps/back-office/src/app/dashboard/pages/form-answer/form-answer.component.ts b/apps/back-office/src/app/dashboard/pages/form-answer/form-answer.component.ts index 05044e402f..4c54baf715 100644 --- a/apps/back-office/src/app/dashboard/pages/form-answer/form-answer.component.ts +++ b/apps/back-office/src/app/dashboard/pages/form-answer/form-answer.component.ts @@ -61,18 +61,23 @@ export class FormAnswerComponent }, }) .valueChanges.pipe(takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { - this.loading = loading; - this.form = data.form; - this.breadcrumbService.setBreadcrumb( - '@form', - this.form.name as string - ); - this.breadcrumbService.setBreadcrumb( - '@resource', - this.form.resource?.name as string - ); - // this.breadcrumbService.setResourceName(); + .subscribe({ + next: ({ data, loading }) => { + this.loading = loading; + this.form = data.form; + this.breadcrumbService.setBreadcrumb( + '@form', + this.form.name as string + ); + this.breadcrumbService.setBreadcrumb( + '@resource', + this.form.resource?.name as string + ); + // this.breadcrumbService.setResourceName(); + }, + error: () => { + this.loading = false; + }, }); } } diff --git a/apps/back-office/src/app/dashboard/pages/form-builder/form-builder.component.ts b/apps/back-office/src/app/dashboard/pages/form-builder/form-builder.component.ts index eb624c50b0..8139b6fc15 100644 --- a/apps/back-office/src/app/dashboard/pages/form-builder/form-builder.component.ts +++ b/apps/back-office/src/app/dashboard/pages/form-builder/form-builder.component.ts @@ -18,6 +18,7 @@ import { FormQueryResponse, EditFormMutationResponse, SnackbarSpinnerComponent, + errorMessageFormatter, UnsubscribeComponent, } from '@oort-front/shared'; import { SpinnerComponent } from '@oort-front/ui'; @@ -186,25 +187,16 @@ export class FormBuilderComponent this.hasChanges = true; this.authService.canLogout.next(!this.hasChanges); } - } else { - this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.accessNotProvided', - { - type: this.translate - .instant('common.form.one') - .toLowerCase(), - error: '', - } - ), - { error: true } - ); - // redirect to default screen if error - this.router.navigate(['/forms']); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: () => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.accessNotProvided', { + type: this.translate.instant('common.form.one').toLowerCase(), + error: '', + }), + { error: true } + ); // redirect to default screen if error this.router.navigate(['/forms']); }, @@ -288,34 +280,35 @@ export class FormBuilderComponent }, }) .subscribe({ - next: ({ errors, data }) => { + next: ({ data }) => { // Dismiss the loading snackbar loadingSnackbarRef.instance.dismiss(); - // Open new snackbar with the request error or success message - const message = errors - ? errors[0].message - : this.translate.instant('common.notifications.objectUpdated', { - type: this.translate.instant('common.form.one').toLowerCase(), - value: '', - }); - const snackbarConfig = { - ...REQUEST_SNACKBAR_CONF, - error: errors ? true : false, - }; - this.snackBar.openSnackBar(message, snackbarConfig); + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectUpdated', { + type: this.translate.instant('common.form.one').toLowerCase(), + value: '', + }), + { + ...REQUEST_SNACKBAR_CONF, + error: false, + } + ); - if (!errors) { - this.form = { ...data?.editForm, structure }; - this.structure = structure; - localStorage.removeItem(`form:${this.id}`); - this.hasChanges = false; - this.authService.canLogout.next(true); - } + this.form = { ...data?.editForm, structure }; + this.structure = structure; + localStorage.removeItem(`form:${this.id}`); + this.hasChanges = false; + this.authService.canLogout.next(true); }, - error: (err) => { + error: (errors) => { // Dismiss the loading snackbar loadingSnackbarRef.instance.dismiss(); - this.snackBar.openSnackBar(err.message, { error: true }); + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + ...REQUEST_SNACKBAR_CONF, + error: true, + }); + // Detach the current set overlay + overlayRef.detach(); }, complete: () => { // Detach the current set overlay @@ -343,15 +336,15 @@ export class FormBuilderComponent }, }) .subscribe({ - next: ({ errors, data }) => { + next: ({ data }) => { // Dismiss the loading snackbar loadingSnackbarRef.instance.dismiss(); - this.handleFormMutationResponse(data, errors); + this.handleFormMutationResponse(data, []); }, - error: (err) => { + error: (errors) => { // Dismiss the loading snackbar loadingSnackbarRef.instance.dismiss(); - this.snackBar.openSnackBar(err.message, { error: true }); + this.handleFormMutationResponse(null, errors); }, complete: () => { // Detach the current set overlay @@ -372,13 +365,13 @@ export class FormBuilderComponent errors: readonly GraphQLError[] | undefined, formName?: string ) { - if (errors) { + if (errors?.length) { this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectNotUpdated', { type: this.translate.instant( formName ? 'common.form.one' : 'common.status' ), - error: errors ? errors[0].message : '', + error: errorMessageFormatter(errors), }), { error: true } ); @@ -418,8 +411,10 @@ export class FormBuilderComponent }, }) .valueChanges.pipe(takeUntil(this.destroy$)) - .subscribe(({ data }) => { - this.structure = data.form.structure; + .subscribe({ + next: ({ data }) => { + this.structure = data.form.structure; + }, }); } @@ -464,14 +459,17 @@ export class FormBuilderComponent }, }) .subscribe({ - next: ({ errors, data }) => { + next: ({ data }) => { // Dismiss the loading snackbar loadingSnackbarRef.instance.dismiss(); - this.handleFormMutationResponse(data, errors, formName); + this.handleFormMutationResponse(data, [], formName); }, - error: () => { + error: (errors) => { // Dismiss the loading snackbar loadingSnackbarRef.instance.dismiss(); + this.handleFormMutationResponse(null, errors, formName); + // Detach the current set overlay + overlayRef.detach(); }, complete: () => { // Detach the current set overlay @@ -499,31 +497,37 @@ export class FormBuilderComponent }, }) .subscribe({ - next: ({ errors, data }) => { + next: ({ data }) => { // Dismiss the loading snackbar loadingSnackbarRef.instance.dismiss(); - // Open new snackbar with the request error or success message - const message = errors - ? this.translate.instant('common.notifications.objectNotUpdated', { - type: this.translate.instant('common.access'), - error: errors ? errors[0].message : '', - }) - : this.translate.instant('common.notifications.objectUpdated', { - type: this.translate.instant('common.access'), - value: '', - }); - const snackbarConfig = { - ...REQUEST_SNACKBAR_CONF, - error: errors ? true : false, - }; - this.snackBar.openSnackBar(message, snackbarConfig); - if (!errors) { - this.form = { ...data?.editForm, structure: this.structure }; - } + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectUpdated', { + type: this.translate.instant('common.access'), + value: '', + }), + { + ...REQUEST_SNACKBAR_CONF, + error: false, + } + ); + + this.form = { ...data?.editForm, structure: this.structure }; }, - error: (err) => { + error: (errors) => { + // Dismiss the loading snackbar loadingSnackbarRef.instance.dismiss(); - this.snackBar.openSnackBar(err.message, { error: true }); + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotUpdated', { + type: this.translate.instant('common.access'), + error: errorMessageFormatter(errors), + }), + { + ...REQUEST_SNACKBAR_CONF, + error: false, + } + ); + // Detach the current set overlay + overlayRef.detach(); }, complete: () => { // Detach the current set overlay diff --git a/apps/back-office/src/app/dashboard/pages/form-records/form-records.component.ts b/apps/back-office/src/app/dashboard/pages/form-records/form-records.component.ts index 53a9948a0c..98c24f07dd 100644 --- a/apps/back-office/src/app/dashboard/pages/form-records/form-records.component.ts +++ b/apps/back-office/src/app/dashboard/pages/form-records/form-records.component.ts @@ -19,6 +19,7 @@ import { DownloadService, getCachedValues, updateQueryUniqueValues, + errorMessageFormatter, } from '@oort-front/shared'; import { Dialog } from '@angular/cdk/dialog'; import { TranslateService } from '@ngx-translate/core'; @@ -156,22 +157,23 @@ export class FormRecordsComponent }, }); - this.recordsQuery.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe(({ errors, data, loading }) => { + this.recordsQuery.valueChanges.pipe(takeUntil(this.destroy$)).subscribe({ + next: ({ data, loading }) => { this.updateValues(data, loading, true); - - if (errors) { - // TO-DO: Check why it's not working as intended. - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.accessNotProvided', { - type: this.translate.instant('common.record.one').toLowerCase(), - error: errors ? errors[0].message : '', - }), - { error: true } - ); - } - }); + }, + error: (errors) => { + this.loading = false; + this.updating = false; + // TO-DO: Check why it's not working as intended. + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.accessNotProvided', { + type: this.translate.instant('common.record.one').toLowerCase(), + error: errorMessageFormatter(errors), + }), + { error: true } + ); + }, + }); } /** @@ -322,6 +324,10 @@ export class FormRecordsComponent * @param id Id of record to delete. */ private deleteRecord(id: string): void { + const recordMutationMessage = { + success: 'common.notifications.objectDeleted', + error: 'common.notifications.objectNotDeleted', + }; this.apollo .mutate({ mutation: DELETE_RECORD, @@ -331,18 +337,11 @@ export class FormRecordsComponent }, }) .subscribe({ - next: ({ errors }) => { - this.handleRecordMutationResponse( - errors, - { - success: 'common.notifications.objectDeleted', - error: 'common.notifications.objectNotDeleted', - }, - id - ); + next: () => { + this.handleRecordMutationResponse([], recordMutationMessage, id); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.handleRecordMutationResponse(errors, recordMutationMessage, id); }, }); } @@ -383,21 +382,17 @@ export class FormRecordsComponent takeUntil(this.destroy$) ) .subscribe({ - next: ({ errors }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.dataNotRecovered'), - { error: true } - ); - } else { - this.layoutService.setRightSidenav(null); - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.dataRecovered') - ); - } + next: () => { + this.layoutService.setRightSidenav(null); + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.dataRecovered') + ); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: () => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.dataNotRecovered'), + { error: true } + ); }, }); } @@ -498,6 +493,10 @@ export class FormRecordsComponent */ public onRestoreRecord(id: string, e: any): void { e.stopPropagation(); + const restoreRecordMessage = { + success: 'common.notifications.objectRestored', + error: 'common.notifications.objectNotRestored', + }; this.apollo .mutate({ mutation: RESTORE_RECORD, @@ -506,18 +505,11 @@ export class FormRecordsComponent }, }) .subscribe({ - next: ({ errors }) => { - this.handleRecordMutationResponse( - errors, - { - success: 'common.notifications.objectRestored', - error: 'common.notifications.objectNotRestored', - }, - id - ); + next: () => { + this.handleRecordMutationResponse([], restoreRecordMessage, id); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.handleRecordMutationResponse(errors, restoreRecordMessage, id); }, }); } @@ -540,7 +532,7 @@ export class FormRecordsComponent this.snackBar.openSnackBar( this.translate.instant(messageKeys.error, { value: this.translate.instant('common.record.one'), - error: errors ? errors[0].message : '', + error: errorMessageFormatter(errors), }), { error: true } ); diff --git a/apps/back-office/src/app/dashboard/pages/forms/forms.component.ts b/apps/back-office/src/app/dashboard/pages/forms/forms.component.ts index 4733fe51d9..8ad0d1343c 100644 --- a/apps/back-office/src/app/dashboard/pages/forms/forms.component.ts +++ b/apps/back-office/src/app/dashboard/pages/forms/forms.component.ts @@ -12,6 +12,7 @@ import { AddFormMutationResponse, getCachedValues, updateQueryUniqueValues, + errorMessageFormatter, } from '@oort-front/shared'; import { GET_SHORT_FORMS } from './graphql/queries'; import { DELETE_FORM, ADD_FORM } from './graphql/mutations'; @@ -115,11 +116,15 @@ export class FormsComponent extends UnsubscribeComponent implements OnInit { }, }); - this.formsQuery.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe((results) => { + this.formsQuery.valueChanges.pipe(takeUntil(this.destroy$)).subscribe({ + next: (results) => { this.updateValues(results.data, results.loading); - }); + }, + error: () => { + this.loading = false; + this.updating = false; + }, + }); } /** @@ -233,28 +238,24 @@ export class FormsComponent extends UnsubscribeComponent implements OnInit { takeUntil(this.destroy$) ) .subscribe({ - next: ({ errors }) => { - if (!errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectDeleted', { - value: this.translate.instant('common.form.one'), - }) - ); - this.forms = this.forms.filter( - (x) => x.id !== form.id && form.id !== x.resource?.coreForm?.id - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotDeleted', { - value: this.translate.instant('common.form.one'), - error: errors ? errors[0].message : '', - }), - { error: true } - ); - } + next: () => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectDeleted', { + value: this.translate.instant('common.form.one'), + }) + ); + this.forms = this.forms.filter( + (x) => x.id !== form.id && form.id !== x.resource?.coreForm?.id + ); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotDeleted', { + value: this.translate.instant('common.form.one'), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } @@ -286,24 +287,20 @@ export class FormsComponent extends UnsubscribeComponent implements OnInit { takeUntil(this.destroy$) ) .subscribe({ - next: ({ errors, data }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotCreated', { - type: this.translate.instant('common.form.one').toLowerCase(), - error: errors ? errors[0].message : '', - }), - { error: true } - ); - } else { - if (data) { - const { id } = data.addForm; - this.router.navigate(['/forms/' + id + '/builder']); - } + next: ({ data }) => { + if (data) { + const { id } = data.addForm; + this.router.navigate(['/forms/' + id + '/builder']); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotCreated', { + type: this.translate.instant('common.form.one').toLowerCase(), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } diff --git a/apps/back-office/src/app/dashboard/pages/pull-jobs/components/edit-pull-job-modal/edit-pull-job-modal.component.ts b/apps/back-office/src/app/dashboard/pages/pull-jobs/components/edit-pull-job-modal/edit-pull-job-modal.component.ts index ec72f4bdea..826f6a675e 100644 --- a/apps/back-office/src/app/dashboard/pages/pull-jobs/components/edit-pull-job-modal/edit-pull-job-modal.component.ts +++ b/apps/back-office/src/app/dashboard/pages/pull-jobs/components/edit-pull-job-modal/edit-pull-job-modal.component.ts @@ -237,12 +237,12 @@ export class EditPullJobModalComponent }); this.apiConfigurationsQuery.valueChanges .pipe(takeUntil(this.destroy$)) - .subscribe( - ({ data }) => + .subscribe({ + next: ({ data }) => (this.apiConfigurations = data.apiConfigurations.edges.map( (x) => x.node - )) - ); + )), + }); // Fetch form fields if any for mapping if (this.data.pullJob?.convertTo?.id) { @@ -270,8 +270,13 @@ export class EditPullJobModalComponent // this.applications$ = this.applications.asObservable(); this.applicationsQuery.valueChanges .pipe(takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { - this.updateValues(data, loading); + .subscribe({ + next: ({ data, loading }) => { + this.updateValues(data, loading); + }, + error: () => { + this.applicationsLoading = false; + }, }); // Set boolean to allow additional fields if it's not isHardcoded @@ -337,13 +342,15 @@ export class EditPullJobModalComponent }, }) .valueChanges.pipe(takeUntil(this.destroy$)) - .subscribe((resForm) => { - if (resForm.data.form) { - this.fields = resForm.data.form.fields || []; - this.fields = this.fields.concat( - DEFAULT_FIELDS.map((x) => ({ name: x })) - ); - } + .subscribe({ + next: (resForm) => { + if (resForm.data.form) { + this.fields = resForm.data.form.fields || []; + this.fields = this.fields.concat( + DEFAULT_FIELDS.map((x) => ({ name: x })) + ); + } + }, }); } diff --git a/apps/back-office/src/app/dashboard/pages/pull-jobs/pull-jobs.component.ts b/apps/back-office/src/app/dashboard/pages/pull-jobs/pull-jobs.component.ts index 5038026eff..7530a8b380 100644 --- a/apps/back-office/src/app/dashboard/pages/pull-jobs/pull-jobs.component.ts +++ b/apps/back-office/src/app/dashboard/pages/pull-jobs/pull-jobs.component.ts @@ -11,6 +11,7 @@ import { PullJobsNodesQueryResponse, getCachedValues, updateQueryUniqueValues, + errorMessageFormatter, } from '@oort-front/shared'; import { Apollo, QueryRef } from 'apollo-angular'; import { GET_PULL_JOBS } from './graphql/queries'; @@ -92,11 +93,14 @@ export class PullJobsComponent extends UnsubscribeComponent implements OnInit { }, }); - this.pullJobsQuery.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe((results) => { + this.pullJobsQuery.valueChanges.pipe(takeUntil(this.destroy$)).subscribe({ + next: (results) => { this.updateValues(results.data, results.loading); - }); + }, + error: () => { + this.loading = false; + }, + }); } /** @@ -180,53 +184,45 @@ export class PullJobsComponent extends UnsubscribeComponent implements OnInit { variables, }) .pipe( - map(({ errors, data }) => { + map(({ data }) => { return { - errors, data, pulljobName: value.name, }; }) ); }), - takeUntil(this.destroy$) ) .subscribe({ - next: ({ errors, data, pulljobName }) => { - if (errors) { + next: ({ data, pulljobName }) => { + if (data?.addPullJob) { this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotCreated', { - type: this.translate - .instant('common.pullJob.one') - .toLowerCase(), - error: errors ? errors[0].message : '', - }), - { error: true } + this.translate.instant('common.notifications.objectCreated', { + type: this.translate.instant('common.pullJob.one'), + value: pulljobName, + }) ); - } else { - if (data?.addPullJob) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectCreated', { - type: this.translate.instant('common.pullJob.one'), - value: pulljobName, - }) + if (this.cachedPullJobs.length === this.pageInfo.length) { + this.cachedPullJobs = this.cachedPullJobs.concat([ + data?.addPullJob, + ]); + this.pullJobs = this.cachedPullJobs.slice( + ITEMS_PER_PAGE * this.pageInfo.pageIndex, + ITEMS_PER_PAGE * (this.pageInfo.pageIndex + 1) ); - if (this.cachedPullJobs.length === this.pageInfo.length) { - this.cachedPullJobs = this.cachedPullJobs.concat([ - data?.addPullJob, - ]); - this.pullJobs = this.cachedPullJobs.slice( - ITEMS_PER_PAGE * this.pageInfo.pageIndex, - ITEMS_PER_PAGE * (this.pageInfo.pageIndex + 1) - ); - } - this.pageInfo.length += 1; } + this.pageInfo.length += 1; } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotCreated', { + type: this.translate.instant('common.pullJob.one').toLowerCase(), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } @@ -263,38 +259,31 @@ export class PullJobsComponent extends UnsubscribeComponent implements OnInit { takeUntil(this.destroy$) ) .subscribe({ - next: ({ errors, data }) => { - if (errors) { + next: ({ data }) => { + if (data?.deletePullJob) { this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.objectNotDeleted', - { - value: this.translate.instant('common.pullJob.one'), - error: errors ? errors[0].message : '', - } - ), - { error: true } + this.translate.instant('common.notifications.objectDeleted', { + value: this.translate.instant('common.pullJob.one'), + }) + ); + this.cachedPullJobs = this.cachedPullJobs.filter( + (x) => x.id !== data?.deletePullJob.id + ); + this.pageInfo.length -= 1; + this.pullJobs = this.cachedPullJobs.slice( + ITEMS_PER_PAGE * this.pageInfo.pageIndex, + ITEMS_PER_PAGE * (this.pageInfo.pageIndex + 1) ); - } else { - if (data?.deletePullJob) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectDeleted', { - value: this.translate.instant('common.pullJob.one'), - }) - ); - this.cachedPullJobs = this.cachedPullJobs.filter( - (x) => x.id !== data?.deletePullJob.id - ); - this.pageInfo.length -= 1; - this.pullJobs = this.cachedPullJobs.slice( - ITEMS_PER_PAGE * this.pageInfo.pageIndex, - ITEMS_PER_PAGE * (this.pageInfo.pageIndex + 1) - ); - } } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotDeleted', { + value: this.translate.instant('common.pullJob.one'), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } @@ -345,9 +334,8 @@ export class PullJobsComponent extends UnsubscribeComponent implements OnInit { variables, }) .pipe( - map(({ errors, data }) => { + map(({ data }) => { return { - errors, data, pulljobName: value.name, }; @@ -357,42 +345,38 @@ export class PullJobsComponent extends UnsubscribeComponent implements OnInit { takeUntil(this.destroy$) ) .subscribe({ - next: ({ errors, data, pulljobName }) => { - if (errors) { + next: ({ data, pulljobName }) => { + if (data?.editPullJob) { this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotUpdated', { - value: this.translate.instant('common.pullJob.one'), - error: errors ? errors[0].message : '', - }), - { error: true } + this.translate.instant('common.notifications.objectUpdated', { + type: this.translate + .instant('common.pullJob.one') + .toLowerCase(), + value: pulljobName, + }) ); - } else { - if (data?.editPullJob) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectUpdated', { - type: this.translate - .instant('common.pullJob.one') - .toLowerCase(), - value: pulljobName, - }) - ); - this.cachedPullJobs = this.cachedPullJobs.map( - (pullJob: PullJob) => { - if (pullJob.id === data?.editPullJob.id) { - pullJob = data?.editPullJob || pullJob; - } - return pullJob; + this.cachedPullJobs = this.cachedPullJobs.map( + (pullJob: PullJob) => { + if (pullJob.id === data?.editPullJob.id) { + pullJob = data?.editPullJob || pullJob; } - ); - this.pullJobs = this.cachedPullJobs.slice( - ITEMS_PER_PAGE * this.pageInfo.pageIndex, - ITEMS_PER_PAGE * (this.pageInfo.pageIndex + 1) - ); - } + return pullJob; + } + ); + this.pullJobs = this.cachedPullJobs.slice( + ITEMS_PER_PAGE * this.pageInfo.pageIndex, + ITEMS_PER_PAGE * (this.pageInfo.pageIndex + 1) + ); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotUpdated', { + value: this.translate.instant('common.pullJob.one'), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } diff --git a/apps/back-office/src/app/dashboard/pages/reference-data/reference-data.component.ts b/apps/back-office/src/app/dashboard/pages/reference-data/reference-data.component.ts index 6adebf01ae..f53671dd69 100644 --- a/apps/back-office/src/app/dashboard/pages/reference-data/reference-data.component.ts +++ b/apps/back-office/src/app/dashboard/pages/reference-data/reference-data.component.ts @@ -27,6 +27,7 @@ import { ApiConfigurationQueryResponse, EditReferenceDataMutationResponse, paginationStrategy, + errorMessageFormatter, } from '@oort-front/shared'; import { Apollo, QueryRef } from 'apollo-angular'; import { EDIT_REFERENCE_DATA } from './graphql/mutations'; @@ -410,24 +411,21 @@ export class ReferenceDataComponent }); } this.loading = loading; - } else { - this.snackBar.openSnackBar( - this.translateService.instant( - 'common.notifications.accessNotProvided', - { - type: this.translateService - .instant('notification.term.resource') - .toLowerCase(), - error: '', - } - ), - { error: true } - ); - this.router.navigate(['/referencedata']); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: () => { + this.snackBar.openSnackBar( + this.translateService.instant( + 'common.notifications.accessNotProvided', + { + type: this.translateService + .instant('notification.term.resource') + .toLowerCase(), + error: '', + } + ), + { error: true } + ); this.router.navigate(['/referencedata']); }, }); @@ -476,10 +474,12 @@ export class ReferenceDataComponent id: this.referenceForm.value.apiConfiguration, }, }) - .subscribe(({ data }) => { - if (data.apiConfiguration) { - this.selectedApiConfiguration = data.apiConfiguration; - } + .subscribe({ + next: ({ data }) => { + if (data.apiConfiguration) { + this.selectedApiConfiguration = data.apiConfiguration; + } + }, }); } @@ -516,11 +516,11 @@ export class ReferenceDataComponent }, }) .subscribe({ - next: ({ errors, data, loading }) => { - this.handleEditReferenceDataResponse(data, errors, loading); + next: ({ data, loading }) => { + this.handleEditReferenceDataResponse(data, [], loading); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.handleEditReferenceDataResponse(null, errors, false); }, }); } @@ -543,7 +543,7 @@ export class ReferenceDataComponent this.snackBar.openSnackBar( this.translateService.instant('common.notifications.objectNotUpdated', { type: this.translateService.instant('common.referenceData.one'), - error: errors ? errors[0].message : '', + error: errorMessageFormatter(errors), }), { error: true } ); @@ -696,11 +696,11 @@ export class ReferenceDataComponent variables, }) .subscribe({ - next: ({ errors, data, loading }) => { - this.handleEditReferenceDataResponse(data, errors, loading, true); + next: ({ data, loading }) => { + this.handleEditReferenceDataResponse(data, [], loading, true); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.handleEditReferenceDataResponse(null, errors, false, true); }, }); } diff --git a/apps/back-office/src/app/dashboard/pages/reference-datas/reference-datas.component.ts b/apps/back-office/src/app/dashboard/pages/reference-datas/reference-datas.component.ts index 89d61be9be..ee2cf07712 100644 --- a/apps/back-office/src/app/dashboard/pages/reference-datas/reference-datas.component.ts +++ b/apps/back-office/src/app/dashboard/pages/reference-datas/reference-datas.component.ts @@ -9,6 +9,7 @@ import { ReferenceDatasQueryResponse, getCachedValues, updateQueryUniqueValues, + errorMessageFormatter, } from '@oort-front/shared'; import { GET_REFERENCE_DATAS } from './graphql/queries'; import { ADD_REFERENCE_DATA, DELETE_REFERENCE_DATA } from './graphql/mutations'; @@ -112,8 +113,14 @@ export class ReferenceDatasComponent this.referenceDatasQuery.valueChanges .pipe(takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { - this.updateValues(data, loading); + .subscribe({ + next: ({ data, loading }) => { + this.updateValues(data, loading); + }, + error: () => { + this.loading = false; + this.updating = false; + }, }); // Initializing sort to an empty one @@ -174,28 +181,21 @@ export class ReferenceDatasComponent takeUntil(this.destroy$) ) .subscribe({ - next: ({ errors, data }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotCreated', { - type: this.translate - .instant('common.referenceData.one') - .toLowerCase(), - error: errors ? errors[0].message : '', - }), - { error: true } - ); - } else { - if (data) { - this.router.navigate([ - '/referencedata', - data.addReferenceData.id, - ]); - } + next: ({ data }) => { + if (data) { + this.router.navigate(['/referencedata', data.addReferenceData.id]); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotCreated', { + type: this.translate + .instant('common.referenceData.one') + .toLowerCase(), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } @@ -234,7 +234,7 @@ export class ReferenceDatasComponent ) .subscribe({ next: (res) => { - if (res && !res.errors) { + if (res) { this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectDeleted', { value: this.translate.instant('common.referenceData.one'), @@ -243,23 +243,16 @@ export class ReferenceDatasComponent this.dataSource = this.dataSource.filter( (x) => x.id !== element.id ); - } else { - if (res.errors) { - this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.objectNotDeleted', - { - value: this.translate.instant('common.referenceData.one'), - error: res.errors ? res.errors[0] : '', - } - ), - { error: true } - ); - } } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotDeleted', { + value: this.translate.instant('common.referenceData.one'), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } diff --git a/apps/back-office/src/app/dashboard/pages/resource/aggregations-tab/aggregations-tab.component.ts b/apps/back-office/src/app/dashboard/pages/resource/aggregations-tab/aggregations-tab.component.ts index 51e09ca1e8..dd3a784913 100644 --- a/apps/back-office/src/app/dashboard/pages/resource/aggregations-tab/aggregations-tab.component.ts +++ b/apps/back-office/src/app/dashboard/pages/resource/aggregations-tab/aggregations-tab.component.ts @@ -1,21 +1,25 @@ +import { Dialog } from '@angular/cdk/dialog'; import { Component, OnInit } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; -import { Dialog } from '@angular/cdk/dialog'; import { Aggregation, AggregationService, ConfirmService, Resource, - UnsubscribeComponent, ResourceQueryResponse, + UnsubscribeComponent, getCachedValues, updateQueryUniqueValues, } from '@oort-front/shared'; +import { + SnackbarService, + UIPageChangeEvent, + handleTablePageEvent, +} from '@oort-front/ui'; import { Apollo, QueryRef } from 'apollo-angular'; import get from 'lodash/get'; -import { GET_RESOURCE_AGGREGATIONS } from './graphql/queries'; import { filter, switchMap, takeUntil } from 'rxjs'; -import { UIPageChangeEvent, handleTablePageEvent } from '@oort-front/ui'; +import { GET_RESOURCE_AGGREGATIONS } from './graphql/queries'; import { isNil } from 'lodash'; /** @@ -79,13 +83,15 @@ export class AggregationsTabComponent * @param aggregationService Grid aggregation service * @param confirmService Shared confirm service * @param translate Angular translate service + * @param snackbarService Snackbar service */ constructor( private apollo: Apollo, private dialog: Dialog, private aggregationService: AggregationService, private confirmService: ConfirmService, - private translate: TranslateService + private translate: TranslateService, + private snackbarService: SnackbarService ) { super(); } @@ -105,8 +111,13 @@ export class AggregationsTabComponent this.aggregationsQuery.valueChanges .pipe(takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { - this.updateValues(data, loading); + .subscribe({ + next: ({ data, loading }) => { + this.updateValues(data, loading); + }, + error: () => { + this.loading = false; + }, }); } @@ -198,11 +209,13 @@ export class AggregationsTabComponent }), takeUntil(this.destroy$) ) - .subscribe(({ data }: any) => { - if (data.addAggregation) { - this.aggregations = [...this.aggregations, data?.addAggregation]; - this.pageInfo.length += 1; - } + .subscribe({ + next: ({ data }: any) => { + if (data.addAggregation) { + this.aggregations = [...this.aggregations, data?.addAggregation]; + this.pageInfo.length += 1; + } + }, }); } @@ -232,16 +245,18 @@ export class AggregationsTabComponent }), takeUntil(this.destroy$) ) - .subscribe(({ data }: any) => { - if (data.editAggregation) { - this.aggregations = this.aggregations.map((x: any) => { - if (x.id === aggregation.id) { - return data.editAggregation; - } else { - return x; - } - }); - } + .subscribe({ + next: ({ data }: any) => { + if (data.editAggregation) { + this.aggregations = this.aggregations.map((x: any) => { + if (x.id === aggregation.id) { + return data.editAggregation; + } else { + return x; + } + }); + } + }, }); } @@ -273,13 +288,15 @@ export class AggregationsTabComponent }), takeUntil(this.destroy$) ) - .subscribe(({ data }: any) => { - if (data.deleteAggregation) { - this.aggregations = this.aggregations.filter( - (x: any) => x.id !== aggregation.id - ); - this.pageInfo.length -= 1; - } + .subscribe({ + next: ({ data }: any) => { + if (data.deleteAggregation) { + this.aggregations = this.aggregations.filter( + (x: any) => x.id !== aggregation.id + ); + this.pageInfo.length -= 1; + } + }, }); } diff --git a/apps/back-office/src/app/dashboard/pages/resource/calculated-fields-tab/calculated-fields-tab.component.ts b/apps/back-office/src/app/dashboard/pages/resource/calculated-fields-tab/calculated-fields-tab.component.ts index 4e8c5a3758..967ad9b8b2 100644 --- a/apps/back-office/src/app/dashboard/pages/resource/calculated-fields-tab/calculated-fields-tab.component.ts +++ b/apps/back-office/src/app/dashboard/pages/resource/calculated-fields-tab/calculated-fields-tab.component.ts @@ -4,6 +4,7 @@ import { EditResourceMutationResponse, Resource, UnsubscribeComponent, + errorMessageFormatter, } from '@oort-front/shared'; import { Apollo } from 'apollo-angular'; import get from 'lodash/get'; @@ -161,14 +162,11 @@ export class CalculatedFieldsTabComponent ) ); } - if (res.errors) { - this.snackBar.openSnackBar(res.errors[0].message, { - error: true, - }); - } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); }, }); } @@ -220,14 +218,11 @@ export class CalculatedFieldsTabComponent if (res.data?.editResource) { this.fields = this.fields.filter((f: any) => f.name !== field.name); } - if (res.errors) { - this.snackBar.openSnackBar(res.errors[0].message, { - error: true, - }); - } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); }, }); } diff --git a/apps/back-office/src/app/dashboard/pages/resource/forms-tab/forms-tab.component.ts b/apps/back-office/src/app/dashboard/pages/resource/forms-tab/forms-tab.component.ts index 80279a0817..94b99381c2 100644 --- a/apps/back-office/src/app/dashboard/pages/resource/forms-tab/forms-tab.component.ts +++ b/apps/back-office/src/app/dashboard/pages/resource/forms-tab/forms-tab.component.ts @@ -7,6 +7,7 @@ import { ConfirmService, UnsubscribeComponent, ResourceQueryResponse, + errorMessageFormatter, } from '@oort-front/shared'; import { TranslateService } from '@ngx-translate/core'; import { DELETE_FORM } from './graphql/mutations'; @@ -81,11 +82,16 @@ export class FormsTabComponent extends UnsubscribeComponent implements OnInit { id: this.resource?.id, }, }) - .subscribe(({ data }) => { - if (data.resource) { - this.forms = data.resource.forms || []; - } - this.loading = false; + .subscribe({ + next: ({ data }) => { + if (data.resource) { + this.forms = data.resource.forms || []; + } + this.loading = false; + }, + error: () => { + this.loading = false; + }, }); } @@ -124,26 +130,22 @@ export class FormsTabComponent extends UnsubscribeComponent implements OnInit { takeUntil(this.destroy$) ) .subscribe({ - next: ({ errors }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotDeleted', { - value: this.translate.instant('common.form.one'), - error: errors ? errors[0].message : '', - }), - { error: true } - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectDeleted', { - value: this.translate.instant('common.form.one'), - }) - ); - this.forms = this.forms.filter((x: any) => x.id !== form.id); - } + next: () => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectDeleted', { + value: this.translate.instant('common.form.one'), + }) + ); + this.forms = this.forms.filter((x: any) => x.id !== form.id); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotDeleted', { + value: this.translate.instant('common.form.one'), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } diff --git a/apps/back-office/src/app/dashboard/pages/resource/layouts-tab/layouts-tab.component.ts b/apps/back-office/src/app/dashboard/pages/resource/layouts-tab/layouts-tab.component.ts index efa2ae7f5f..037a06dea0 100644 --- a/apps/back-office/src/app/dashboard/pages/resource/layouts-tab/layouts-tab.component.ts +++ b/apps/back-office/src/app/dashboard/pages/resource/layouts-tab/layouts-tab.component.ts @@ -104,11 +104,14 @@ export class LayoutsTabComponent }, }); - this.layoutsQuery.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { + this.layoutsQuery.valueChanges.pipe(takeUntil(this.destroy$)).subscribe({ + next: ({ data, loading }) => { this.updateValues(data, loading); - }); + }, + error: () => { + this.loading = false; + }, + }); } /** @@ -195,11 +198,13 @@ export class LayoutsTabComponent }), takeUntil(this.destroy$) ) - .subscribe(({ data }: any) => { - if (data.addLayout) { - this.layouts = [...this.layouts, data?.addLayout]; - this.pageInfo.length += 1; - } + .subscribe({ + next: ({ data }: any) => { + if (data.addLayout) { + this.layouts = [...this.layouts, data?.addLayout]; + this.pageInfo.length += 1; + } + }, }); } @@ -229,16 +234,18 @@ export class LayoutsTabComponent }), takeUntil(this.destroy$) ) - .subscribe(({ data }: any) => { - if (data.editLayout) { - this.layouts = this.layouts.map((x: any) => { - if (x.id === layout.id) { - return data.editLayout; - } else { - return x; - } - }); - } + .subscribe({ + next: ({ data }: any) => { + if (data.editLayout) { + this.layouts = this.layouts.map((x: any) => { + if (x.id === layout.id) { + return data.editLayout; + } else { + return x; + } + }); + } + }, }); } @@ -268,11 +275,13 @@ export class LayoutsTabComponent }), takeUntil(this.destroy$) ) - .subscribe(({ data }: any) => { - if (data.deleteLayout) { - this.layouts = this.layouts.filter((x: any) => x.id !== layout.id); - this.pageInfo.length -= 1; - } + .subscribe({ + next: ({ data }: any) => { + if (data.deleteLayout) { + this.layouts = this.layouts.filter((x: any) => x.id !== layout.id); + this.pageInfo.length -= 1; + } + }, }); } diff --git a/apps/back-office/src/app/dashboard/pages/resource/records-tab/records-tab.component.ts b/apps/back-office/src/app/dashboard/pages/resource/records-tab/records-tab.component.ts index 8fcf8f6c35..cfff27964b 100644 --- a/apps/back-office/src/app/dashboard/pages/resource/records-tab/records-tab.component.ts +++ b/apps/back-office/src/app/dashboard/pages/resource/records-tab/records-tab.component.ts @@ -12,6 +12,7 @@ import { RestoreRecordMutationResponse, getCachedValues, updateQueryUniqueValues, + errorMessageFormatter, } from '@oort-front/shared'; import { Apollo, QueryRef } from 'apollo-angular'; import get from 'lodash/get'; @@ -131,11 +132,14 @@ export class RecordsTabComponent showDeletedRecords: this.showDeletedRecords, }, }); - this.recordsQuery.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { + this.recordsQuery.valueChanges.pipe(takeUntil(this.destroy$)).subscribe({ + next: ({ data, loading }) => { this.updateValues(data, loading); - }); + }, + error: () => { + this.loading = false; + }, + }); } /** @@ -177,6 +181,10 @@ export class RecordsTabComponent * @param id Id of record to delete. */ private deleteRecord(id: string): void { + const deleteRecordMessage = { + success: 'common.notifications.objectDeleted', + error: 'common.notifications.objectNotDeleted', + }; this.apollo .mutate({ mutation: DELETE_RECORD, @@ -186,17 +194,11 @@ export class RecordsTabComponent }, }) .subscribe({ - next: ({ errors }) => { - this.handleRecordMutationResponse( - { - success: 'common.notifications.objectDeleted', - error: 'common.notifications.objectNotDeleted', - }, - errors - ); + next: () => { + this.handleRecordMutationResponse(deleteRecordMessage, []); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.handleRecordMutationResponse(deleteRecordMessage, errors); }, }); } @@ -220,7 +222,7 @@ export class RecordsTabComponent this.snackBar.openSnackBar( this.translate.instant(messageKeys.error, { value: this.translate.instant('common.record.one'), - error: errors ? errors[0].message : '', + error: errorMessageFormatter(errors), }), { error: true } ); @@ -242,6 +244,10 @@ export class RecordsTabComponent */ public onRestoreRecord(id: string, e: any): void { e.stopPropagation(); + const restoreRecordMessage = { + success: 'common.notifications.objectRestored', + error: 'common.notifications.objectNotRestored', + }; this.apollo .mutate({ mutation: RESTORE_RECORD, @@ -250,17 +256,11 @@ export class RecordsTabComponent }, }) .subscribe({ - next: ({ errors }) => { - this.handleRecordMutationResponse( - { - success: 'common.notifications.objectRestored', - error: 'common.notifications.objectNotRestored', - }, - errors - ); + next: () => { + this.handleRecordMutationResponse(restoreRecordMessage, []); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.handleRecordMutationResponse(restoreRecordMessage, errors); }, }); } diff --git a/apps/back-office/src/app/dashboard/pages/resource/resource.component.ts b/apps/back-office/src/app/dashboard/pages/resource/resource.component.ts index 011d1e688c..03bbc4093a 100644 --- a/apps/back-office/src/app/dashboard/pages/resource/resource.component.ts +++ b/apps/back-office/src/app/dashboard/pages/resource/resource.component.ts @@ -5,6 +5,7 @@ import { EditResourceMutationResponse, ResourceQueryResponse, BreadcrumbService, + errorMessageFormatter, } from '@oort-front/shared'; import { EDIT_RESOURCE } from './graphql/mutations'; import { GET_RESOURCE_BY_ID } from './graphql/queries'; @@ -104,21 +105,16 @@ export class ResourceComponent implements OnInit { ); history.pushState({ resource: this.resource }, ''); this.loading = loading; - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.accessNotProvided', { - type: this.translate - .instant('common.resource.one') - .toLowerCase(), - error: '', - }), - { error: true } - ); - this.router.navigate(['/resources']); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: () => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.accessNotProvided', { + type: this.translate.instant('common.resource.one').toLowerCase(), + error: '', + }), + { error: true } + ); this.router.navigate(['/resources']); }, }); @@ -139,29 +135,25 @@ export class ResourceComponent implements OnInit { }, }) .subscribe({ - next: ({ errors, data }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotUpdated', { - type: this.translate.instant('common.resource.one'), - error: errors ? errors[0].message : '', - }), - { error: true } - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectUpdated', { - type: this.translate.instant('common.resource.one'), - value: '', - }) - ); - if (data) { - this.resource = data.editResource; - } + next: ({ data }) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectUpdated', { + type: this.translate.instant('common.resource.one'), + value: '', + }) + ); + if (data) { + this.resource = data.editResource; } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotUpdated', { + type: this.translate.instant('common.resource.one'), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } diff --git a/apps/back-office/src/app/dashboard/pages/resources/resources.component.ts b/apps/back-office/src/app/dashboard/pages/resources/resources.component.ts index f0d355462d..9d84da802a 100644 --- a/apps/back-office/src/app/dashboard/pages/resources/resources.component.ts +++ b/apps/back-office/src/app/dashboard/pages/resources/resources.component.ts @@ -11,6 +11,7 @@ import { ResourcesQueryResponse, getCachedValues, updateQueryUniqueValues, + errorMessageFormatter, } from '@oort-front/shared'; import { Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; @@ -128,11 +129,15 @@ export class ResourcesComponent extends UnsubscribeComponent implements OnInit { }, }); - this.resourcesQuery.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { + this.resourcesQuery.valueChanges.pipe(takeUntil(this.destroy$)).subscribe({ + next: ({ data, loading }) => { this.updateValues(data, loading); - }); + }, + error: () => { + this.loading = false; + this.updating = false; + }, + }); } /** @@ -251,23 +256,24 @@ export class ResourcesComponent extends UnsubscribeComponent implements OnInit { }), takeUntil(this.destroy$) ) - .subscribe(({ errors }) => { - if (!errors) { + .subscribe({ + next: () => { this.resources = this.resources.filter((x) => x.id !== resource.id); this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectDeleted', { value: this.translate.instant('common.resource.one'), }) ); - } else { + }, + error: (errors) => { this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectNotDeleted', { value: this.translate.instant('common.resource.one'), - error: errors[0].message, + error: errorMessageFormatter(errors), }), { error: true } ); - } + }, }); } @@ -293,24 +299,20 @@ export class ResourcesComponent extends UnsubscribeComponent implements OnInit { takeUntil(this.destroy$) ) .subscribe({ - next: ({ errors, data }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotCreated', { - type: this.translate.instant('common.form.one').toLowerCase(), - error: errors[0].message, - }), - { error: true } - ); - } else { - if (data) { - const { id } = data.addForm; - this.router.navigate(['/forms/builder', id]); - } + next: ({ data }) => { + if (data) { + const { id } = data.addForm; + this.router.navigate(['/forms/builder', id]); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotCreated', { + type: this.translate.instant('common.form.one').toLowerCase(), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } diff --git a/apps/back-office/src/app/dashboard/pages/update-record/update-record.component.ts b/apps/back-office/src/app/dashboard/pages/update-record/update-record.component.ts index 9323e094a5..2e3dac617d 100644 --- a/apps/back-office/src/app/dashboard/pages/update-record/update-record.component.ts +++ b/apps/back-office/src/app/dashboard/pages/update-record/update-record.component.ts @@ -60,13 +60,18 @@ export class UpdateRecordComponent }, }) .valueChanges.pipe(takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { - this.form = data.form; - this.breadcrumbService.setBreadcrumb( - '@resource', - this.form.name as string - ); - this.loading = loading; + .subscribe({ + next: ({ data, loading }) => { + this.form = data.form; + this.breadcrumbService.setBreadcrumb( + '@resource', + this.form.name as string + ); + this.loading = loading; + }, + error: () => { + this.loading = false; + }, }); } if (this.id !== null) { @@ -78,24 +83,29 @@ export class UpdateRecordComponent }, }) .valueChanges.pipe(takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { - this.record = data.record; - this.breadcrumbService.setBreadcrumb( - '@record', - this.record.incrementalId as string - ); - this.breadcrumbService.setBreadcrumb( - '@form', - this.record.form?.name as string - ); - this.breadcrumbService.setBreadcrumb( - '@resource', - this.record.form?.name as string - ); - if (!template) { - this.form = this.record.form || {}; - this.loading = loading; - } + .subscribe({ + next: ({ data, loading }) => { + this.record = data.record; + this.breadcrumbService.setBreadcrumb( + '@record', + this.record.incrementalId as string + ); + this.breadcrumbService.setBreadcrumb( + '@form', + this.record.form?.name as string + ); + this.breadcrumbService.setBreadcrumb( + '@resource', + this.record.form?.name as string + ); + if (!template) { + this.form = this.record.form || {}; + this.loading = loading; + } + }, + error: () => { + this.loading = false; + }, }); } } diff --git a/apps/back-office/src/app/dashboard/pages/users/users.component.ts b/apps/back-office/src/app/dashboard/pages/users/users.component.ts index c5ad782949..d9bd622dcf 100644 --- a/apps/back-office/src/app/dashboard/pages/users/users.component.ts +++ b/apps/back-office/src/app/dashboard/pages/users/users.component.ts @@ -12,6 +12,7 @@ import { UnsubscribeComponent, User, UsersNodeQueryResponse, + errorMessageFormatter, getCachedValues, updateQueryUniqueValues, } from '@oort-front/shared'; @@ -24,7 +25,14 @@ import { } from '@oort-front/ui'; import { Dialog } from '@angular/cdk/dialog'; import { TranslateService } from '@ngx-translate/core'; -import { filter, map, switchMap, takeUntil } from 'rxjs'; +import { + catchError, + filter, + map, + switchMap, + takeUntil, + throwError, +} from 'rxjs'; import { CompositeFilterDescriptor } from '@progress/kendo-data-query'; import { ApolloQueryResult } from '@apollo/client'; import { isNil } from 'lodash'; @@ -122,16 +130,24 @@ export class UsersComponent extends UnsubscribeComponent implements OnInit { query: GET_ROLES, }) .valueChanges.pipe(takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { - this.roles = data.roles; - this.loading = loading; + .subscribe({ + next: ({ data, loading }) => { + this.roles = data.roles; + this.loading = loading; + }, + error: () => { + this.loading = false; + }, }); - this.usersQuery.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { + this.usersQuery.valueChanges.pipe(takeUntil(this.destroy$)).subscribe({ + next: ({ data, loading }) => { this.loading = true; this.updateValues(data, loading); - }); + }, + error: () => { + this.loading = false; + }, + }); } /** @@ -170,47 +186,43 @@ export class UsersComponent extends UnsubscribeComponent implements OnInit { }, }) .pipe( - map(({ data, errors }) => { - return { - data, - errors, - usersLength: value.length, - }; - }) + catchError((errors) => + throwError(() => { + return { errors, usersLength: value.length }; + }) + ) ); }), takeUntil(this.destroy$) ) .subscribe({ - next: ({ errors, data, usersLength }) => { - if (!errors) { - if (data?.addUsers.length) { - this.snackBar.openSnackBar( - this.translate.instant('components.users.onInvite.plural') - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('components.users.onInvite.singular') - ); - } - this.fetchUsers(true); + next: ({ data }) => { + if (data?.addUsers.length) { + this.snackBar.openSnackBar( + this.translate.instant('components.users.onInvite.plural') + ); } else { - if (usersLength > 1) { - this.snackBar.openSnackBar( - this.translate.instant('components.users.onNotInvite.plural', { - error: errors[0].message, - }), - { error: true } - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant( - 'components.users.onNotInvite.singular', - { error: errors[0].message } - ), - { error: true } - ); - } + this.snackBar.openSnackBar( + this.translate.instant('components.users.onInvite.singular') + ); + } + this.fetchUsers(true); + }, + error: ({ errors, usersLength }) => { + if (usersLength > 1) { + this.snackBar.openSnackBar( + this.translate.instant('components.users.onNotInvite.plural', { + error: errorMessageFormatter(errors), + }), + { error: true } + ); + } else { + this.snackBar.openSnackBar( + this.translate.instant('components.users.onNotInvite.singular', { + error: errorMessageFormatter(errors), + }), + { error: true } + ); } }, }); @@ -261,24 +273,40 @@ export class UsersComponent extends UnsubscribeComponent implements OnInit { variables: { ids }, }) .pipe( - map(({ data, errors }) => { + map(({ data }) => { return { data, - errors, deletedUsers: ids.length, }; - }) + }), + catchError((errors) => + throwError(() => { + return { errors, deletedUsers: ids.length }; + }) + ) ); }), takeUntil(this.destroy$) ) .subscribe({ - next: ({ errors, data, deletedUsers }) => { - if (errors) { + next: ({ data, deletedUsers }) => { + this.loading = false; + if (data?.deleteUsers) { + if (data.deleteUsers > 1) { + this.snackBar.openSnackBar( + this.translate.instant('components.users.onDelete.plural') + ); + } else { + this.snackBar.openSnackBar( + this.translate.instant('components.users.onDelete.singular') + ); + } + this.fetchUsers(true); + } else { if (deletedUsers > 1) { this.snackBar.openSnackBar( this.translate.instant('components.users.onNotDelete.plural', { - error: errors ? errors[0].message : '', + error: '', }), { error: true } ); @@ -286,43 +314,29 @@ export class UsersComponent extends UnsubscribeComponent implements OnInit { this.snackBar.openSnackBar( this.translate.instant( 'components.users.onNotDelete.singular', - { error: errors ? errors[0].message : '' } + { error: '' } ), { error: true } ); } + } + }, + error: ({ errors, deletedUsers }) => { + this.loading = false; + if (deletedUsers > 1) { + this.snackBar.openSnackBar( + this.translate.instant('components.users.onNotDelete.plural', { + error: errorMessageFormatter(errors), + }), + { error: true } + ); } else { - this.loading = false; - if (data?.deleteUsers) { - if (data.deleteUsers > 1) { - this.snackBar.openSnackBar( - this.translate.instant('components.users.onDelete.plural') - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('components.users.onDelete.singular') - ); - } - this.fetchUsers(true); - } else { - if (deletedUsers > 1) { - this.snackBar.openSnackBar( - this.translate.instant( - 'components.users.onNotDelete.plural', - { error: '' } - ), - { error: true } - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant( - 'components.users.onNotDelete.singular', - { error: '' } - ), - { error: true } - ); - } - } + this.snackBar.openSnackBar( + this.translate.instant('components.users.onNotDelete.singular', { + error: errorMessageFormatter(errors), + }), + { error: true } + ); } }, }); diff --git a/apps/back-office/src/app/graphql.module.ts b/apps/back-office/src/app/graphql.module.ts index 5fddd0e4aa..f4fdcf8985 100644 --- a/apps/back-office/src/app/graphql.module.ts +++ b/apps/back-office/src/app/graphql.module.ts @@ -14,6 +14,7 @@ import extractFiles from 'extract-files/extractFiles.mjs'; import isExtractableFile from 'extract-files/isExtractableFile.mjs'; import { GraphQLWsLink } from '@apollo/client/link/subscriptions'; import { createClient } from 'graphql-ws'; +import { createGraphQlErrorHandler } from '@oort-front/shared'; /** * Configuration of the Apollo client. @@ -52,6 +53,7 @@ export const createApollo = (httpLink: HttpLink): ApolloClientOptions => { const link = ApolloLink.from([ basic, + createGraphQlErrorHandler(console.error), split( ({ query }) => { const { kind, operation }: Definition = getMainDefinition(query); diff --git a/apps/front-office/src/app/app.module.ts b/apps/front-office/src/app/app.module.ts index 258f69fbbd..e93ac7448a 100644 --- a/apps/front-office/src/app/app.module.ts +++ b/apps/front-office/src/app/app.module.ts @@ -29,6 +29,7 @@ import { AuthInterceptorService, FormService, DatePipe, + ErrorHandlerInterceptorService, } from '@oort-front/shared'; import { registerLocaleData } from '@angular/common'; import localeFr from '@angular/common/locales/fr'; @@ -142,6 +143,11 @@ export const httpTranslateLoader = (http: HttpClient) => useClass: AuthInterceptorService, multi: true, }, + { + provide: HTTP_INTERCEPTORS, + useClass: ErrorHandlerInterceptorService, + multi: true, + }, { provide: AppAbility, useValue: new AppAbility(), diff --git a/apps/front-office/src/app/application/pages/form/form.component.ts b/apps/front-office/src/app/application/pages/form/form.component.ts index 92d350afae..1ff975d3db 100644 --- a/apps/front-office/src/app/application/pages/form/form.component.ts +++ b/apps/front-office/src/app/application/pages/form/form.component.ts @@ -114,12 +114,17 @@ export class FormComponent extends UnsubscribeComponent implements OnInit { }), takeUntil(this.destroy$) ) - .subscribe((res: any) => { - // If a query is already loading, cancel it - if (this.querySubscription) { - this.querySubscription.unsubscribe(); - } - this.handleApplicationLoadResponse(res.data, res.loading); + .subscribe({ + next: (res: any) => { + // If a query is already loading, cancel it + if (this.querySubscription) { + this.querySubscription.unsubscribe(); + } + this.handleApplicationLoadResponse(res.data, res.loading); + }, + error: () => { + this.loading = false; + }, }); } diff --git a/apps/front-office/src/app/application/pages/share/share.component.ts b/apps/front-office/src/app/application/pages/share/share.component.ts index 4b9aa9e631..e9728694d4 100644 --- a/apps/front-office/src/app/application/pages/share/share.component.ts +++ b/apps/front-office/src/app/application/pages/share/share.component.ts @@ -6,6 +6,7 @@ import { Dashboard, DashboardQueryResponse, UnsubscribeComponent, + errorMessageFormatter, } from '@oort-front/shared'; import { GET_SHARE_DASHBOARD_BY_ID } from './graphql/queries'; import { switchMap, takeUntil } from 'rxjs/operators'; @@ -55,19 +56,23 @@ export class ShareComponent extends UnsubscribeComponent implements OnInit { }), takeUntil(this.destroy$) ) - .subscribe(({ data }) => { - let url = ''; - const dashboard: Dashboard = data.dashboard; - if (dashboard) { - if (dashboard.step) { - url += '/' + data.dashboard.step?.workflow?.page?.application?.id; - url += '/workflow/' + data.dashboard.step?.workflow?.id; - url += '/dashboard/' + data.dashboard.id; - } else { - url += '/' + data.dashboard.page?.application?.id; - url += '/dashboard/' + data.dashboard.id; + .subscribe({ + next: ({ data }) => { + let url = ''; + const dashboard: Dashboard = data.dashboard; + if (dashboard) { + if (dashboard.step) { + url += '/' + data.dashboard.step?.workflow?.page?.application?.id; + url += '/workflow/' + data.dashboard.step?.workflow?.id; + url += '/dashboard/' + data.dashboard.id; + } else { + url += '/' + data.dashboard.page?.application?.id; + url += '/dashboard/' + data.dashboard.id; + } + this.router.navigate([url]); } - } else { + }, + error: (errors) => { // Error handling this.snackBar.openSnackBar( this.translateService.instant( @@ -76,13 +81,12 @@ export class ShareComponent extends UnsubscribeComponent implements OnInit { type: this.translateService .instant('common.dashboard.one') .toLowerCase(), - error: '', + error: errorMessageFormatter(errors), } ), { error: true } ); - } - this.router.navigate([url]); + }, }); } } diff --git a/apps/front-office/src/app/application/pages/workflow/workflow.component.ts b/apps/front-office/src/app/application/pages/workflow/workflow.component.ts index 5c3aff07ca..9fefbd9317 100644 --- a/apps/front-office/src/app/application/pages/workflow/workflow.component.ts +++ b/apps/front-office/src/app/application/pages/workflow/workflow.component.ts @@ -7,6 +7,7 @@ import { Workflow, UnsubscribeComponent, WorkflowQueryResponse, + errorMessageFormatter, } from '@oort-front/shared'; import { GET_WORKFLOW_BY_ID } from './graphql/queries'; import { TranslateService } from '@ngx-translate/core'; @@ -118,20 +119,17 @@ export class WorkflowComponent extends UnsubscribeComponent implements OnInit { } this.onOpenStep(currentActiveStep); } - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.accessNotProvided', { - type: this.translate - .instant('common.workflow.one') - .toLowerCase(), - error: '', - }), - { error: true } - ); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.loading = false; + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.accessNotProvided', { + type: this.translate.instant('common.workflow.one').toLowerCase(), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } diff --git a/apps/front-office/src/app/graphql.module.ts b/apps/front-office/src/app/graphql.module.ts index eb2b400550..2d339fb92d 100644 --- a/apps/front-office/src/app/graphql.module.ts +++ b/apps/front-office/src/app/graphql.module.ts @@ -14,6 +14,7 @@ import extractFiles from 'extract-files/extractFiles.mjs'; import isExtractableFile from 'extract-files/isExtractableFile.mjs'; import { GraphQLWsLink } from '@apollo/client/link/subscriptions'; import { createClient } from 'graphql-ws'; +import { createGraphQlErrorHandler } from '@oort-front/shared'; /** * Configuration of the Apollo client. @@ -52,6 +53,7 @@ export const createApollo = (httpLink: HttpLink): ApolloClientOptions => { const link = ApolloLink.from([ basic, + createGraphQlErrorHandler(console.error), split( ({ query }) => { const { kind, operation }: Definition = getMainDefinition(query); diff --git a/apps/web-widgets/src/app/graphql.module.ts b/apps/web-widgets/src/app/graphql.module.ts index 113d734641..7e576c1cb1 100644 --- a/apps/web-widgets/src/app/graphql.module.ts +++ b/apps/web-widgets/src/app/graphql.module.ts @@ -14,6 +14,7 @@ import extractFiles from 'extract-files/extractFiles.mjs'; import isExtractableFile from 'extract-files/isExtractableFile.mjs'; import { GraphQLWsLink } from '@apollo/client/link/subscriptions'; import { createClient } from 'graphql-ws'; +import { createGraphQlErrorHandler } from '@oort-front/shared'; /** * Configuration of the Apollo client. @@ -63,6 +64,7 @@ export const createApollo = (httpLink: HttpLink): ApolloClientOptions => { const link = ApolloLink.from([ basic, + createGraphQlErrorHandler(console.error), auth, split( ({ query }) => { diff --git a/apps/web-widgets/src/app/widgets/app-widget/application/pages/form/form.component.ts b/apps/web-widgets/src/app/widgets/app-widget/application/pages/form/form.component.ts index 29c8c65338..61a7673925 100644 --- a/apps/web-widgets/src/app/widgets/app-widget/application/pages/form/form.component.ts +++ b/apps/web-widgets/src/app/widgets/app-widget/application/pages/form/form.component.ts @@ -114,11 +114,16 @@ export class FormComponent extends UnsubscribeComponent implements OnInit { }), takeUntil(this.destroy$) ) - .subscribe((res: any) => { - if (this.querySubscription) { - this.querySubscription.unsubscribe(); - } - this.handleApplicationLoadResponse(res.data, res.loading); + .subscribe({ + next: (res: any) => { + if (this.querySubscription) { + this.querySubscription.unsubscribe(); + } + this.handleApplicationLoadResponse(res.data, res.loading); + }, + error: () => { + this.loading = false; + }, }); } diff --git a/apps/web-widgets/src/app/widgets/app-widget/application/pages/share/share.component.ts b/apps/web-widgets/src/app/widgets/app-widget/application/pages/share/share.component.ts index afe623a606..dda4a5f5ad 100644 --- a/apps/web-widgets/src/app/widgets/app-widget/application/pages/share/share.component.ts +++ b/apps/web-widgets/src/app/widgets/app-widget/application/pages/share/share.component.ts @@ -6,6 +6,7 @@ import { Dashboard, DashboardQueryResponse, UnsubscribeComponent, + errorMessageFormatter, } from '@oort-front/shared'; import { GET_SHARE_DASHBOARD_BY_ID } from './graphql/queries'; import { switchMap, takeUntil } from 'rxjs/operators'; @@ -55,19 +56,23 @@ export class ShareComponent extends UnsubscribeComponent implements OnInit { }), takeUntil(this.destroy$) ) - .subscribe(({ data }) => { - let url = ''; - const dashboard: Dashboard = data.dashboard; - if (dashboard) { - if (dashboard.step) { - url += '/' + data.dashboard.step?.workflow?.page?.application?.id; - url += '/workflow/' + data.dashboard.step?.workflow?.id; - url += '/dashboard/' + data.dashboard.id; - } else { - url += '/' + data.dashboard.page?.application?.id; - url += '/dashboard/' + data.dashboard.id; + .subscribe({ + next: ({ data }) => { + let url = ''; + const dashboard: Dashboard = data.dashboard; + if (dashboard) { + if (dashboard.step) { + url += '/' + data.dashboard.step?.workflow?.page?.application?.id; + url += '/workflow/' + data.dashboard.step?.workflow?.id; + url += '/dashboard/' + data.dashboard.id; + } else { + url += '/' + data.dashboard.page?.application?.id; + url += '/dashboard/' + data.dashboard.id; + } + this.router.navigate([url]); } - } else { + }, + error: (errors) => { // Error handling this.snackBar.openSnackBar( this.translateService.instant( @@ -76,13 +81,12 @@ export class ShareComponent extends UnsubscribeComponent implements OnInit { type: this.translateService .instant('common.dashboard.one') .toLowerCase(), - error: '', + error: errorMessageFormatter(errors), } ), { error: true } ); - } - this.router.navigate([url]); + }, }); } } diff --git a/apps/web-widgets/src/app/widgets/app-widget/application/pages/workflow/workflow.component.ts b/apps/web-widgets/src/app/widgets/app-widget/application/pages/workflow/workflow.component.ts index 952cdbcf1d..558e97b4ab 100644 --- a/apps/web-widgets/src/app/widgets/app-widget/application/pages/workflow/workflow.component.ts +++ b/apps/web-widgets/src/app/widgets/app-widget/application/pages/workflow/workflow.component.ts @@ -7,6 +7,7 @@ import { Workflow, UnsubscribeComponent, WorkflowQueryResponse, + errorMessageFormatter, } from '@oort-front/shared'; import { GET_WORKFLOW_BY_ID } from './graphql/queries'; import { TranslateService } from '@ngx-translate/core'; @@ -101,20 +102,16 @@ export class WorkflowComponent extends UnsubscribeComponent implements OnInit { } this.onOpenStep(currentActiveStep); } - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.accessNotProvided', { - type: this.translate - .instant('common.workflow.one') - .toLowerCase(), - error: '', - }), - { error: true } - ); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.accessNotProvided', { + type: this.translate.instant('common.workflow.one').toLowerCase(), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } diff --git a/apps/web-widgets/src/app/widgets/form-widget/components/form.component.ts b/apps/web-widgets/src/app/widgets/form-widget/components/form.component.ts index 66e3847449..fc24035dbf 100644 --- a/apps/web-widgets/src/app/widgets/form-widget/components/form.component.ts +++ b/apps/web-widgets/src/app/widgets/form-widget/components/form.component.ts @@ -58,11 +58,16 @@ export class FormComponent implements OnInit, OnChanges { * Trigger get form query action */ private getFormById() { - this.getFormQuery.subscribe(({ data, loading }) => { - if (data) { - this.form = data.form; - this.loading = loading; - } + this.getFormQuery.subscribe({ + next: ({ data, loading }) => { + if (data) { + this.form = data.form; + this.loading = loading; + } + }, + error: () => { + this.loading = false; + }, }); } diff --git a/libs/shared/src/index.ts b/libs/shared/src/index.ts index dc5819fa79..3c50b51cf2 100644 --- a/libs/shared/src/index.ts +++ b/libs/shared/src/index.ts @@ -25,6 +25,7 @@ export * from './lib/services/data-template/data-template.service'; export * from './lib/services/editor/editor.service'; export * from './lib/services/rest/rest.service'; export * from './lib/services/map/map-layers.service'; +export * from './lib/interceptors/error-handler/error-handler-interceptor.service'; // === DIRECTIVES === export * from './lib/directives/skeleton/public-api'; diff --git a/libs/shared/src/lib/components/access/edit-access/edit-access.component.ts b/libs/shared/src/lib/components/access/edit-access/edit-access.component.ts index 16d39d14be..103fd11e3d 100644 --- a/libs/shared/src/lib/components/access/edit-access/edit-access.component.ts +++ b/libs/shared/src/lib/components/access/edit-access/edit-access.component.ts @@ -86,8 +86,10 @@ export class EditAccessComponent }, }) .pipe(takeUntil(this.destroy$)) - .subscribe(({ data }) => { - this.roles = data.roles; + .subscribe({ + next: ({ data }) => { + this.roles = data.roles; + }, }); if (!this.useModal) { diff --git a/libs/shared/src/lib/components/aggregation/add-aggregation-modal/add-aggregation-modal.component.ts b/libs/shared/src/lib/components/aggregation/add-aggregation-modal/add-aggregation-modal.component.ts index dfcadcb408..6fdc1b268f 100644 --- a/libs/shared/src/lib/components/aggregation/add-aggregation-modal/add-aggregation-modal.component.ts +++ b/libs/shared/src/lib/components/aggregation/add-aggregation-modal/add-aggregation-modal.component.ts @@ -155,12 +155,15 @@ export class AddAggregationModalComponent }), takeUntil(this.destroy$) ) - .subscribe(({ data }) => { - if (data?.addAggregation) { - this.dialogRef.close(data.addAggregation as any); - } else { + .subscribe({ + next: ({ data }) => { + if (data?.addAggregation) { + this.dialogRef.close(data.addAggregation as any); + } + }, + error: () => { this.dialogRef.close(); - } + }, }); } } diff --git a/libs/shared/src/lib/components/aggregation/aggregation-grid/aggregation-grid.component.ts b/libs/shared/src/lib/components/aggregation/aggregation-grid/aggregation-grid.component.ts index 1d2b68637e..1ec4b8111e 100644 --- a/libs/shared/src/lib/components/aggregation/aggregation-grid/aggregation-grid.component.ts +++ b/libs/shared/src/lib/components/aggregation/aggregation-grid/aggregation-grid.component.ts @@ -289,7 +289,12 @@ export class AggregationGridComponent }) ) .pipe(takeUntil(merge(this.cancelRefresh$, this.destroy$))) - .subscribe((results) => this.updateValues(results.data, results.loading)); + .subscribe({ + next: (results) => this.updateValues(results.data, results.loading), + error: () => { + this.loading = false; + }, + }); } /** diff --git a/libs/shared/src/lib/components/aggregation/aggregation-table/aggregation-table.component.ts b/libs/shared/src/lib/components/aggregation/aggregation-table/aggregation-table.component.ts index 3dae52afad..5645e2d89d 100644 --- a/libs/shared/src/lib/components/aggregation/aggregation-table/aggregation-table.component.ts +++ b/libs/shared/src/lib/components/aggregation/aggregation-table/aggregation-table.component.ts @@ -143,14 +143,16 @@ export class AggregationTableComponent }), takeUntil(this.destroy$) ) - .subscribe(({ data }: any) => { - if (data.editAggregation) { - const layouts = [...this.allAggregations]; - const index = layouts.findIndex((x) => x.id === aggregation.id); - layouts[index] = data.editAggregation; - this.allAggregations = layouts; - this.setSelectedAggregations(this.selectedAggregations?.value); - } + .subscribe({ + next: ({ data }: any) => { + if (data.editAggregation) { + const layouts = [...this.allAggregations]; + const index = layouts.findIndex((x) => x.id === aggregation.id); + layouts[index] = data.editAggregation; + this.allAggregations = layouts; + this.setSelectedAggregations(this.selectedAggregations?.value); + } + }, }); } diff --git a/libs/shared/src/lib/components/controls/reference-data-select/reference-data-select.component.ts b/libs/shared/src/lib/components/controls/reference-data-select/reference-data-select.component.ts index d4055b4b0b..c336d7e429 100644 --- a/libs/shared/src/lib/components/controls/reference-data-select/reference-data-select.component.ts +++ b/libs/shared/src/lib/components/controls/reference-data-select/reference-data-select.component.ts @@ -102,9 +102,14 @@ export class ReferenceDataSelectComponent extends GraphQLSelectComponent { this.query.valueChanges .pipe(takeUntil(this.queryChange$), takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { - this.queryName = Object.keys(data)[0]; - this.updateValues(data, loading); + .subscribe({ + next: ({ data, loading }) => { + this.queryName = Object.keys(data)[0]; + this.updateValues(data, loading); + }, + error: () => { + this.loading = false; + }, }); } super.onOpenSelect(); diff --git a/libs/shared/src/lib/components/controls/resource-select/resource-select.component.ts b/libs/shared/src/lib/components/controls/resource-select/resource-select.component.ts index 4fb555a4d1..d8106d00f3 100644 --- a/libs/shared/src/lib/components/controls/resource-select/resource-select.component.ts +++ b/libs/shared/src/lib/components/controls/resource-select/resource-select.component.ts @@ -102,9 +102,14 @@ export class ResourceSelectComponent extends GraphQLSelectComponent { this.query.valueChanges .pipe(takeUntil(this.queryChange$), takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { - this.queryName = Object.keys(data)[0]; - this.updateValues(data, loading); + .subscribe({ + next: ({ data, loading }) => { + this.queryName = Object.keys(data)[0]; + this.updateValues(data, loading); + }, + error: () => { + this.loading = false; + }, }); } super.onOpenSelect(); diff --git a/libs/shared/src/lib/components/convert-modal/convert-modal.component.ts b/libs/shared/src/lib/components/convert-modal/convert-modal.component.ts index 613cf179e1..d44c991c2b 100644 --- a/libs/shared/src/lib/components/convert-modal/convert-modal.component.ts +++ b/libs/shared/src/lib/components/convert-modal/convert-modal.component.ts @@ -100,13 +100,18 @@ export class ConvertModalComponent }, }) .pipe(takeUntil(this.destroy$)) - .subscribe(({ data }) => { - const record = data.record; - this.form = record.form; - this.loading = false; - this.availableForms = - this.form?.resource?.forms?.filter((x) => x.id !== this.form?.id) || - []; + .subscribe({ + next: ({ data }) => { + const record = data.record; + this.form = record.form; + this.loading = false; + this.availableForms = + this.form?.resource?.forms?.filter((x) => x.id !== this.form?.id) || + []; + }, + error: () => { + this.loading = false; + }, }); this.convertForm .get('targetForm') diff --git a/libs/shared/src/lib/components/custom-widget-style/custom-widget-style.component.ts b/libs/shared/src/lib/components/custom-widget-style/custom-widget-style.component.ts index e677e429e9..30ca5070c4 100644 --- a/libs/shared/src/lib/components/custom-widget-style/custom-widget-style.component.ts +++ b/libs/shared/src/lib/components/custom-widget-style/custom-widget-style.component.ts @@ -118,13 +118,18 @@ export class CustomWidgetStyleComponent }), takeUntil(this.destroy$) ) - .subscribe(({ css, value }) => { - set(this.widgetComp, 'widget.settings.widgetDisplay.style', value); - this.styleApplied.innerText = css; - this.document - .getElementsByTagName('head')[0] - .appendChild(this.styleApplied); - this.loading = false; + .subscribe({ + next: ({ css, value }) => { + set(this.widgetComp, 'widget.settings.widgetDisplay.style', value); + this.styleApplied.innerText = css; + this.document + .getElementsByTagName('head')[0] + .appendChild(this.styleApplied); + this.loading = false; + }, + error: () => { + this.loading = false; + }, }); } diff --git a/libs/shared/src/lib/components/distribution-lists/distribution-lists.component.ts b/libs/shared/src/lib/components/distribution-lists/distribution-lists.component.ts index c59d09ba40..3178507b1a 100644 --- a/libs/shared/src/lib/components/distribution-lists/distribution-lists.component.ts +++ b/libs/shared/src/lib/components/distribution-lists/distribution-lists.component.ts @@ -4,7 +4,6 @@ import { ApplicationService } from '../../services/application/application.servi import { Dialog } from '@angular/cdk/dialog'; import { takeUntil } from 'rxjs'; import { UnsubscribeComponent } from '../utils/unsubscribe/unsubscribe.component'; -import { SnackbarService } from '@oort-front/ui'; import { DistributionList } from '../../models/distribution-list.model'; /** @@ -36,13 +35,8 @@ export class DistributionListsComponent * * @param dialog The Dialog service * @param translate The translation service - * @param snackBar Shared snackbar service */ - constructor( - public dialog: Dialog, - private translate: TranslateService, - private snackBar: SnackbarService - ) { + constructor(public dialog: Dialog, private translate: TranslateService) { super(); } @@ -78,12 +72,6 @@ export class DistributionListsComponent name: value.name, emails: value.emails, }); - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectUpdated', { - value: value.name, - type: this.translate.instant('common.distributionList.one'), - }) - ); } }); } @@ -105,12 +93,6 @@ export class DistributionListsComponent name: value.name, emails: value.emails, }); - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectCreated', { - value: value.name, - type: this.translate.instant('common.distributionList.one'), - }) - ); } }); } @@ -147,11 +129,6 @@ export class DistributionListsComponent this.applicationService.deleteDistributionList( distributionList.id || '' ); - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectDeleted', { - value: distributionList.name, - }) - ); } }); } diff --git a/libs/shared/src/lib/components/draft-record-list-modal/draft-record-list-modal.component.ts b/libs/shared/src/lib/components/draft-record-list-modal/draft-record-list-modal.component.ts index 98d3ed3b92..e8af607e09 100644 --- a/libs/shared/src/lib/components/draft-record-list-modal/draft-record-list-modal.component.ts +++ b/libs/shared/src/lib/components/draft-record-list-modal/draft-record-list-modal.component.ts @@ -107,10 +107,15 @@ export class DraftRecordListModalComponent form: this.data.form, }, }) - .subscribe(({ data }) => { - this.form = data.form; - this.draftRecords = data.draftRecords; - this.loading = false; + .subscribe({ + next: ({ data }) => { + this.form = data.form; + this.draftRecords = data.draftRecords; + this.loading = false; + }, + error: () => { + this.loading = false; + }, }); } diff --git a/libs/shared/src/lib/components/form-modal/form-modal.component.ts b/libs/shared/src/lib/components/form-modal/form-modal.component.ts index d7be3651a2..6c01f7644b 100644 --- a/libs/shared/src/lib/components/form-modal/form-modal.component.ts +++ b/libs/shared/src/lib/components/form-modal/form-modal.component.ts @@ -47,6 +47,7 @@ import { UnsubscribeComponent } from '../utils/unsubscribe/unsubscribe.component import { FormHelpersService } from '../../services/form-helper/form-helper.service'; import { DialogModule } from '@oort-front/ui'; import { DraftRecordComponent } from '../draft-record/draft-record.component'; +import { errorMessageFormatter } from '../../utils/graphql/error-handler'; /** * Interface of Dialog data. @@ -359,34 +360,33 @@ export class FormModalComponent }, }) .subscribe({ - next: ({ errors, data }) => { - if (errors) { - this.snackBar.openSnackBar(`Error. ${errors[0].message}`, { - error: true, - }); - this.ngZone.run(() => { - this.dialogRef.close(); - }); - } else { - if (this.lastDraftRecord) { - const callback = () => { - this.lastDraftRecord = undefined; - }; - this.formHelpersService.deleteRecordDraft( - this.lastDraftRecord, - callback - ); - } - this.ngZone.run(() => { - this.dialogRef.close({ - template: this.data.template, - data: data?.addRecord, - } as any); - }); + next: ({ data }) => { + if (this.lastDraftRecord) { + const callback = () => { + this.lastDraftRecord = undefined; + }; + this.formHelpersService.deleteRecordDraft( + this.lastDraftRecord, + callback + ); } + this.ngZone.run(() => { + this.dialogRef.close({ + template: this.data.template, + data: data?.addRecord, + } as any); + }); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + `Error. ${errorMessageFormatter(errors)}`, + { + error: true, + } + ); + this.ngZone.run(() => { + this.dialogRef.close(); + }); }, }); } @@ -410,11 +410,14 @@ export class FormModalComponent }, }) .subscribe({ - next: ({ errors, data }) => { - this.handleRecordMutationResponse({ data, errors }, 'editRecord'); + next: ({ data }) => { + this.handleRecordMutationResponse({ data, errors: [] }, 'editRecord'); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.handleRecordMutationResponse( + { data: null, errors }, + 'editRecord' + ); }, }); } @@ -437,7 +440,7 @@ export class FormModalComponent }, }) .subscribe({ - next: ({ errors, data }) => { + next: ({ data }) => { if (this.lastDraftRecord) { const callback = () => { this.lastDraftRecord = undefined; @@ -447,10 +450,16 @@ export class FormModalComponent callback ); } - this.handleRecordMutationResponse({ data, errors }, 'editRecords'); + this.handleRecordMutationResponse( + { data, errors: [] }, + 'editRecords' + ); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.handleRecordMutationResponse( + { data: null, errors }, + 'editRecords' + ); }, }); } @@ -472,11 +481,11 @@ export class FormModalComponent responseType === 'editRecords' ? this.translate.instant('common.record.few') : this.translate.instant('common.record.one'); - if (errors) { + if (errors?.length) { this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectNotUpdated', { type, - error: errors ? errors[0].message : '', + error: errorMessageFormatter(errors), }), { error: true } ); @@ -629,21 +638,18 @@ export class FormModalComponent takeUntil(this.destroy$) ) .subscribe({ - next: (errors) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.dataNotRecovered'), - { error: true } - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.dataRecovered') - ); - } + next: () => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.dataRecovered') + ); this.dialog.closeAll(); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: () => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.dataNotRecovered'), + { error: true } + ); + this.dialog.closeAll(); }, }); } diff --git a/libs/shared/src/lib/components/form/form.component.ts b/libs/shared/src/lib/components/form/form.component.ts index 373e115359..714ce4acad 100644 --- a/libs/shared/src/lib/components/form/form.component.ts +++ b/libs/shared/src/lib/components/form/form.component.ts @@ -28,6 +28,7 @@ import { UnsubscribeComponent } from '../utils/unsubscribe/unsubscribe.component import { FormHelpersService } from '../../services/form-helper/form-helper.service'; import { SnackbarService, UILayoutService } from '@oort-front/ui'; import { isNil } from 'lodash'; +import { errorMessageFormatter } from '../../utils/graphql/error-handler'; /** * This component is used to display forms @@ -295,13 +296,8 @@ export class FormComponent }, }); } - mutation.subscribe(({ errors, data }: any) => { - if (errors) { - this.save.emit({ completed: false }); - this.survey.clear(false, true); - this.surveyActive = true; - this.snackBar.openSnackBar(errors[0].message, { error: true }); - } else { + mutation.subscribe({ + next: ({ data }: any) => { if (this.lastDraftRecord) { const callback = () => { this.lastDraftRecord = undefined; @@ -328,7 +324,15 @@ export class FormComponent completed: true, hideNewRecord: data.addRecord && data.addRecord.form.uniqueRecord, }); - } + }, + error: (errors: any) => { + this.save.emit({ completed: false }); + this.survey.clear(false, true); + this.surveyActive = true; + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); + }, }); }; @@ -409,21 +413,17 @@ export class FormComponent takeUntil(this.destroy$) ) .subscribe({ - next: ({ errors }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.dataNotRecovered'), - { error: true } - ); - } else { - this.layoutService.setRightSidenav(null); - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.dataRecovered') - ); - } + next: () => { + this.layoutService.setRightSidenav(null); + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.dataRecovered') + ); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: () => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.dataNotRecovered'), + { error: true } + ); }, }); } diff --git a/libs/shared/src/lib/components/grid-layout/add-layout-modal/add-layout-modal.component.ts b/libs/shared/src/lib/components/grid-layout/add-layout-modal/add-layout-modal.component.ts index 4c7c16aa05..b8d0f1ec1f 100644 --- a/libs/shared/src/lib/components/grid-layout/add-layout-modal/add-layout-modal.component.ts +++ b/libs/shared/src/lib/components/grid-layout/add-layout-modal/add-layout-modal.component.ts @@ -164,12 +164,15 @@ export class AddLayoutModalComponent }), takeUntil(this.destroy$) ) - .subscribe(({ data }) => { - if (data?.addLayout) { - this.dialogRef.close(data.addLayout as any); - } else { + .subscribe({ + next: ({ data }) => { + if (data?.addLayout) { + this.dialogRef.close(data.addLayout as any); + } + }, + error: () => { this.dialogRef.close(); - } + }, }); } } diff --git a/libs/shared/src/lib/components/grid-layout/layout-table/layout-table.component.ts b/libs/shared/src/lib/components/grid-layout/layout-table/layout-table.component.ts index 06bf2197bb..16acd02f2d 100644 --- a/libs/shared/src/lib/components/grid-layout/layout-table/layout-table.component.ts +++ b/libs/shared/src/lib/components/grid-layout/layout-table/layout-table.component.ts @@ -165,14 +165,16 @@ export class LayoutTableComponent }), takeUntil(this.destroy$) ) - .subscribe(({ data }: any) => { - if (data.editLayout) { - const layouts = [...this.allLayouts]; - const index = layouts.findIndex((x) => x.id === layout.id); - layouts[index] = data.editLayout; - this.allLayouts = layouts; - this.setSelectedLayouts(this.selectedLayouts?.value); - } + .subscribe({ + next: ({ data }: any) => { + if (data.editLayout) { + const layouts = [...this.allLayouts]; + const index = layouts.findIndex((x) => x.id === layout.id); + layouts[index] = data.editLayout; + this.allLayouts = layouts; + this.setSelectedLayouts(this.selectedLayouts?.value); + } + }, }); } diff --git a/libs/shared/src/lib/components/notifications/components/edit-notification-modal/edit-notification-modal.component.ts b/libs/shared/src/lib/components/notifications/components/edit-notification-modal/edit-notification-modal.component.ts index b354a3a95b..33eceb223a 100644 --- a/libs/shared/src/lib/components/notifications/components/edit-notification-modal/edit-notification-modal.component.ts +++ b/libs/shared/src/lib/components/notifications/components/edit-notification-modal/edit-notification-modal.component.ts @@ -223,11 +223,13 @@ export class EditNotificationModalComponent layoutIds: layoutId ? [layoutId] : null, }, }) - .subscribe((res) => { - this.resource = res.data.resource; - if (layoutId && this.resource.layouts?.edges[0]) { - this.layout = this.resource.layouts.edges[0].node; - } + .subscribe({ + next: (res) => { + this.resource = res.data.resource; + if (layoutId && this.resource.layouts?.edges[0]) { + this.layout = this.resource.layouts.edges[0].node; + } + }, }); } @@ -282,8 +284,10 @@ export class EditNotificationModalComponent }), takeUntil(this.destroy$) ) - .subscribe((res: any) => { - this.layout = res.data?.editLayout; + .subscribe({ + next: (res: any) => { + this.layout = res.data?.editLayout; + }, }); } diff --git a/libs/shared/src/lib/components/notifications/notifications.component.ts b/libs/shared/src/lib/components/notifications/notifications.component.ts index 3961c48417..c5cfe0bb5d 100644 --- a/libs/shared/src/lib/components/notifications/notifications.component.ts +++ b/libs/shared/src/lib/components/notifications/notifications.component.ts @@ -1,7 +1,7 @@ import { Dialog } from '@angular/cdk/dialog'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; -import { SnackbarService, UIPageChangeEvent } from '@oort-front/ui'; +import { UIPageChangeEvent } from '@oort-front/ui'; import { Apollo, QueryRef } from 'apollo-angular'; import { Subscription, filter, switchMap, takeUntil } from 'rxjs'; import { @@ -65,15 +65,13 @@ export class NotificationsComponent * @param confirmService Shared confirmation service * @param apollo Apollo service * @param applicationService Shared application service - * @param snackBar Shared snackbar service */ constructor( public dialog: Dialog, private translate: TranslateService, private confirmService: ConfirmService, private apollo: Apollo, - private applicationService: ApplicationService, - private snackBar: SnackbarService + private applicationService: ApplicationService ) { super(); } @@ -97,19 +95,25 @@ export class NotificationsComponent }), takeUntil(this.destroy$) ) - .subscribe((res) => { - this.cachedNotifications = - res.data.application.customNotifications.edges.map((x) => x.node); - this.notifications = this.cachedNotifications.slice( - this.pageInfo.pageSize * this.pageInfo.pageIndex, - this.pageInfo.pageSize * (this.pageInfo.pageIndex + 1) - ); - this.pageInfo.length = - res.data.application.customNotifications.totalCount; - this.pageInfo.endCursor = - res.data.application.customNotifications.pageInfo.endCursor; - this.loading = res.loading; - this.updating = false; + .subscribe({ + next: (res) => { + this.cachedNotifications = + res.data.application.customNotifications.edges.map((x) => x.node); + this.notifications = this.cachedNotifications.slice( + this.pageInfo.pageSize * this.pageInfo.pageIndex, + this.pageInfo.pageSize * (this.pageInfo.pageIndex + 1) + ); + this.pageInfo.length = + res.data.application.customNotifications.totalCount; + this.pageInfo.endCursor = + res.data.application.customNotifications.pageInfo.endCursor; + this.loading = res.loading; + this.updating = false; + }, + error: () => { + this.loading = false; + this.updating = false; + }, }); } @@ -143,12 +147,6 @@ export class NotificationsComponent notification.id, value, () => { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectUpdated', { - value: value.name, - type: this.translate.instant('common.customNotification.one'), - }) - ); this.notificationsQuery.refetch(); } ); @@ -179,11 +177,6 @@ export class NotificationsComponent this.applicationService.deleteCustomNotification( notification.id, () => { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectDeleted', { - value: notification.name, - }) - ); this.notificationsQuery.refetch(); } ); @@ -203,12 +196,6 @@ export class NotificationsComponent dialogRef.closed.pipe(takeUntil(this.destroy$)).subscribe((value: any) => { if (value) { this.applicationService.addCustomNotification(value, () => { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectCreated', { - value: value.name, - type: this.translate.instant('common.customNotification.one'), - }) - ); this.notificationsQuery.refetch(); }); } diff --git a/libs/shared/src/lib/components/query-builder/query-builder.component.ts b/libs/shared/src/lib/components/query-builder/query-builder.component.ts index 6fa6734fbd..3774fe56a0 100644 --- a/libs/shared/src/lib/components/query-builder/query-builder.component.ts +++ b/libs/shared/src/lib/components/query-builder/query-builder.component.ts @@ -119,27 +119,27 @@ export class QueryBuilderComponent } } else { this.availableQueries = this.queryBuilder.availableQueries$; - this.availableQueries.pipe(takeUntil(this.destroy$)).subscribe((res) => { - if (res && res.length > 0) { - if (this.queryName) { - this.allQueries = res - .filter((x) => x.name === this.queryName) - .map((x) => x.name); - if (this.allQueries.length === 1) { - this.form?.get('name')?.setValue(this.allQueries[0]); + this.availableQueries.pipe(takeUntil(this.destroy$)).subscribe({ + next: (res) => { + if (res && res.length > 0) { + if (this.queryName) { + this.allQueries = res + .filter((x) => x.name === this.queryName) + .map((x) => x.name); + if (this.allQueries.length === 1) { + this.form?.get('name')?.setValue(this.allQueries[0]); + } + this.filteredQueries = this.filterQueries(this.form?.value.name); + this.availableFields = this.queryBuilder.getFields( + this.form?.value.name + ); + this.form?.setControl( + 'filter', + createFilterGroup(this.form?.value.filter) + ); } - } else { - this.allQueries = res.filter((x) => x.name).map((x) => x.name); } - this.filteredQueries = this.filterQueries(this.form?.value.name); - this.availableFields = this.queryBuilder.getFields( - this.form?.value.name - ); - this.form?.setControl( - 'filter', - createFilterGroup(this.form?.value.filter) - ); - } + }, }); const setFormBuilderControls = ( fieldControlRequired: boolean = false diff --git a/libs/shared/src/lib/components/record-dropdown/record-dropdown.component.ts b/libs/shared/src/lib/components/record-dropdown/record-dropdown.component.ts index 8a9e411cd2..048c2e49c6 100644 --- a/libs/shared/src/lib/components/record-dropdown/record-dropdown.component.ts +++ b/libs/shared/src/lib/components/record-dropdown/record-dropdown.component.ts @@ -97,10 +97,12 @@ export class RecordDropdownComponent }, }) .pipe(takeUntil(this.destroy$)) - .subscribe(({ data }) => { - if (data.record) { - this.selectedRecord = data.record; - } + .subscribe({ + next: ({ data }) => { + if (data.record) { + this.selectedRecord = data.record; + } + }, }); } @@ -118,11 +120,14 @@ export class RecordDropdownComponent }); this.records$ = this.records.asObservable(); - this.recordsQuery.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { + this.recordsQuery.valueChanges.pipe(takeUntil(this.destroy$)).subscribe({ + next: ({ data, loading }) => { this.updateValues(data, loading); - }); + }, + error: () => { + this.loading = false; + }, + }); } } diff --git a/libs/shared/src/lib/components/record-history/record-history.component.ts b/libs/shared/src/lib/components/record-history/record-history.component.ts index 7111eab7e4..faf0f0ce6d 100644 --- a/libs/shared/src/lib/components/record-history/record-history.component.ts +++ b/libs/shared/src/lib/components/record-history/record-history.component.ts @@ -30,6 +30,7 @@ import { FormControl, FormGroup } from '@angular/forms'; import { startCase, isNil } from 'lodash'; import { ResizeEvent } from 'angular-resizable-element'; import { DOCUMENT } from '@angular/common'; +import { errorMessageFormatter } from '../../utils/graphql/error-handler'; /** * Return the type of the old value if existing, else the type of the new value. @@ -168,9 +169,11 @@ export class RecordHistoryComponent }, }) .pipe(takeUntil(this.destroy$)) - .subscribe(({ data }) => { - this.record = data.record; - this.sortedFields = this.sortFields(this.getFields()); + .subscribe({ + next: ({ data }) => { + this.record = data.record; + this.sortedFields = this.sortFields(this.getFields()); + }, }); this.apollo @@ -182,16 +185,8 @@ export class RecordHistoryComponent }, }) .pipe(takeUntil(this.destroy$)) - .subscribe(({ errors, data }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.history.error', { - error: errors[0].message, - }), - { error: true } - ); - this.cancel.emit(true); - } else { + .subscribe({ + next: ({ data }) => { this.history = data.recordHistory.filter( (item) => item.changes.length ); @@ -203,7 +198,17 @@ export class RecordHistoryComponent }); }); this.loading = false; - } + }, + error: (errors) => { + this.loading = false; + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.history.error', { + error: errorMessageFormatter(errors), + }), + { error: true } + ); + this.cancel.emit(true); + }, }); }; if (this.refresh$) { diff --git a/libs/shared/src/lib/components/record-modal/record-modal.component.ts b/libs/shared/src/lib/components/record-modal/record-modal.component.ts index 1fbc8685e0..bd327f7711 100644 --- a/libs/shared/src/lib/components/record-modal/record-modal.component.ts +++ b/libs/shared/src/lib/components/record-modal/record-modal.component.ts @@ -314,21 +314,18 @@ export class RecordModalComponent takeUntil(this.destroy$) ) .subscribe({ - next: (errors) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.dataNotRecovered'), - { error: true } - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.dataRecovered') - ); - } + next: () => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.dataRecovered') + ); this.dialogRef.close(); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: () => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.dataNotRecovered'), + { error: true } + ); + this.dialogRef.close(); }, }); } diff --git a/libs/shared/src/lib/components/role-summary/role-auto-assignment/role-auto-assignment.component.ts b/libs/shared/src/lib/components/role-summary/role-auto-assignment/role-auto-assignment.component.ts index 2f3e803b97..276b0612ae 100644 --- a/libs/shared/src/lib/components/role-summary/role-auto-assignment/role-auto-assignment.component.ts +++ b/libs/shared/src/lib/components/role-summary/role-auto-assignment/role-auto-assignment.component.ts @@ -87,39 +87,43 @@ export class RoleAutoAssignmentComponent .query({ query: GET_GROUPS, }) - .subscribe(({ data }) => { - if (data.groups) { - this.groups = data.groups; - this.fields.push({ - text: 'User Groups', - name: '{{groups}}', - editor: 'select', - multiSelect: true, - options: this.groups.map((group) => ({ - text: group.title, - value: group.id, - })), - filter: { - operators: ['eq', 'contains'], - }, - }); - } + .subscribe({ + next: ({ data }) => { + if (data.groups) { + this.groups = data.groups; + this.fields.push({ + text: 'User Groups', + name: '{{groups}}', + editor: 'select', + multiSelect: true, + options: this.groups.map((group) => ({ + text: group.title, + value: group.id, + })), + filter: { + operators: ['eq', 'contains'], + }, + }); + } + }, }); const url = '/permissions/attributes'; - this.restService.get(url).subscribe((res: any) => { - if (isArray(res)) { - res.forEach((attr: { value: string; text: string }) => { - this.fields.push({ - text: attr.text, - name: `{{attributes.${attr.value}}}`, - filter: { - operators: ['eq'], - }, - editor: 'text', + this.restService.get(url).subscribe({ + next: (res: any) => { + if (isArray(res)) { + res.forEach((attr: { value: string; text: string }) => { + this.fields.push({ + text: attr.text, + name: `{{attributes.${attr.value}}}`, + filter: { + operators: ['eq'], + }, + editor: 'text', + }); }); - }); - } + } + }, }); } diff --git a/libs/shared/src/lib/components/role-summary/role-channels/role-channels.component.ts b/libs/shared/src/lib/components/role-summary/role-channels/role-channels.component.ts index 69abee4ea8..b24686a609 100644 --- a/libs/shared/src/lib/components/role-summary/role-channels/role-channels.component.ts +++ b/libs/shared/src/lib/components/role-summary/role-channels/role-channels.component.ts @@ -65,20 +65,22 @@ export class RoleChannelsComponent }, }) .pipe(takeUntil(this.destroy$)) - .subscribe(({ data }) => { - this.channels = data.channels; - // Move channels in an array under corresponding applications. - this.applications = Array.from( - new Set(this.channels.map((x) => x.application?.name)) - ).map((name) => ({ - name: name ? name : 'Global', - channels: this.channels.reduce((o: Channel[], channel: Channel) => { - if (channel?.application?.name === name) { - o.push(channel); - } - return o; - }, []), - })); + .subscribe({ + next: ({ data }) => { + this.channels = data.channels; + // Move channels in an array under corresponding applications. + this.applications = Array.from( + new Set(this.channels.map((x) => x.application?.name)) + ).map((name) => ({ + name: name ? name : 'Global', + channels: this.channels.reduce((o: Channel[], channel: Channel) => { + if (channel?.application?.name === name) { + o.push(channel); + } + return o; + }, []), + })); + }, }); } diff --git a/libs/shared/src/lib/components/role-summary/role-details/role-details.component.ts b/libs/shared/src/lib/components/role-summary/role-details/role-details.component.ts index 3cdd97fde3..0f3228e27d 100644 --- a/libs/shared/src/lib/components/role-summary/role-details/role-details.component.ts +++ b/libs/shared/src/lib/components/role-summary/role-details/role-details.component.ts @@ -78,12 +78,16 @@ export class RoleDetailsComponent implements OnInit { application: this.role.application !== null, }, }) - .subscribe(({ data }) => { - this.permissions = data.permissions; + .subscribe({ + next: ({ data }) => { + this.permissions = data.permissions; + }, }); const url = `/roles/${this.role.id}/summary`; - this.restService.get(url).subscribe((res: any) => { - this.roleStats = res; + this.restService.get(url).subscribe({ + next: (res: any) => { + this.roleStats = res; + }, }); } diff --git a/libs/shared/src/lib/components/role-summary/role-features/role-features.component.ts b/libs/shared/src/lib/components/role-summary/role-features/role-features.component.ts index b3861d3536..5283be7707 100644 --- a/libs/shared/src/lib/components/role-summary/role-features/role-features.component.ts +++ b/libs/shared/src/lib/components/role-summary/role-features/role-features.component.ts @@ -14,6 +14,7 @@ import { Role } from '../../../models/user.model'; import { EDIT_PAGE_ACCESS } from '../graphql/mutations'; import { GET_APPLICATION_FEATURES } from '../graphql/queries'; import { SnackbarService } from '@oort-front/ui'; +import { errorMessageFormatter } from '../../../utils/public-api'; /** * Features tab of Role Summary component. @@ -73,8 +74,10 @@ export class RoleFeaturesComponent implements OnInit { ); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); }, }); } @@ -135,8 +138,11 @@ export class RoleFeaturesComponent implements OnInit { } this.loading = loading; }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.loading = false; + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); }, }); } diff --git a/libs/shared/src/lib/components/role-summary/role-features/role-workflows/role-workflows.component.ts b/libs/shared/src/lib/components/role-summary/role-features/role-workflows/role-workflows.component.ts index 4aa2eda736..9effd171df 100644 --- a/libs/shared/src/lib/components/role-summary/role-features/role-workflows/role-workflows.component.ts +++ b/libs/shared/src/lib/components/role-summary/role-features/role-workflows/role-workflows.component.ts @@ -22,6 +22,7 @@ import { EditStepMutationResponse, Step } from '../../../../models/step.model'; import { WorkflowQueryResponse } from '../../../../models/workflow.model'; import { EDIT_STEP_ACCESS } from '../../graphql/mutations'; import { SnackbarService } from '@oort-front/ui'; +import { errorMessageFormatter } from '../../../../utils/graphql/error-handler'; /** Component for the workflows section of the roles features */ @Component({ @@ -141,8 +142,10 @@ export class RoleWorkflowsComponent implements OnInit, OnChanges { ); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); }, }); } @@ -183,8 +186,11 @@ export class RoleWorkflowsComponent implements OnInit, OnChanges { } this.loading = loading; }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.loading = false; + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); }, }); } diff --git a/libs/shared/src/lib/components/role-summary/role-resources/role-resources.component.ts b/libs/shared/src/lib/components/role-summary/role-resources/role-resources.component.ts index e8ee3a3a3a..6af6e7dabe 100644 --- a/libs/shared/src/lib/components/role-summary/role-resources/role-resources.component.ts +++ b/libs/shared/src/lib/components/role-summary/role-resources/role-resources.component.ts @@ -29,6 +29,7 @@ import { UIPageChangeEvent, handleTablePageEvent, } from '@oort-front/ui'; +import { errorMessageFormatter } from '../../../utils/graphql/error-handler'; /** Default page size */ const DEFAULT_PAGE_SIZE = 10; @@ -124,11 +125,15 @@ export class RoleResourcesComponent }, }); - this.resourcesQuery.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { + this.resourcesQuery.valueChanges.pipe(takeUntil(this.destroy$)).subscribe({ + next: ({ data, loading }) => { this.updateValues(data, loading); - }); + }, + error: () => { + this.loading = false; + this.updating = false; + }, + }); } /** @@ -230,11 +235,16 @@ export class RoleResourcesComponent role: this.role.id, }, }) - .subscribe(({ data }) => { - if (data.resource) { - this.openedResource = data.resource; - } - this.updating = false; + .subscribe({ + next: ({ data }) => { + if (data.resource) { + this.openedResource = data.resource; + } + this.updating = false; + }, + error: () => { + this.updating = false; + }, }); } } @@ -299,13 +309,21 @@ export class RoleResourcesComponent }, }) .subscribe({ - next: ({ errors, data }) => { - this.handleResourceMutationResponse(resource, { data, errors }, true); + next: ({ data }) => { + this.handleResourceMutationResponse( + resource, + { data, errors: [] }, + true + ); this.updating = false; }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { this.updating = false; + this.handleResourceMutationResponse( + resource, + { data: null, errors }, + true + ); }, }); } @@ -328,12 +346,12 @@ export class RoleResourcesComponent }, }) .subscribe({ - next: ({ errors, data }) => { - this.handleResourceMutationResponse(resource, { data, errors }); + next: ({ data }) => { + this.handleResourceMutationResponse(resource, { data, errors: [] }); this.updating = false; }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.handleResourceMutationResponse(resource, { data: null, errors }); this.updating = false; }, }); @@ -375,8 +393,10 @@ export class RoleResourcesComponent this.openedResource = tableElements[index].resource; } } - if (errors) { - this.snackBar.openSnackBar(errors[0].message, { error: true }); + if (errors?.length) { + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); } } @@ -424,12 +444,12 @@ export class RoleResourcesComponent }, }) .subscribe({ - next: ({ errors, data }) => { - this.handleResourceMutationResponse(resource, { data, errors }); + next: ({ data }) => { + this.handleResourceMutationResponse(resource, { data, errors: [] }); this.updating = false; }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.handleResourceMutationResponse(resource, { data: null, errors }); this.updating = false; }, }); diff --git a/libs/shared/src/lib/components/role-summary/role-summary.component.ts b/libs/shared/src/lib/components/role-summary/role-summary.component.ts index d072a09aaf..f63d37e146 100644 --- a/libs/shared/src/lib/components/role-summary/role-summary.component.ts +++ b/libs/shared/src/lib/components/role-summary/role-summary.component.ts @@ -51,15 +51,20 @@ export class RoleSummaryComponent implements OnInit { id: this.id, }, }) - .subscribe(({ data, loading }) => { - if (data) { - this.role = data.role; - this.breadcrumbService.setBreadcrumb( - '@role', - this.role.title as string - ); - } - this.loading = loading; + .subscribe({ + next: ({ data, loading }) => { + if (data) { + this.role = data.role; + this.breadcrumbService.setBreadcrumb( + '@role', + this.role.title as string + ); + } + this.loading = loading; + }, + error: () => { + this.loading = false; + }, }); } @@ -76,11 +81,16 @@ export class RoleSummaryComponent implements OnInit { mutation: EDIT_ROLE, variables: { ...e, id: this.id }, }) - .subscribe(({ data, loading }) => { - if (data) { - this.role = data.editRole; - this.loading = loading; - } + .subscribe({ + next: ({ data, loading }) => { + if (data) { + this.role = data.editRole; + this.loading = loading; + } + }, + error: () => { + this.loading = false; + }, }); } } diff --git a/libs/shared/src/lib/components/role-summary/role-users/role-users.component.ts b/libs/shared/src/lib/components/role-summary/role-users/role-users.component.ts index 0ba2e846c5..254519ef00 100644 --- a/libs/shared/src/lib/components/role-summary/role-users/role-users.component.ts +++ b/libs/shared/src/lib/components/role-summary/role-users/role-users.component.ts @@ -73,11 +73,15 @@ export class RoleUsersComponent extends UnsubscribeComponent implements OnInit { automated: this.autoAssigned, }, }); - this.usersQuery.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { + this.usersQuery.valueChanges.pipe(takeUntil(this.destroy$)).subscribe({ + next: ({ data, loading }) => { this.updateValues(data, loading); - }); + }, + error: () => { + this.loading = false; + this.updating = false; + }, + }); } /** diff --git a/libs/shared/src/lib/components/roles/components/group-list/group-list.component.ts b/libs/shared/src/lib/components/roles/components/group-list/group-list.component.ts index c41f2e459d..a23bd0aa5f 100644 --- a/libs/shared/src/lib/components/roles/components/group-list/group-list.component.ts +++ b/libs/shared/src/lib/components/roles/components/group-list/group-list.component.ts @@ -18,6 +18,7 @@ import { } from '../../../../models/user.model'; import { SnackbarSpinnerComponent } from '../../../snackbar-spinner/snackbar-spinner.component'; import { FormBuilder } from '@angular/forms'; +import { errorMessageFormatter } from '../../../../utils/graphql/error-handler'; import { isNil } from 'lodash'; import { of } from 'rxjs'; @@ -107,11 +108,16 @@ export class GroupListComponent .query({ query: GET_GROUPS, }) - .subscribe(({ data, loading }) => { - this.groups = data.groups; - this.filteredGroups = this.groups; - // this.manualCreation = data.groups.manualCreation; - this.loading = loading; + .subscribe({ + next: ({ data, loading }) => { + this.groups = data.groups; + this.filteredGroups = this.groups; + // this.manualCreation = data.groups.manualCreation; + this.loading = loading; + }, + error: () => { + this.loading = false; + }, }); } @@ -120,8 +126,10 @@ export class GroupListComponent */ private getPermissionsConfiguration(): void { const url = '/permissions/configuration'; - this.restService.get(url).subscribe((res) => { - this.manualCreation = get(res, 'groups.local', true); + this.restService.get(url).subscribe({ + next: (res) => { + this.manualCreation = get(res, 'groups.local', true); + }, }); } @@ -159,9 +167,8 @@ export class GroupListComponent }, }) .pipe( - map(({ errors }) => { + map(() => { return { - errors, groupTile: value.title, }; }) @@ -170,27 +177,23 @@ export class GroupListComponent takeUntil(this.destroy$) ) .subscribe({ - next: ({ errors, groupTile }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotCreated', { - type: this.translate.instant('common.group.one').toLowerCase(), - error: errors ? errors[0].message : '', - }), - { error: true } - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectCreated', { - type: this.translate.instant('common.group.one'), - value: groupTile, - }) - ); - this.getGroups(); - } + next: ({ groupTile }) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectCreated', { + type: this.translate.instant('common.group.one'), + value: groupTile, + }) + ); + this.getGroups(); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotCreated', { + type: this.translate.instant('common.group.one').toLowerCase(), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } @@ -232,6 +235,7 @@ export class GroupListComponent ); }, error: () => { + this.loadingFetch = false; snackBarSpinner.instance.message = this.translate.instant( 'common.notifications.groups.error' ); @@ -287,29 +291,22 @@ export class GroupListComponent .subscribe({ next: (res) => { if (res) { - if (res.errors) { - this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.objectNotDeleted', - { - value: item.title, - error: res.errors ? res.errors[0].message : '', - } - ), - { error: true } - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectDeleted', { - value: item.title, - }) - ); - } + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectDeleted', { + value: item.title, + }) + ); this.getGroups(); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotDeleted', { + value: item.title, + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } diff --git a/libs/shared/src/lib/components/roles/components/role-list/role-list.component.ts b/libs/shared/src/lib/components/roles/components/role-list/role-list.component.ts index a968847364..1d7617452a 100644 --- a/libs/shared/src/lib/components/roles/components/role-list/role-list.component.ts +++ b/libs/shared/src/lib/components/roles/components/role-list/role-list.component.ts @@ -18,6 +18,7 @@ import { UnsubscribeComponent } from '../../../utils/unsubscribe/unsubscribe.com import { filter, map, switchMap, takeUntil } from 'rxjs/operators'; import { SnackbarService } from '@oort-front/ui'; import { FormBuilder } from '@angular/forms'; +import { errorMessageFormatter } from '../../../../utils/graphql/error-handler'; import { isNil } from 'lodash'; import { of } from 'rxjs'; @@ -133,10 +134,15 @@ export class RoleListComponent extends UnsubscribeComponent implements OnInit { }), }, }) - .subscribe(({ data, loading }) => { - this.roles = data.roles; - this.loading = loading; - this.filterPredicate(); + .subscribe({ + next: ({ data, loading }) => { + this.roles = data.roles; + this.loading = loading; + this.filterPredicate(); + }, + error: () => { + this.loading = false; + }, }); } @@ -165,9 +171,8 @@ export class RoleListComponent extends UnsubscribeComponent implements OnInit { }); } return currentSubscription.pipe( - map((res: any) => { + map(() => { return { - ...(!isNil(res) && { ...res }), roleTitle: value.title, }; }) @@ -177,33 +182,22 @@ export class RoleListComponent extends UnsubscribeComponent implements OnInit { ) .subscribe({ next: (res: any) => { - if (!this.inApplication) { - if (res?.errors) { - this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.objectNotCreated', - { - type: this.translate - .instant('common.role.one') - .toLowerCase(), - error: res.errors ? res.errors[0].message : '', - } - ), - { error: true } - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectCreated', { - type: this.translate.instant('common.role.one'), - value: res.roleTitle, - }) - ); - this.getRoles(); - } - } + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectCreated', { + type: this.translate.instant('common.role.one'), + value: res.roleTitle, + }) + ); + this.getRoles(); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotCreated', { + type: this.translate.instant('common.role.one').toLowerCase(), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } @@ -229,7 +223,7 @@ export class RoleListComponent extends UnsubscribeComponent implements OnInit { dialogRef.closed .pipe( filter((value: any) => !isNil(value)), - switchMap((value: any) => { + switchMap(() => { let currentSubscription!: any; if (this.inApplication) { this.applicationService.deleteRole(item); @@ -243,43 +237,27 @@ export class RoleListComponent extends UnsubscribeComponent implements OnInit { }, }); } - return currentSubscription.pipe( - map((res: any) => { - return { - ...(!isNil(res) && { ...res }), - roleTitle: value.title, - }; - }) - ); + return currentSubscription; }), takeUntil(this.destroy$) ) .subscribe({ - next: (res: any) => { - if (!this.inApplication) { - if (res?.errors) { - this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.objectNotDeleted', - { - value: item.title, - error: res.errors ? res.errors[0].message : '', - } - ), - { error: true } - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectDeleted', { - value: item.title, - }) - ); - this.getRoles(); - } - } + next: () => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectDeleted', { + value: item.title, + }) + ); + this.getRoles(); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotDeleted', { + value: item.title, + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } diff --git a/libs/shared/src/lib/components/ui/aggregation-builder/aggregation-builder.component.ts b/libs/shared/src/lib/components/ui/aggregation-builder/aggregation-builder.component.ts index 53ce57940b..2d421f4904 100644 --- a/libs/shared/src/lib/components/ui/aggregation-builder/aggregation-builder.component.ts +++ b/libs/shared/src/lib/components/ui/aggregation-builder/aggregation-builder.component.ts @@ -19,6 +19,7 @@ import { } from '../../../models/aggregation.model'; import { getReferenceMetadata } from '../../../utils/reference-data-metadata.util'; import { PipelineStage } from './pipeline/pipeline-stage.enum'; +import { errorMessageFormatter } from '../../../utils/graphql/error-handler'; /** * Main component of Aggregation builder. @@ -105,10 +106,12 @@ export class AggregationBuilderComponent // Fixes issue where sometimes we try to load the fields before the queries are loaded this.queryBuilder.availableQueries$ .pipe(takeUntil(this.destroy$)) - .subscribe((queryList) => { - if (queryList.length > 0) { - this.initFields(); - } + .subscribe({ + next: (queryList) => { + if (queryList.length > 0) { + this.initFields(); + } + }, }); this.stageList = this.referenceData @@ -308,13 +311,15 @@ export class AggregationBuilderComponent pipeline: this.aggregationForm.value.pipeline, first: -1, }); - - const { data: aggregationData, errors } = await firstValueFrom(query$); - if (!aggregationData || errors) { + let aggregationData!: any; + try { + const { data } = await firstValueFrom(query$); + aggregationData = data; + } catch (errors) { this.loadingAggregationRecords = false; - if (errors?.length) { - this.snackBar.openSnackBar(errors[0].message, { error: true }); - } + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); return; } this.loadingAggregationRecords = false; diff --git a/libs/shared/src/lib/components/ui/core-grid/core-grid.component.ts b/libs/shared/src/lib/components/ui/core-grid/core-grid.component.ts index 63dc9e5f43..52756be9ff 100644 --- a/libs/shared/src/lib/components/ui/core-grid/core-grid.component.ts +++ b/libs/shared/src/lib/components/ui/core-grid/core-grid.component.ts @@ -61,6 +61,7 @@ import { ConfirmService } from '../../../services/confirm/confirm.service'; import { ContextService } from '../../../services/context/context.service'; import { ResourceQueryResponse } from '../../../models/resource.model'; import { Router } from '@angular/router'; +import { errorMessageFormatter } from '../../../utils/public-api'; /** * Default file name when exporting grid data. @@ -514,17 +515,14 @@ export class CoreGridComponent } this.getRecords(); }, - error: (err: any) => { + error: (errors: any) => { this.loading = false; this.status = { error: true, message: this.translate.instant( 'components.widget.grid.errors.metaQueryFetchFailed', { - error: - err.networkError?.error?.errors - ?.map((x: any) => x.message) - .join(', ') || err, + error: errorMessageFormatter(errors), } ), }; @@ -658,19 +656,21 @@ export class CoreGridComponent filter((res: any) => !isNil(res.queryName)), takeUntil(this.destroy$) ) - .subscribe((res: any) => { - const dataItem = this.gridData.data.find((x) => x.id === item.id); - // Update data item element - Object.assign(dataItem, get(res.data, res.queryName)); - // Update data item raw value ( used by inline edition ) - dataItem._meta.raw = res.editedData; - item.saved = false; - const index = this.updatedItems.findIndex((x) => x.id === item.id); - this.updatedItems.splice(index, 1, { - id: item.id, - ...res.editedData, - }); - this.loadItems(); + .subscribe({ + next: (res: any) => { + const dataItem = this.gridData.data.find((x) => x.id === item.id); + // Update data item element + Object.assign(dataItem, get(res.data, res.queryName)); + // Update data item raw value ( used by inline edition ) + dataItem._meta.raw = res.editedData; + item.saved = false; + const index = this.updatedItems.findIndex((x) => x.id === item.id); + this.updatedItems.splice(index, 1, { + id: item.id, + ...res.editedData, + }); + this.loadItems(); + }, }); } @@ -850,16 +850,13 @@ export class CoreGridComponent this.getTemporaryRecords(); } }, - error: (err: any) => { + error: (errors: any) => { this.status = { error: true, message: this.translate.instant( 'components.widget.grid.errors.queryFetchFailed', { - error: - err.networkError?.error?.errors - ?.map((x: any) => x.message) - .join(', ') || err, + error: errorMessageFormatter(errors), } ), }; @@ -1245,9 +1242,11 @@ export class CoreGridComponent }), takeUntil(this.destroy$) ) - .subscribe(() => { - this.reloadData(); - this.layoutService.setRightSidenav(null); + .subscribe({ + next: () => { + this.reloadData(); + this.layoutService.setRightSidenav(null); + }, }); } @@ -1371,22 +1370,18 @@ export class CoreGridComponent takeUntil(this.destroy$) ) .subscribe({ - next: ({ errors }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.dataNotRecovered'), - { error: true } - ); - } else { - this.reloadData(); - this.layoutService.setRightSidenav(null); - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.dataRecovered') - ); - } + next: () => { + this.reloadData(); + this.layoutService.setRightSidenav(null); + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.dataRecovered') + ); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: () => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.dataNotRecovered'), + { error: true } + ); }, }); } @@ -1499,7 +1494,12 @@ export class CoreGridComponent }) ) .pipe(takeUntil(merge(this.cancelRefresh$, this.destroy$))) - .subscribe(() => (this.loading = false)); + .subscribe({ + next: () => (this.loading = false), + error: () => { + this.loading = false; + }, + }); } // === FILTERING === diff --git a/libs/shared/src/lib/components/ui/map/map.component.ts b/libs/shared/src/lib/components/ui/map/map.component.ts index be382387c2..329720d5a0 100644 --- a/libs/shared/src/lib/components/ui/map/map.component.ts +++ b/libs/shared/src/lib/components/ui/map/map.component.ts @@ -1100,32 +1100,34 @@ export class MapComponent this.resetLayers(this.layers.filter((x) => x.shouldRefresh)); from(this.getLayers(layersToGet ?? [], false)) .pipe(takeUntil(merge(this.cancelRefresh$, this.destroy$))) - .subscribe((res) => { - this.overlaysTree = [res.layers]; - - flatMapDeep(this.overlaysTree.flat(), flattenOverlaysTree).forEach( - (x) => { - if (x.layer) { - const id = (x.layer as any).id; - if (!isNil(shouldDisplayStatuses[id])) { - (x.layer as any).shouldDisplay = shouldDisplayStatuses[id]; - if (shouldDisplayStatuses[id]) { + .subscribe({ + next: (res) => { + this.overlaysTree = [res.layers]; + + flatMapDeep(this.overlaysTree.flat(), flattenOverlaysTree).forEach( + (x) => { + if (x.layer) { + const id = (x.layer as any).id; + if (!isNil(shouldDisplayStatuses[id])) { + (x.layer as any).shouldDisplay = shouldDisplayStatuses[id]; + if (shouldDisplayStatuses[id]) { + this.map.addLayer(x.layer); + } + } else { this.map.addLayer(x.layer); } - } else { - this.map.addLayer(x.layer); } } - } - ); - - if (controls.layer) { - // update layer controls, from newly created layers - this.setLayersControl( - flatten(this.basemapTree), - flatten(this.overlaysTree) ); - } + + if (controls.layer) { + // update layer controls, from newly created layers + this.setLayersControl( + flatten(this.basemapTree), + flatten(this.overlaysTree) + ); + } + }, }); } diff --git a/libs/shared/src/lib/components/user-summary/user-details/user-details.component.ts b/libs/shared/src/lib/components/user-summary/user-details/user-details.component.ts index 6d81e42726..3f2cff3dcb 100644 --- a/libs/shared/src/lib/components/user-summary/user-details/user-details.component.ts +++ b/libs/shared/src/lib/components/user-summary/user-details/user-details.component.ts @@ -93,23 +93,29 @@ export class UserDetailsComponent implements OnInit { ); }) ) - .subscribe(({ attributes, manualCreation }) => { - this.form.addControl( - 'attributes', - this.fb.group( - attributes.reduce( - (group: any, attribute: any) => ({ - ...group, - [attribute.value]: this.fb.control({ - value: get(this.user, `attributes.${attribute.value}`, null), - disabled: !manualCreation, + .subscribe({ + next: ({ attributes, manualCreation }) => { + this.form.addControl( + 'attributes', + this.fb.group( + attributes.reduce( + (group: any, attribute: any) => ({ + ...group, + [attribute.value]: this.fb.control({ + value: get( + this.user, + `attributes.${attribute.value}`, + null + ), + disabled: !manualCreation, + }), }), - }), - {} + {} + ) ) - ) - ); - this.attributes = attributes; + ); + this.attributes = attributes; + }, }); } } diff --git a/libs/shared/src/lib/components/user-summary/user-roles/user-app-roles/user-app-roles.component.ts b/libs/shared/src/lib/components/user-summary/user-roles/user-app-roles/user-app-roles.component.ts index af1df657ea..6b4a7a0069 100644 --- a/libs/shared/src/lib/components/user-summary/user-roles/user-app-roles/user-app-roles.component.ts +++ b/libs/shared/src/lib/components/user-summary/user-roles/user-app-roles/user-app-roles.component.ts @@ -11,6 +11,7 @@ import { GET_APPLICATIONS, GET_ROLES } from '../../graphql/queries'; import { UnsubscribeComponent } from '../../../utils/unsubscribe/unsubscribe.component'; import { takeUntil } from 'rxjs/operators'; import { SnackbarService } from '@oort-front/ui'; +import { errorMessageFormatter } from '../../../../utils/public-api'; /** Roles tab for the user summary */ @Component({ @@ -102,8 +103,10 @@ export class UserAppRolesComponent this.applicationsQuery.valueChanges .pipe(takeUntil(this.destroy$)) .subscribe({ - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); }, }); } @@ -160,8 +163,11 @@ export class UserAppRolesComponent ); this.loading = loading; }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); + this.loading = false; }, }); } diff --git a/libs/shared/src/lib/components/user-summary/user-roles/user-back-roles/user-back-roles.component.ts b/libs/shared/src/lib/components/user-summary/user-roles/user-back-roles/user-back-roles.component.ts index 7ac178b98a..a303c669ea 100644 --- a/libs/shared/src/lib/components/user-summary/user-roles/user-back-roles/user-back-roles.component.ts +++ b/libs/shared/src/lib/components/user-summary/user-roles/user-back-roles/user-back-roles.component.ts @@ -5,6 +5,7 @@ import { get } from 'lodash'; import { Role, RolesQueryResponse, User } from '../../../../models/user.model'; import { GET_ROLES } from '../../graphql/queries'; import { SnackbarService } from '@oort-front/ui'; +import { errorMessageFormatter } from '../../../../utils/public-api'; import { takeUntil } from 'rxjs'; import { UnsubscribeComponent } from '../../../utils/unsubscribe/unsubscribe.component'; @@ -71,8 +72,11 @@ export class UserBackRolesComponent } this.loading = loading; }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); + this.loading = false; }, }); } diff --git a/libs/shared/src/lib/components/user-summary/user-roles/user-groups/user-groups.component.ts b/libs/shared/src/lib/components/user-summary/user-roles/user-groups/user-groups.component.ts index d359ee1755..22dc0f856f 100644 --- a/libs/shared/src/lib/components/user-summary/user-roles/user-groups/user-groups.component.ts +++ b/libs/shared/src/lib/components/user-summary/user-roles/user-groups/user-groups.component.ts @@ -9,6 +9,7 @@ import { } from '../../../../models/user.model'; import { GET_GROUPS } from '../../graphql/queries'; import { SnackbarService } from '@oort-front/ui'; +import { errorMessageFormatter } from '../../../../utils/public-api'; import { UnsubscribeComponent } from '../../../utils/unsubscribe/unsubscribe.component'; import { takeUntil } from 'rxjs'; @@ -78,8 +79,11 @@ export class UserGroupsComponent } this.loading = loading; }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); + this.loading = false; }, }); } diff --git a/libs/shared/src/lib/components/user-summary/user-summary.component.ts b/libs/shared/src/lib/components/user-summary/user-summary.component.ts index fb34f76665..119afbb09d 100644 --- a/libs/shared/src/lib/components/user-summary/user-summary.component.ts +++ b/libs/shared/src/lib/components/user-summary/user-summary.component.ts @@ -11,6 +11,7 @@ import { EDIT_USER_PROFILE, EDIT_USER_ROLES } from './graphql/mutations'; import { GET_USER } from './graphql/queries'; import { BreadcrumbService } from '../../services/breadcrumb/breadcrumb.service'; import { SnackbarService } from '@oort-front/ui'; +import { errorMessageFormatter } from '../../utils/graphql/error-handler'; /** * User Summary shared component. @@ -75,8 +76,11 @@ export class UserSummaryComponent implements OnInit { } this.loading = loading; }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); + this.loading = false; }, }); } @@ -103,8 +107,11 @@ export class UserSummaryComponent implements OnInit { this.loading = loading; } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); + this.loading = false; }, }); } @@ -140,8 +147,11 @@ export class UserSummaryComponent implements OnInit { this.loading = loading; } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); + this.loading = false; }, }); } diff --git a/libs/shared/src/lib/components/users/invite-users-modal/invite-users-modal.component.ts b/libs/shared/src/lib/components/users/invite-users-modal/invite-users-modal.component.ts index a367122234..1b48e72a78 100644 --- a/libs/shared/src/lib/components/users/invite-users-modal/invite-users-modal.component.ts +++ b/libs/shared/src/lib/components/users/invite-users-modal/invite-users-modal.component.ts @@ -20,6 +20,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { UploadsModule } from '@progress/kendo-angular-upload'; import { ButtonModule as uiButtonModule, TextareaModule } from '@oort-front/ui'; import { DialogModule } from '@oort-front/ui'; +import { isNil } from 'lodash'; /** Model fot the input data */ interface DialogData { @@ -148,10 +149,7 @@ export class InviteUsersModalComponent extends UnsubscribeComponent { this.gridData.data = this.gridData.data.concat(res); }, error: (err) => { - if (err.status === 400) { - this.snackBar.openSnackBar(err.error, { error: true }); - this.resetFileInput(); - } else { + if (isNil(err.status)) { this.snackBar.openSnackBar( this.translate.instant( 'models.user.notifications.userImportFail' @@ -160,8 +158,8 @@ export class InviteUsersModalComponent extends UnsubscribeComponent { error: true, } ); - this.resetFileInput(); } + this.resetFileInput(); }, }); } else { diff --git a/libs/shared/src/lib/components/widgets/chart-settings/tab-filters/tab-filters.component.ts b/libs/shared/src/lib/components/widgets/chart-settings/tab-filters/tab-filters.component.ts index 1baa91d13d..2243581a71 100644 --- a/libs/shared/src/lib/components/widgets/chart-settings/tab-filters/tab-filters.component.ts +++ b/libs/shared/src/lib/components/widgets/chart-settings/tab-filters/tab-filters.component.ts @@ -108,9 +108,11 @@ export class TabFiltersComponent implements OnInit { id: resourceID, }, }) - .subscribe((res) => { - this.resource = res.data.resource; - this.filterFields = this.resource?.metadata ?? []; + .subscribe({ + next: (res) => { + this.resource = res.data.resource; + this.filterFields = this.resource?.metadata ?? []; + }, }); } else if (referenceDataID) { this.apollo @@ -120,9 +122,11 @@ export class TabFiltersComponent implements OnInit { id: referenceDataID, }, }) - .subscribe((res) => { - this.referenceData = res.data.referenceData; - this.filterFields = getReferenceMetadata(this.referenceData); + .subscribe({ + next: (res) => { + this.referenceData = res.data.referenceData; + this.filterFields = getReferenceMetadata(this.referenceData); + }, }); } } diff --git a/libs/shared/src/lib/components/widgets/chart-settings/tab-main/tab-main.component.ts b/libs/shared/src/lib/components/widgets/chart-settings/tab-main/tab-main.component.ts index ee137d8d96..19b2366389 100644 --- a/libs/shared/src/lib/components/widgets/chart-settings/tab-main/tab-main.component.ts +++ b/libs/shared/src/lib/components/widgets/chart-settings/tab-main/tab-main.component.ts @@ -119,17 +119,22 @@ export class TabMainComponent extends UnsubscribeComponent implements OnInit { aggregationIds: aggregationId ? [aggregationId] : null, }, }) - .subscribe(({ data }) => { - this.resource = data.resource; - if (aggregationId && this.resource.aggregations?.edges[0]) { - this.aggregation = this.resource.aggregations.edges[0].node; - this.availableSeriesFields = - this.aggregationBuilder.getAvailableSeriesFields(this.aggregation, { - resource: this.resource, - }); - } else { - this.availableSeriesFields = []; - } + .subscribe({ + next: ({ data }) => { + this.resource = data.resource; + if (aggregationId && this.resource.aggregations?.edges[0]) { + this.aggregation = this.resource.aggregations.edges[0].node; + this.availableSeriesFields = + this.aggregationBuilder.getAvailableSeriesFields( + this.aggregation, + { + resource: this.resource, + } + ); + } else { + this.availableSeriesFields = []; + } + }, }); } @@ -148,17 +153,22 @@ export class TabMainComponent extends UnsubscribeComponent implements OnInit { aggregationIds: aggregationId ? [aggregationId] : null, }, }) - .subscribe(({ data }) => { - this.referenceData = data.referenceData; - if (aggregationId && this.referenceData.aggregations?.edges[0]) { - this.aggregation = this.referenceData.aggregations.edges[0].node; - this.availableSeriesFields = - this.aggregationBuilder.getAvailableSeriesFields(this.aggregation, { - referenceData: this.referenceData, - }); - } else { - this.availableSeriesFields = []; - } + .subscribe({ + next: ({ data }) => { + this.referenceData = data.referenceData; + if (aggregationId && this.referenceData.aggregations?.edges[0]) { + this.aggregation = this.referenceData.aggregations.edges[0].node; + this.availableSeriesFields = + this.aggregationBuilder.getAvailableSeriesFields( + this.aggregation, + { + referenceData: this.referenceData, + } + ); + } else { + this.availableSeriesFields = []; + } + }, }); } @@ -228,14 +238,16 @@ export class TabMainComponent extends UnsubscribeComponent implements OnInit { }), takeUntil(this.destroy$) ) - .subscribe(({ data }) => { - if (data?.editAggregation) { - if (this.resource) { - this.getResource(this.resource?.id as string); - } else { - this.getReferenceData(this.referenceData?.id as string); + .subscribe({ + next: ({ data }) => { + if (data?.editAggregation) { + if (this.resource) { + this.getResource(this.resource?.id as string); + } else { + this.getReferenceData(this.referenceData?.id as string); + } } - } + }, }); } diff --git a/libs/shared/src/lib/components/widgets/chart/chart.component.ts b/libs/shared/src/lib/components/widgets/chart/chart.component.ts index 07ed7a8f9b..4bcbe052b9 100644 --- a/libs/shared/src/lib/components/widgets/chart/chart.component.ts +++ b/libs/shared/src/lib/components/widgets/chart/chart.component.ts @@ -343,12 +343,8 @@ export class ChartComponent private getData(): void { this.dataQuery .pipe(takeUntil(merge(this.cancelRefresh$, this.destroy$))) - .subscribe(({ errors, data, loading }: any) => { - if (errors) { - this.loading = false; - this.hasError = true; - this.series.next([]); - } else { + .subscribe({ + next: ({ data, loading }: any) => { this.hasError = false; const today = new Date(); this.lastUpdate = @@ -415,7 +411,12 @@ export class ChartComponent ); } this.loading = loading; - } + }, + error: () => { + this.loading = false; + this.hasError = true; + this.series.next([]); + }, }); } diff --git a/libs/shared/src/lib/components/widgets/common/template-aggregation-modal/template-aggregation-modal.component.ts b/libs/shared/src/lib/components/widgets/common/template-aggregation-modal/template-aggregation-modal.component.ts index b0f62608d4..f39c4e4f2f 100644 --- a/libs/shared/src/lib/components/widgets/common/template-aggregation-modal/template-aggregation-modal.component.ts +++ b/libs/shared/src/lib/components/widgets/common/template-aggregation-modal/template-aggregation-modal.component.ts @@ -164,12 +164,14 @@ export class TemplateAggregationModalComponent aggregationIds: aggregationId ? [aggregationId] : null, }, }) - .subscribe(({ data }) => { - this.resource = data.resource; - if (aggregationId && this.resource.aggregations?.edges[0]) { - this.aggregation = this.resource.aggregations.edges[0].node; - this.form.controls.name.setValue(this.aggregation.name as string); - } + .subscribe({ + next: ({ data }) => { + this.resource = data.resource; + if (aggregationId && this.resource.aggregations?.edges[0]) { + this.aggregation = this.resource.aggregations.edges[0].node; + this.form.controls.name.setValue(this.aggregation.name as string); + } + }, }); } @@ -188,12 +190,14 @@ export class TemplateAggregationModalComponent aggregationIds: aggregationId ? [aggregationId] : null, }, }) - .subscribe(({ data }) => { - this.referenceData = data.referenceData; - if (aggregationId && this.referenceData.aggregations?.edges[0]) { - this.aggregation = this.referenceData.aggregations.edges[0].node; - this.form.controls.name.setValue(this.aggregation.name as string); - } + .subscribe({ + next: ({ data }) => { + this.referenceData = data.referenceData; + if (aggregationId && this.referenceData.aggregations?.edges[0]) { + this.aggregation = this.referenceData.aggregations.edges[0].node; + this.form.controls.name.setValue(this.aggregation.name as string); + } + }, }); } @@ -255,14 +259,16 @@ export class TemplateAggregationModalComponent }), takeUntil(this.destroy$) ) - .subscribe(({ data }) => { - if (data?.editAggregation) { - if (this.resource) { - this.getResource(this.resource?.id as string); - } else { - this.getReferenceData(this.referenceData?.id as string); + .subscribe({ + next: ({ data }) => { + if (data?.editAggregation) { + if (this.resource) { + this.getResource(this.resource?.id as string); + } else { + this.getReferenceData(this.referenceData?.id as string); + } } - } + }, }); } } diff --git a/libs/shared/src/lib/components/widgets/common/template-aggregations/template-aggregations.component.ts b/libs/shared/src/lib/components/widgets/common/template-aggregations/template-aggregations.component.ts index 05d20bdf8d..8202ad3bd3 100644 --- a/libs/shared/src/lib/components/widgets/common/template-aggregations/template-aggregations.component.ts +++ b/libs/shared/src/lib/components/widgets/common/template-aggregations/template-aggregations.component.ts @@ -26,6 +26,7 @@ import { AggregationDataQueryResponse, ReferenceDataAggregationQueryResponse, } from '../../../../models/aggregation.model'; +import { errorMessageFormatter } from '../../../../utils/graphql/error-handler'; /** * Template aggregations component. @@ -187,13 +188,15 @@ export class TemplateAggregationsComponent : undefined, first: -1, }); - - const { data: aggregationData, errors } = await firstValueFrom(query$); - if (!aggregationData || errors) { + let aggregationData!: any; + try { + const { data } = await firstValueFrom(query$); + aggregationData = data; + } catch (errors) { this.loadingAggregationRecords = false; - if (errors?.length) { - this.snackBar.openSnackBar(errors[0].message, { error: true }); - } + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); return; } this.loadingAggregationRecords = false; diff --git a/libs/shared/src/lib/components/widgets/editor-settings/editor-settings.component.ts b/libs/shared/src/lib/components/widgets/editor-settings/editor-settings.component.ts index 8956975834..d17b09523c 100644 --- a/libs/shared/src/lib/components/widgets/editor-settings/editor-settings.component.ts +++ b/libs/shared/src/lib/components/widgets/editor-settings/editor-settings.component.ts @@ -209,17 +209,22 @@ export class EditorSettingsComponent layout: layout ? [layout] : undefined, }, }) - .subscribe(({ data }) => { - if (data) { - this.resource = data.resource; - if (layout) { - this.layout = data.resource.layouts?.edges[0]?.node || null; - } else { - this.layout = null; + .subscribe({ + next: ({ data }) => { + if (data) { + this.resource = data.resource; + if (layout) { + this.layout = data.resource.layouts?.edges[0]?.node || null; + } else { + this.layout = null; + } + this.updateFields(); } - this.updateFields(); - } - this.loading = false; + this.loading = false; + }, + error: () => { + this.loading = false; + }, }); } @@ -237,12 +242,17 @@ export class EditorSettingsComponent id: referenceData, }, }) - .subscribe(({ data }) => { - if (data) { - this.referenceData = data.referenceData; - this.updateFields(); - } - this.loading = false; + .subscribe({ + next: ({ data }) => { + if (data) { + this.referenceData = data.referenceData; + this.updateFields(); + } + this.loading = false; + }, + error: () => { + this.loading = false; + }, }); } diff --git a/libs/shared/src/lib/components/widgets/editor-settings/record-selection-tab/record-selection-tab.component.ts b/libs/shared/src/lib/components/widgets/editor-settings/record-selection-tab/record-selection-tab.component.ts index 200781941b..4a848906bf 100644 --- a/libs/shared/src/lib/components/widgets/editor-settings/record-selection-tab/record-selection-tab.component.ts +++ b/libs/shared/src/lib/components/widgets/editor-settings/record-selection-tab/record-selection-tab.component.ts @@ -127,12 +127,14 @@ export class RecordSelectionTabComponent }), takeUntil(this.destroy$) ) - .subscribe(() => { - if (this.form.get('layout')) { - this.form - .get('layout') - ?.setValue(this.form.get('layout')?.value || null); - } + .subscribe({ + next: () => { + if (this.form.get('layout')) { + this.form + .get('layout') + ?.setValue(this.form.get('layout')?.value || null); + } + }, }); } diff --git a/libs/shared/src/lib/components/widgets/editor/editor.component.ts b/libs/shared/src/lib/components/widgets/editor/editor.component.ts index 6722764306..d60d9c3f75 100644 --- a/libs/shared/src/lib/components/widgets/editor/editor.component.ts +++ b/libs/shared/src/lib/components/widgets/editor/editor.component.ts @@ -314,23 +314,25 @@ export class EditorComponent ]) ) .pipe(takeUntil(this.cancelRefresh$)) - .subscribe(() => { - this.formattedStyle = this.dataTemplateService.renderStyle( - this.settings.wholeCardStyles || false, - this.fieldsValue, - this.styles - ); - this.formattedHtml = this.dataTemplateService.renderHtml( - this.settings.text, - { - data: this.fieldsValue, - aggregation: this.aggregations, - fields: this.fields, - styles: this.styles, - } - ); - this.loading = false; - callback(); + .subscribe({ + next: () => { + this.formattedStyle = this.dataTemplateService.renderStyle( + this.settings.wholeCardStyles || false, + this.fieldsValue, + this.styles + ); + this.formattedHtml = this.dataTemplateService.renderHtml( + this.settings.text, + { + data: this.fieldsValue, + aggregation: this.aggregations, + fields: this.fields, + styles: this.styles, + } + ); + this.loading = false; + callback(); + }, }); } else if (this.settings.element && this.settings.referenceData) { from( @@ -366,32 +368,36 @@ export class EditorComponent ]) ) .pipe(takeUntil(this.cancelRefresh$)) - .subscribe(() => { - this.formattedHtml = this.dataTemplateService.renderHtml( - this.settings.text, - { - data: this.fieldsValue, - aggregation: this.aggregations, - fields: this.fields, - } - ); - this.loading = false; - callback(); + .subscribe({ + next: () => { + this.formattedHtml = this.dataTemplateService.renderHtml( + this.settings.text, + { + data: this.fieldsValue, + aggregation: this.aggregations, + fields: this.fields, + } + ); + this.loading = false; + callback(); + }, }); } else { from(Promise.all([this.getAggregationsData()])) .pipe(takeUntil(this.cancelRefresh$)) - .subscribe(() => { - this.formattedHtml = this.dataTemplateService.renderHtml( - this.settings.text, - { - data: this.fieldsValue, - aggregation: this.aggregations, - fields: this.fields, - } - ); - this.loading = false; - callback(); + .subscribe({ + next: () => { + this.formattedHtml = this.dataTemplateService.renderHtml( + this.settings.text, + { + data: this.fieldsValue, + aggregation: this.aggregations, + fields: this.fields, + } + ); + this.loading = false; + callback(); + }, }); } } diff --git a/libs/shared/src/lib/components/widgets/grid-settings/grid-settings.component.ts b/libs/shared/src/lib/components/widgets/grid-settings/grid-settings.component.ts index 14aed383e7..96a9a08e5a 100644 --- a/libs/shared/src/lib/components/widgets/grid-settings/grid-settings.component.ts +++ b/libs/shared/src/lib/components/widgets/grid-settings/grid-settings.component.ts @@ -280,8 +280,10 @@ export class GridSettingsComponent }), takeUntil(this.destroy$) ) - .subscribe(({ data }) => { - this.channels = data.channels; + .subscribe({ + next: ({ data }) => { + this.channels = data.channels; + }, }); } } @@ -306,8 +308,8 @@ export class GridSettingsComponent firstAggregations: aggregationIds?.length || 10, }, }) - .subscribe(({ data }) => { - if (data) { + .subscribe({ + next: ({ data }) => { this.resource = data.resource; this.relatedForms = data.resource.relatedForms || []; this.templates = data.resource.forms || []; @@ -320,12 +322,13 @@ export class GridSettingsComponent this.resource.queryName as string ); } - } else { + }, + error: () => { this.relatedForms = []; this.templates = []; this.resource = null; this.fields = []; - } + }, }); } else { this.relatedForms = []; @@ -357,15 +360,17 @@ export class GridSettingsComponent resource: this.resource.id, aggregation: aggregationId || '', }) - .subscribe(({ data }: any) => { - if (data.recordsAggregation) { - this.fields = data.recordsAggregation.items[0] - ? Object.keys(data.recordsAggregation.items[0]).map((f) => ({ - name: f, - editor: 'text', - })) - : []; - } + .subscribe({ + next: ({ data }: any) => { + if (data.recordsAggregation) { + this.fields = data.recordsAggregation.items[0] + ? Object.keys(data.recordsAggregation.items[0]).map((f) => ({ + name: f, + editor: 'text', + })) + : []; + } + }, }); } } diff --git a/libs/shared/src/lib/components/widgets/grid/grid.component.ts b/libs/shared/src/lib/components/widgets/grid/grid.component.ts index e6e589b636..ba9c848774 100644 --- a/libs/shared/src/lib/components/widgets/grid/grid.component.ts +++ b/libs/shared/src/lib/components/widgets/grid/grid.component.ts @@ -186,14 +186,16 @@ export class GridWidgetComponent resource: this.settings.resource, }, }) - .subscribe((res) => { - if (res.data) { - this.canCreateRecords = get( - res, - 'data.resource.canCreateRecords', - false - ); - } + .subscribe({ + next: (res) => { + if (res.data) { + this.canCreateRecords = get( + res, + 'data.resource.canCreateRecords', + false + ); + } + }, }); if (layouts.length > 0) { @@ -623,81 +625,84 @@ export class GridWidgetComponent id: value.record, }, }) - .subscribe((getRecord) => { - const resourceField = form.fields?.find( - (field) => - field.resource && - field.resource === this.settings.resource - ); - let data = getRecord.data.record.data; - const key = resourceField.name; - if (resourceField.type === 'resource') { - data = { ...data, [key]: selectedRecords[0] }; - } else { - if (data[key]) { - data = { - ...data, - [key]: data[key].concat(selectedRecords), - }; + .subscribe({ + next: (getRecord) => { + const resourceField = form.fields?.find( + (field) => + field.resource && + field.resource === this.settings.resource + ); + let data = getRecord.data.record.data; + const key = resourceField.name; + if (resourceField.type === 'resource') { + data = { ...data, [key]: selectedRecords[0] }; } else { - data = { ...data, [key]: selectedRecords }; - } - } - this.apollo - .mutate({ - mutation: EDIT_RECORD, - variables: { - id: value.record, - template: targetForm, - data, - }, - }) - .subscribe(async (editRecord) => { - if (editRecord.errors) { - this.snackBar.openSnackBar( - this.translate.instant( - 'models.record.notifications.rowsNotAdded' - ), - { error: true } - ); - resolve(false); + if (data[key]) { + data = { + ...data, + [key]: data[key].concat(selectedRecords), + }; } else { - if (editRecord.data) { - const record = editRecord.data.editRecord; - if (record) { - this.snackBar.openSnackBar( - this.translate.instant( - 'models.record.notifications.rowsAdded', + data = { ...data, [key]: selectedRecords }; + } + } + this.apollo + .mutate({ + mutation: EDIT_RECORD, + variables: { + id: value.record, + template: targetForm, + data, + }, + }) + .subscribe({ + next: async (editRecord) => { + if (editRecord.data) { + const record = editRecord.data.editRecord; + if (record) { + this.snackBar.openSnackBar( + this.translate.instant( + 'models.record.notifications.rowsAdded', + { + field: record.data[targetFormField], + length: selectedRecords.length, + value: key, + } + ) + ); + const { FormModalComponent } = await import( + '../../form-modal/form-modal.component' + ); + const dialogRef2 = this.dialog.open( + FormModalComponent, { - field: record.data[targetFormField], - length: selectedRecords.length, - value: key, + disableClose: true, + data: { + recordId: record.id, + template: targetForm, + }, + autoFocus: false, } - ) - ); - const { FormModalComponent } = await import( - '../../form-modal/form-modal.component' - ); - const dialogRef2 = this.dialog.open( - FormModalComponent, - { - disableClose: true, - data: { - recordId: record.id, - template: targetForm, - }, - autoFocus: false, - } - ); - dialogRef2.closed - .pipe(takeUntil(this.destroy$)) - .subscribe(() => resolve(true)); - } else { - resolve(false); + ); + dialogRef2.closed + .pipe(takeUntil(this.destroy$)) + .subscribe(() => resolve(true)); + } else { + resolve(false); + } } - } - } - }); + }, + error: () => { + this.snackBar.openSnackBar( + this.translate.instant( + 'models.record.notifications.rowsNotAdded' + ), + { error: true } + ); + resolve(false); + }, + }); + }, }); } else { resolve(false); diff --git a/libs/shared/src/lib/components/widgets/map-settings/edit-layer-modal/edit-layer-modal.component.ts b/libs/shared/src/lib/components/widgets/map-settings/edit-layer-modal/edit-layer-modal.component.ts index 821090ff3b..1c3fd217ac 100644 --- a/libs/shared/src/lib/components/widgets/map-settings/edit-layer-modal/edit-layer-modal.component.ts +++ b/libs/shared/src/lib/components/widgets/map-settings/edit-layer-modal/edit-layer-modal.component.ts @@ -528,29 +528,44 @@ export class EditLayerModalComponent aggregation: aggregationID ? [aggregationID] : [], }, }) - .subscribe(({ data }) => { - this.resource = data.resource; - // Update fields - if (layoutID) { - this.layout = get(data, 'resource.layouts.edges[0].node', null); - this.fields.next(this.mapLayersService.getQueryFields(this.layout)); - } else { - if (aggregationID) { - this.aggregation = get( - data, - 'resource.aggregations.edges[0].node', - null - ); + .subscribe({ + next: ({ data }) => { + this.resource = data.resource; + // Update fields + if (layoutID) { + this.layout = get(data, 'resource.layouts.edges[0].node', null); this.fields.next( - this.aggregation - ? this.mapLayersService.getAggregationFields( - data.resource.queryName ?? '', - this.aggregation - ) - : [] + this.mapLayersService.getQueryFields(this.layout) ); + } else { + if (aggregationID) { + this.aggregation = get( + data, + 'resource.aggregations.edges[0].node', + null + ); + this.fields.next( + this.mapLayersService.getQueryFields(this.layout) + ); + } else { + if (aggregationID) { + this.aggregation = get( + data, + 'resource.aggregations.edges[0].node', + null + ); + this.fields.next( + this.aggregation + ? this.mapLayersService.getAggregationFields( + data.resource.queryName ?? '', + this.aggregation + ) + : [] + ); + } + } } - } + }, }); } } @@ -572,27 +587,29 @@ export class EditLayerModalComponent aggregation: aggregationID ? [aggregationID] : [], }, }) - .subscribe(({ data }) => { - this.referenceData = data.referenceData; - if (aggregationID) { - this.aggregation = get( - data, - 'referenceData.aggregations.edges[0].node', - null - ); - this.fields.next( - this.aggregation - ? this.mapLayersService.getAggregationFields( - data.referenceData.graphQLTypeName ?? '', - this.aggregation - ) - : [] - ); - } else { - this.fields.next( - this.getFieldsFromRefData(this.referenceData?.fields || []) - ); - } + .subscribe({ + next: ({ data }) => { + this.referenceData = data.referenceData; + if (aggregationID) { + this.aggregation = get( + data, + 'referenceData.aggregations.edges[0].node', + null + ); + this.fields.next( + this.aggregation + ? this.mapLayersService.getAggregationFields( + data.referenceData.graphQLTypeName ?? '', + this.aggregation + ) + : [] + ); + } else { + this.fields.next( + this.getFieldsFromRefData(this.referenceData?.fields || []) + ); + } + }, }); } } diff --git a/libs/shared/src/lib/components/widgets/map-settings/edit-layer-modal/layer-datasource/layer-datasource.component.ts b/libs/shared/src/lib/components/widgets/map-settings/edit-layer-modal/layer-datasource/layer-datasource.component.ts index 6f2dfe8f35..45da5b8027 100644 --- a/libs/shared/src/lib/components/widgets/map-settings/edit-layer-modal/layer-datasource/layer-datasource.component.ts +++ b/libs/shared/src/lib/components/widgets/map-settings/edit-layer-modal/layer-datasource/layer-datasource.component.ts @@ -142,8 +142,10 @@ export class LayerDatasourceComponent extends UnsubscribeComponent { }), takeUntil(this.destroy$) ) - .subscribe(() => { - this.formGroup.get('layout')?.setValue(this.formGroup.value.layout); + .subscribe({ + next: () => { + this.formGroup.get('layout')?.setValue(this.formGroup.value.layout); + }, }); } @@ -174,10 +176,12 @@ export class LayerDatasourceComponent extends UnsubscribeComponent { }), takeUntil(this.destroy$) ) - .subscribe(() => { - this.formGroup - .get('aggregation') - ?.setValue(this.formGroup.value.aggregation); + .subscribe({ + next: () => { + this.formGroup + .get('aggregation') + ?.setValue(this.formGroup.value.aggregation); + }, }); } diff --git a/libs/shared/src/lib/components/widgets/map-settings/map-layers/map-layers.component.ts b/libs/shared/src/lib/components/widgets/map-settings/map-layers/map-layers.component.ts index 6b2bf94b33..2134856ad5 100644 --- a/libs/shared/src/lib/components/widgets/map-settings/map-layers/map-layers.component.ts +++ b/libs/shared/src/lib/components/widgets/map-settings/map-layers/map-layers.component.ts @@ -58,9 +58,14 @@ export class MapLayersComponent extends UnsubscribeComponent implements OnInit { */ private updateLayerList(): void { const layerIds = this.control.value; - this.mapLayersService.getLayers(layerIds).subscribe((layers) => { - this.mapLayers = layers; - this.loading = false; + this.mapLayersService.getLayers(layerIds).subscribe({ + next: (layers) => { + this.mapLayers = layers; + this.loading = false; + }, + error: () => { + this.loading = false; + }, }); } @@ -112,6 +117,7 @@ export class MapLayersComponent extends UnsubscribeComponent implements OnInit { ) .subscribe({ next: (res) => { + this.loading = false; if (res) { const value = this.control.value; this.control.setValue([...value, res.id]); @@ -120,8 +126,10 @@ export class MapLayersComponent extends UnsubscribeComponent implements OnInit { this.restoreMapSettingsView(); } }, - error: (err) => console.error(err), - complete: () => (this.loading = false), + error: () => { + this.loading = false; + this.restoreMapSettingsView(); + }, }); } @@ -146,62 +154,66 @@ export class MapLayersComponent extends UnsubscribeComponent implements OnInit { * @param id id of layer to edit */ public onEditLayer(id: string) { - this.mapLayersService - .getLayerById(id) - .pipe(takeUntil(this.destroy$)) - .subscribe({ - next: async (layer) => { - const { EditLayerModalComponent } = await import( - '../edit-layer-modal/edit-layer-modal.component' - ); - if (this.mapComponent) { - this.mapComponent.resetLayers(); - this.mapComponent.layers = []; - } - const dialogRef = this.dialog.open(EditLayerModalComponent, { - disableClose: true, - autoFocus: false, - data: { - layer, - mapComponent: this.mapComponent, - mapPortal: this.mapPortal, - }, - }); - dialogRef.closed - .pipe(takeUntil(this.destroy$)) - .subscribe((value: any) => { - if (value) { - this.loading = true; - this.mapLayersService.editLayer(value).subscribe({ - next: (res) => { - if (res) { - const index = this.mapLayers.findIndex( - (layer) => layer.id === id - ); - if (index !== -1) { - this.mapLayers.splice(index, 1, { - ...res, - name: value.name, - }); - this.restoreMapSettingsView(); - } else { - // Selecting a new layer - const value = this.control.value; - this.control.setValue([...value, res.id]); - this.mapLayers.push(res); - } + this.mapLayersService.getLayerById(id).subscribe({ + next: async (layer) => { + const { EditLayerModalComponent } = await import( + '../edit-layer-modal/edit-layer-modal.component' + ); + if (this.mapComponent) { + this.mapComponent.resetLayers(); + this.mapComponent.layers = []; + } + const dialogRef = this.dialog.open(EditLayerModalComponent, { + disableClose: true, + autoFocus: false, + data: { + layer, + mapComponent: this.mapComponent, + mapPortal: this.mapPortal, + }, + }); + dialogRef.closed.pipe(takeUntil(this.destroy$)).subscribe({ + next: (value: any) => { + if (value) { + this.loading = true; + this.mapLayersService.editLayer(value).subscribe({ + next: (res) => { + this.loading = false; + if (res) { + const index = this.mapLayers.findIndex( + (layer) => layer.id === id + ); + if (index !== -1) { + this.mapLayers.splice(index, 1, { + ...res, + name: value.name, + }); + this.restoreMapSettingsView(); + } else { + // Selecting a new layer + const value = this.control.value; + this.control.setValue([...value, res.id]); + this.mapLayers.push(res); } - }, - error: (err) => console.log(err), - complete: () => (this.loading = false), - }); - } else { - this.restoreMapSettingsView(); - } - }); - }, - error: (err) => console.log(err), - }); + } + }, + error: (err) => { + this.loading = false; + this.restoreMapSettingsView(); + console.log(err); + }, + }); + } else { + this.restoreMapSettingsView(); + } + }, + error: () => { + this.restoreMapSettingsView(); + }, + }); + }, + error: (err) => console.log(err), + }); } /** diff --git a/libs/shared/src/lib/components/widgets/summary-card-settings/summary-card-general/summary-card-general.component.ts b/libs/shared/src/lib/components/widgets/summary-card-settings/summary-card-general/summary-card-general.component.ts index f834596e31..aea711f180 100644 --- a/libs/shared/src/lib/components/widgets/summary-card-settings/summary-card-general/summary-card-general.component.ts +++ b/libs/shared/src/lib/components/widgets/summary-card-settings/summary-card-general/summary-card-general.component.ts @@ -138,12 +138,14 @@ export class SummaryCardGeneralComponent extends UnsubscribeComponent { }), takeUntil(this.destroy$) ) - .subscribe(() => { - if (this.formGroup.get('card.layout')) { - this.formGroup - .get('card.layout') - ?.setValue(this.formGroup.get('card.layout')?.value || null); - } + .subscribe({ + next: () => { + if (this.formGroup.get('card.layout')) { + this.formGroup + .get('card.layout') + ?.setValue(this.formGroup.get('card.layout')?.value || null); + } + }, }); } @@ -202,12 +204,14 @@ export class SummaryCardGeneralComponent extends UnsubscribeComponent { }), takeUntil(this.destroy$) ) - .subscribe(() => { - if (this.formGroup.get('card.aggregation')) { - this.formGroup - .get('card.aggregation') - ?.setValue(this.formGroup.get('card.aggregation')?.value || null); - } + .subscribe({ + next: () => { + if (this.formGroup.get('card.aggregation')) { + this.formGroup + .get('card.aggregation') + ?.setValue(this.formGroup.get('card.aggregation')?.value || null); + } + }, }); } diff --git a/libs/shared/src/lib/components/widgets/summary-card-settings/summary-card-settings.component.ts b/libs/shared/src/lib/components/widgets/summary-card-settings/summary-card-settings.component.ts index c64cdf71c8..23343d6dfd 100644 --- a/libs/shared/src/lib/components/widgets/summary-card-settings/summary-card-settings.component.ts +++ b/libs/shared/src/lib/components/widgets/summary-card-settings/summary-card-settings.component.ts @@ -298,15 +298,8 @@ export class SummaryCardSettingsComponent aggregation: aggregationID ? [aggregationID] : undefined, }, }) - .subscribe(({ data, errors }) => { - if (errors) { - this.widgetFormGroup.get('card.resource')?.patchValue(null); - this.widgetFormGroup.get('card.layout')?.patchValue(null); - this.widgetFormGroup.get('card.aggregation')?.patchValue(null); - this.resource = null; - this.layout = null; - this.aggregation = null; - } else { + .subscribe({ + next: ({ data }) => { this.resource = data.resource; if (layoutID) { this.layout = data?.resource.layouts?.edges[0]?.node || null; @@ -327,7 +320,15 @@ export class SummaryCardSettingsComponent data?.resource.aggregations?.edges[0]?.node || null; this.getCustomAggregation(); } - } + }, + error: () => { + this.widgetFormGroup.get('card.resource')?.patchValue(null); + this.widgetFormGroup.get('card.layout')?.patchValue(null); + this.widgetFormGroup.get('card.aggregation')?.patchValue(null); + this.resource = null; + this.layout = null; + this.aggregation = null; + }, }); } @@ -344,11 +345,8 @@ export class SummaryCardSettingsComponent id, }, }) - .subscribe(({ data, errors }) => { - if (errors) { - this.widgetFormGroup.get('card.referenceData')?.patchValue(null); - this.referenceData = null; - } else { + .subscribe({ + next: ({ data }) => { this.referenceData = data.referenceData; this.fields = (this.referenceData.fields || []) .filter((field) => field && typeof field !== 'string') @@ -359,7 +357,11 @@ export class SummaryCardSettingsComponent type: field.type, }; }); - } + }, + error: () => { + this.widgetFormGroup.get('card.referenceData')?.patchValue(null); + this.referenceData = null; + }, }); } @@ -374,16 +376,18 @@ export class SummaryCardSettingsComponent resource: this.resource.id, aggregation: this.aggregation.id || '', }) - ?.subscribe(({ data }: any) => { - if (data.recordsAggregation) { - const customAggregation = data.recordsAggregation; - this.fields = customAggregation.items[0] - ? Object.keys(customAggregation.items[0]).map((f) => ({ - name: f, - editor: 'text', - })) - : []; - } + ?.subscribe({ + next: ({ data }: any) => { + if (data.recordsAggregation) { + const customAggregation = data.recordsAggregation; + this.fields = customAggregation.items[0] + ? Object.keys(customAggregation.items[0]).map((f) => ({ + name: f, + editor: 'text', + })) + : []; + } + }, }); } diff --git a/libs/shared/src/lib/components/widgets/summary-card/summary-card.component.ts b/libs/shared/src/lib/components/widgets/summary-card/summary-card.component.ts index 49fd089f4a..c9fc4cbdd3 100644 --- a/libs/shared/src/lib/components/widgets/summary-card/summary-card.component.ts +++ b/libs/shared/src/lib/components/widgets/summary-card/summary-card.component.ts @@ -466,9 +466,10 @@ export class SummaryCardComponent }) ) .pipe(takeUntil(merge(this.cancelRefresh$, this.destroy$))) - .subscribe(({ items, pageInfo }) => - this.updateReferenceDataCards(items, pageInfo) - ); + .subscribe({ + next: ({ items, pageInfo }) => + this.updateReferenceDataCards(items, pageInfo), + }); } } @@ -886,6 +887,7 @@ export class SummaryCardComponent } } } + this.loading = false; }, error: () => { this.loading = false; @@ -1013,7 +1015,7 @@ export class SummaryCardComponent }) ) .pipe(takeUntil(merge(this.cancelRefresh$, this.destroy$))) - .subscribe(() => this.updateRecordCards.bind(this)); + .subscribe({ next: () => this.updateRecordCards.bind(this) }); } } } @@ -1062,9 +1064,14 @@ export class SummaryCardComponent }) ) .pipe(takeUntil(merge(this.cancelRefresh$, this.destroy$))) - .subscribe(({ items, pageInfo }) => { - this.updateReferenceDataCards(items, pageInfo); - this.loading = false; + .subscribe({ + next: ({ items, pageInfo }) => { + this.updateReferenceDataCards(items, pageInfo); + this.loading = false; + }, + error: () => { + this.loading = false; + }, }); } } @@ -1158,7 +1165,12 @@ export class SummaryCardComponent }) ) .pipe(takeUntil(merge(this.cancelRefresh$, this.destroy$))) - .subscribe(() => (this.loading = false)); + .subscribe({ + next: () => (this.loading = false), + error: () => { + this.loading = false; + }, + }); } else if (this.useReferenceData) { if (this.refData?.pageInfo?.strategy) { this.refresh(); diff --git a/libs/shared/src/lib/interceptors/error-handler/error-handler-interceptor.service.ts b/libs/shared/src/lib/interceptors/error-handler/error-handler-interceptor.service.ts new file mode 100644 index 0000000000..02a5612515 --- /dev/null +++ b/libs/shared/src/lib/interceptors/error-handler/error-handler-interceptor.service.ts @@ -0,0 +1,64 @@ +import { Inject, Injectable } from '@angular/core'; +import { + HttpRequest, + HttpHandler, + HttpEvent, + HttpInterceptor, +} from '@angular/common/http'; +import { Observable, catchError, throwError } from 'rxjs'; +import { SnackbarService } from '@oort-front/ui'; + +/** + * Error handler interceptor service + */ +@Injectable() +export class ErrorHandlerInterceptorService implements HttpInterceptor { + /** + * Error handler interceptor service constructor + * + * @param snackbarService Snackbar service + * @param environment Current environment data + */ + constructor( + private snackbarService: SnackbarService, + @Inject('environment') private environment: any + ) {} + + /** + * Handle http request error to show a snackbar in the UI + * + * @param request Http request + * @param next Http request handler + * @returns Current request result + */ + intercept( + request: HttpRequest, + next: HttpHandler + ): Observable> { + if (request.url.includes(this.environment.apiUrl)) { + return next.handle(request).pipe( + catchError((res: any) => { + // Open default snackbar if error is not a GraphQL type + if (res.status) { + let errorMessage = `${res.statusText}: ${res.status}`; + if (Array.isArray(res.error.errors)) { + res.error.errors.forEach((error: { message: string }) => { + errorMessage = errorMessage + '\n' + error.message; + }); + } else { + errorMessage = errorMessage + '\n' + res.error; + } + errorMessage = errorMessage + '\n' + res.message; + this.snackbarService.openSnackBar(errorMessage, { + error: true, + duration: 0, + }); + } + return throwError(() => res.error.errors); + }) + ); + } else { + return next.handle(request); + } + } +} diff --git a/libs/shared/src/lib/interceptors/error-handler/error-handler-interceptor.spec.ts b/libs/shared/src/lib/interceptors/error-handler/error-handler-interceptor.spec.ts new file mode 100644 index 0000000000..d42bf7d362 --- /dev/null +++ b/libs/shared/src/lib/interceptors/error-handler/error-handler-interceptor.spec.ts @@ -0,0 +1,18 @@ +import { TestBed } from '@angular/core/testing'; + +import { ErrorHandlerInterceptorService } from './error-handler-interceptor.service'; + +describe('ErrorHandlerInterceptorService', () => { + beforeEach(() => + TestBed.configureTestingModule({ + providers: [ErrorHandlerInterceptorService], + }) + ); + + it('should be created', () => { + const interceptor: ErrorHandlerInterceptorService = TestBed.inject( + ErrorHandlerInterceptorService + ); + expect(interceptor).toBeTruthy(); + }); +}); diff --git a/libs/shared/src/lib/services/aggregation/aggregation.service.ts b/libs/shared/src/lib/services/aggregation/aggregation.service.ts index 5f01793c0a..8af09b014e 100644 --- a/libs/shared/src/lib/services/aggregation/aggregation.service.ts +++ b/libs/shared/src/lib/services/aggregation/aggregation.service.ts @@ -84,13 +84,13 @@ export class AggregationService { first: options.first, }, }) - ).then(async ({ errors, data }) => { - if (errors) { - return FALLBACK_AGGREGATIONS; - } else { + ) + .then(async ({ data }) => { return data.resource.aggregations || FALLBACK_AGGREGATIONS; - } - }); + }) + .catch(() => { + return FALLBACK_AGGREGATIONS; + }); } else { return await firstValueFrom( this.apollo.query({ @@ -101,13 +101,13 @@ export class AggregationService { first: options.first, }, }) - ).then(async ({ errors, data }) => { - if (errors) { - return FALLBACK_AGGREGATIONS; - } else { + ) + .then(async ({ data }) => { return data.referenceData.aggregations || FALLBACK_AGGREGATIONS; - } - }); + }) + .catch(() => { + return FALLBACK_AGGREGATIONS; + }); } } diff --git a/libs/shared/src/lib/services/application-notifications/application-notifications.service.ts b/libs/shared/src/lib/services/application-notifications/application-notifications.service.ts index ac4a87c36c..d94d2463a1 100644 --- a/libs/shared/src/lib/services/application-notifications/application-notifications.service.ts +++ b/libs/shared/src/lib/services/application-notifications/application-notifications.service.ts @@ -13,6 +13,7 @@ import { } from './graphql/mutations'; import { TranslateService } from '@ngx-translate/core'; import { SnackbarService } from '@oort-front/ui'; +import { errorMessageFormatter } from '../../utils/graphql/error-handler'; /** * Shared service to manage application's notifications. */ @@ -60,18 +61,8 @@ export class ApplicationNotificationsService { notification, }, }) - .subscribe((res) => { - if (res.errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotCreated', { - type: this.translate - .instant('common.customNotification.one') - .toLowerCase(), - error: res.errors ? res.errors[0].message : '', - }), - { error: true } - ); - } else { + .subscribe({ + next: (res) => { if (res.data) { this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectCreated', { @@ -80,7 +71,18 @@ export class ApplicationNotificationsService { }) ); } - } + }, + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotCreated', { + type: this.translate + .instant('common.customNotification.one') + .toLowerCase(), + error: errorMessageFormatter(errors), + }), + { error: true } + ); + }, }); } @@ -98,16 +100,8 @@ export class ApplicationNotificationsService { id, }, }) - .subscribe((res) => { - if (res.errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotDeleted', { - value: this.translate.instant('common.customNotification.one'), - error: res.errors ? res.errors[0].message : '', - }), - { error: true } - ); - } else { + .subscribe({ + next: (res) => { if (res.data) { this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectDeleted', { @@ -115,7 +109,16 @@ export class ApplicationNotificationsService { }) ); } - } + }, + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotDeleted', { + value: this.translate.instant('common.customNotification.one'), + error: errorMessageFormatter(errors), + }), + { error: true } + ); + }, }); } @@ -134,16 +137,8 @@ export class ApplicationNotificationsService { notification, }, }) - .subscribe((res) => { - if (res.errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotUpdated', { - value: this.translate.instant('common.customNotification.one'), - error: res.errors ? res.errors[0].message : '', - }), - { error: true } - ); - } else { + .subscribe({ + next: (res) => { if (res.data) { this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectUpdated', { @@ -152,7 +147,16 @@ export class ApplicationNotificationsService { }) ); } - } + }, + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotUpdated', { + value: this.translate.instant('common.customNotification.one'), + error: errorMessageFormatter(errors), + }), + { error: true } + ); + }, }); } } diff --git a/libs/shared/src/lib/services/application/application.service.ts b/libs/shared/src/lib/services/application/application.service.ts index d9e657fb04..a2922c1fdf 100644 --- a/libs/shared/src/lib/services/application/application.service.ts +++ b/libs/shared/src/lib/services/application/application.service.ts @@ -115,6 +115,7 @@ import { RestService } from '../rest/rest.service'; import { DownloadService } from '../download/download.service'; import { DOCUMENT } from '@angular/common'; import { GraphQLError } from 'graphql'; +import { errorMessageFormatter } from '../../utils/graphql/error-handler'; /** * Shared application service. Handles events of opened application. @@ -277,17 +278,19 @@ export class ApplicationService { id, }, }) - .subscribe(() => { - const snackBar = this.snackBar.openSnackBar( - this.translate.instant('models.application.notifications.updated'), - { - action: 'Reload', - duration: 0, - } - ); - snackBar.instance.actionComplete.subscribe(() => - window.location.reload() - ); + .subscribe({ + next: () => { + const snackBar = this.snackBar.openSnackBar( + this.translate.instant('models.application.notifications.updated'), + { + action: 'Reload', + duration: 0, + } + ); + snackBar.instance.actionComplete.subscribe(() => + window.location.reload() + ); + }, }); this.lockSubscription = this.apollo .subscribe({ @@ -296,16 +299,18 @@ export class ApplicationService { id, }, }) - .subscribe(({ data }) => { - if (data?.applicationUnlocked) { - const application = this.application.getValue(); - const newApplication = { - ...application, - locked: data?.applicationUnlocked?.locked, - lockedByUser: data?.applicationUnlocked?.lockedByUser, - }; - this.application.next(newApplication); - } + .subscribe({ + next: ({ data }) => { + if (data?.applicationUnlocked) { + const application = this.application.getValue(); + const newApplication = { + ...application, + locked: data?.applicationUnlocked?.locked, + lockedByUser: data?.applicationUnlocked?.lockedByUser, + }; + this.application.next(newApplication); + } + }, }); } @@ -351,17 +356,19 @@ export class ApplicationService { lock: !locked, }, }) - .subscribe(({ data }) => { - if (data?.toggleApplicationLock) { - if (!data.toggleApplicationLock.lockedByUser) { - const newApplication = { - ...application, - locked: data?.toggleApplicationLock?.locked, - lockedByUser: data?.toggleApplicationLock.lockedByUser, - }; - this.application.next(newApplication); + .subscribe({ + next: ({ data }) => { + if (data?.toggleApplicationLock) { + if (!data.toggleApplicationLock.lockedByUser) { + const newApplication = { + ...application, + locked: data?.toggleApplicationLock?.locked, + lockedByUser: data?.toggleApplicationLock.lockedByUser, + }; + this.application.next(newApplication); + } } - } + }, }); } @@ -385,13 +392,13 @@ export class ApplicationService { status: value.status, }, }) - .subscribe(({ errors, data }) => { - this.handleEditionMutationResponse( - errors, - this.translate.instant('common.application.one'), - value.name - ); - if (!errors && data && data.editApplication) { + .subscribe({ + next: ({ data }) => { + this.handleEditionMutationResponse( + [], + this.translate.instant('common.application.one'), + value.name + ); if (data?.editApplication) { const newApplication = { ...application, @@ -403,7 +410,14 @@ export class ApplicationService { }; this.application.next(newApplication); } - } + }, + error: (errors) => { + this.handleEditionMutationResponse( + errors, + this.translate.instant('common.application.one'), + value.name + ); + }, }); } } @@ -425,13 +439,13 @@ export class ApplicationService { }, }) .subscribe({ - next: ({ errors, data }) => { + next: ({ data }) => { this.handleEditionMutationResponse( - errors, + [], this.translate.instant('common.access'), application?.name ); - if (!errors && data?.editApplication) { + if (data?.editApplication) { const newApplication = { ...application, permissions: data.editApplication.permissions, @@ -439,8 +453,12 @@ export class ApplicationService { this.application.next(newApplication); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.handleEditionMutationResponse( + errors, + this.translate.instant('common.access'), + application?.name + ); }, }); } @@ -461,30 +479,26 @@ export class ApplicationService { }, }) .subscribe({ - next: ({ errors, data }) => { - if (errors) { + next: ({ data }) => { + if (data) { this.snackBar.openSnackBar( this.translate.instant( - 'models.application.notifications.notPublished' - ), - { error: true } + 'models.application.notifications.published', + { + value: data.editApplication.name, + } + ) ); - } else { - if (data) { - this.snackBar.openSnackBar( - this.translate.instant( - 'models.application.notifications.published', - { - value: data.editApplication.name, - } - ) - ); - this.router.navigate(['/applications']); - } + this.router.navigate(['/applications']); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: () => { + this.snackBar.openSnackBar( + this.translate.instant( + 'models.application.notifications.notPublished' + ), + { error: true } + ); }, }); } @@ -506,33 +520,36 @@ export class ApplicationService { id, }, }) - .subscribe(({ errors, data }) => { - if (data) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectDeleted', { - value: this.translate.instant('common.page.one'), - }) - ); - const app = this.application.getValue(); - if (app) { - const newApplication = { - ...app, - pages: app.pages?.filter((x) => x.id !== data?.deletePage.id), - }; - this.application.next(newApplication); - if (!stayOnPage) { - this.router.navigate([`./applications/${app.id}`]); + .subscribe({ + next: ({ data }) => { + if (data) { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectDeleted', { + value: this.translate.instant('common.page.one'), + }) + ); + const app = this.application.getValue(); + if (app) { + const newApplication = { + ...app, + pages: app.pages?.filter((x) => x.id !== data?.deletePage.id), + }; + this.application.next(newApplication); + if (!stayOnPage) { + this.router.navigate([`./applications/${app.id}`]); + } } } - } else { + }, + error: (errors) => { this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectNotDeleted', { value: this.translate.instant('common.page.one'), - error: errors ? errors[0].message : '', + error: errorMessageFormatter(errors), }), { error: true } ); - } + }, }); } } @@ -552,35 +569,38 @@ export class ApplicationService { id, }, }) - .subscribe(({ errors, data }) => { - if (data) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectRestored', { - value: this.translate.instant('common.page.one'), - }) - ); - const application = this.application.getValue(); - if (application) { - const newApplication = { - ...application, - pages: application.pages?.concat([data.restorePage]), - }; - this.application.next(newApplication); - this.router.navigate([ - data.restorePage.type === ContentType.form - ? `/applications/${application.id}/${data.restorePage.type}/${data.restorePage.id}` - : `/applications/${application.id}/${data.restorePage.type}/${data.restorePage.content}`, - ]); + .subscribe({ + next: ({ data }) => { + if (data) { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectRestored', { + value: this.translate.instant('common.page.one'), + }) + ); + const application = this.application.getValue(); + if (application) { + const newApplication = { + ...application, + pages: application.pages?.concat([data.restorePage]), + }; + this.application.next(newApplication); + this.router.navigate([ + data.restorePage.type === ContentType.form + ? `/applications/${application.id}/${data.restorePage.type}/${data.restorePage.id}` + : `/applications/${application.id}/${data.restorePage.type}/${data.restorePage.content}`, + ]); + } } - } else { + }, + error: (errors) => { this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectNotRestored', { value: this.translate.instant('common.page.one'), - error: errors ? errors[0].message : '', + error: errorMessageFormatter(errors), }), { error: true } ); - } + }, }); } } @@ -602,48 +622,44 @@ export class ApplicationService { }, }) .subscribe({ - next: ({ errors, data }) => { - if (errors) { - if (pages.length > 1) { - this.snackBar.openSnackBar( - this.translate.instant( - 'components.application.pages.notReordered.plural', - { error: errors ? errors[0].message : '' } - ), - { error: true } - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant( - 'components.application.pages.notReordered.singular', - { error: errors ? errors[0].message : '' } - ), - { error: true } - ); - } + next: ({ data }) => { + if (pages.length > 1) { + this.snackBar.openSnackBar( + this.translate.instant( + 'components.application.pages.reordered.plural' + ) + ); } else { - if (pages.length > 1) { - this.snackBar.openSnackBar( - this.translate.instant( - 'components.application.pages.reordered.plural' - ) - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant( - 'components.application.pages.reordered.singular' - ) - ); - } - - this.application.next({ - ...application, - ...{ pages: data?.editApplication.pages }, - }); + this.snackBar.openSnackBar( + this.translate.instant( + 'components.application.pages.reordered.singular' + ) + ); } + + this.application.next({ + ...application, + ...{ pages: data?.editApplication.pages }, + }); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + if (pages.length > 1) { + this.snackBar.openSnackBar( + this.translate.instant( + 'components.application.pages.notReordered.plural', + { error: errorMessageFormatter(errors) } + ), + { error: true } + ); + } else { + this.snackBar.openSnackBar( + this.translate.instant( + 'components.application.pages.notReordered.singular', + { error: errorMessageFormatter(errors) } + ), + { error: true } + ); + } }, }); } @@ -666,25 +682,34 @@ export class ApplicationService { name: page.name, }, }) - .subscribe(({ errors, data }) => { - this.handleEditionMutationResponse( - errors, - this.translate.instant('common.page.one'), - page.name - ); - if (!errors && data) { - const newApplication = { - ...application, - pages: application.pages?.map((x) => { - if (x.id === page.id) { - x = { ...x, name: page.name }; - } - return x; - }), - }; - this.application.next(newApplication); - if (callback) callback(); - } + .subscribe({ + next: ({ data }) => { + this.handleEditionMutationResponse( + [], + this.translate.instant('common.page.one'), + page.name + ); + if (data) { + const newApplication = { + ...application, + pages: application.pages?.map((x) => { + if (x.id === page.id) { + x = { ...x, name: page.name }; + } + return x; + }), + }; + this.application.next(newApplication); + if (callback) callback(); + } + }, + error: (errors) => { + this.handleEditionMutationResponse( + errors, + this.translate.instant('common.page.one'), + page.name + ); + }, }); } } @@ -707,24 +732,32 @@ export class ApplicationService { visible: page.visible, }, }) - .subscribe(({ errors, data }) => { - this.handleEditionMutationResponse( - errors, - this.translate.instant('common.page.one') - ); - if (!errors && data) { - const newApplication = { - ...application, - pages: application.pages?.map((x) => { - if (x.id === page.id) { - x = { ...x, visible: data.editPage.visible }; - } - return x; - }), - }; - this.application.next(newApplication); - if (callback) callback(); - } + .subscribe({ + next: ({ data }) => { + this.handleEditionMutationResponse( + [], + this.translate.instant('common.page.one') + ); + if (data) { + const newApplication = { + ...application, + pages: application.pages?.map((x) => { + if (x.id === page.id) { + x = { ...x, visible: data.editPage.visible }; + } + return x; + }), + }; + this.application.next(newApplication); + if (callback) callback(); + } + }, + error: (errors) => { + this.handleEditionMutationResponse( + errors, + this.translate.instant('common.page.one') + ); + }, }); } } @@ -747,24 +780,32 @@ export class ApplicationService { icon, }, }) - .subscribe(({ errors, data }) => { - this.handleEditionMutationResponse( - errors, - this.translate.instant('common.page.one') - ); - if (!errors && data) { - const newApplication = { - ...application, - pages: application.pages?.map((x) => { - if (x.id === page.id) { - x = { ...x, icon: data.editPage.icon }; - } - return x; - }), - }; - this.application.next(newApplication); - if (callback) callback(); - } + .subscribe({ + next: ({ data }) => { + this.handleEditionMutationResponse( + [], + this.translate.instant('common.page.one') + ); + if (data) { + const newApplication = { + ...application, + pages: application.pages?.map((x) => { + if (x.id === page.id) { + x = { ...x, icon: data.editPage.icon }; + } + return x; + }), + }; + this.application.next(newApplication); + if (callback) callback(); + } + }, + error: (errors) => { + this.handleEditionMutationResponse( + errors, + this.translate.instant('common.page.one') + ); + }, }); } } @@ -788,35 +829,38 @@ export class ApplicationService { structure, }, }) - .subscribe(({ errors, data }) => { - if (data?.addPage) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectCreated', { - type: this.translate.instant('common.page.one').toLowerCase(), - value: data.addPage.name, - }) - ); + .subscribe({ + next: ({ data }) => { + if (data?.addPage) { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectCreated', { + type: this.translate.instant('common.page.one').toLowerCase(), + value: data.addPage.name, + }) + ); - const content = data.addPage.content; - const newApplication = { - ...application, - pages: application.pages?.concat([data.addPage]), - }; - this.application.next(newApplication); - this.router.navigate([ - page.type === ContentType.form - ? `/applications/${application.id}/${page.type}/${data.addPage.id}` - : `/applications/${application.id}/${page.type}/${content}`, - ]); - } else { + const content = data.addPage.content; + const newApplication = { + ...application, + pages: application.pages?.concat([data.addPage]), + }; + this.application.next(newApplication); + this.router.navigate([ + page.type === ContentType.form + ? `/applications/${application.id}/${page.type}/${data.addPage.id}` + : `/applications/${application.id}/${page.type}/${content}`, + ]); + } + }, + error: (errors) => { this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectNotCreated', { type: this.translate.instant('common.page.one').toLowerCase(), - error: errors ? errors[0].message : '', + error: errorMessageFormatter(errors), }), { error: true } ); - } + }, }); } } @@ -844,16 +888,8 @@ export class ApplicationService { step: content.stepId, }, }) - .subscribe(({ errors, data }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectNotCreated', { - type: this.translate.instant('common.page.one').toLowerCase(), - error: errors ? errors[0].message : '', - }), - { error: true } - ); - } else { + .subscribe({ + next: ({ data }) => { if (data?.duplicatePage) { const newPage = data.duplicatePage; this.translate.instant('common.notifications.objectCreated', { @@ -873,7 +909,16 @@ export class ApplicationService { ]); if (callback) callback(); } - } + }, + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotCreated', { + type: this.translate.instant('common.page.one').toLowerCase(), + error: errorMessageFormatter(errors), + }), + { error: true } + ); + }, }); } @@ -894,40 +939,29 @@ export class ApplicationService { }, }) .subscribe({ - next: ({ errors, data }) => { - if (errors) { + next: ({ data }) => { + if (data) { this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.objectNotCreated', - { - type: this.translate - .instant('common.role.one') - .toLowerCase(), - error: errors ? errors[0].message : '', - } - ), - { error: true } + this.translate.instant('common.notifications.objectCreated', { + type: this.translate.instant('common.role.one').toLowerCase(), + value: role.title, + }) ); - } else { - if (data) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectCreated', { - type: this.translate - .instant('common.role.one') - .toLowerCase(), - value: role.title, - }) - ); - const newApplication = { - ...application, - roles: application.roles?.concat([data.addRole]), - }; - this.application.next(newApplication); - } + const newApplication = { + ...application, + roles: application.roles?.concat([data.addRole]), + }; + this.application.next(newApplication); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotCreated', { + type: this.translate.instant('common.role.one').toLowerCase(), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } @@ -953,13 +987,13 @@ export class ApplicationService { }, }) .subscribe({ - next: ({ errors, data }) => { + next: ({ data }) => { this.handleEditionMutationResponse( - errors, + [], this.translate.instant('common.role.one'), role.title ); - if (!errors && data) { + if (data) { const newApplication: Application = { ...application, roles: application.roles?.map((x) => { @@ -994,8 +1028,12 @@ export class ApplicationService { this.application.next(newApplication); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.handleEditionMutationResponse( + errors, + this.translate.instant('common.role.one'), + role.title + ); }, }); } @@ -1017,33 +1055,26 @@ export class ApplicationService { }, }) .subscribe({ - next: ({ errors }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.objectNotDeleted', - { - value: role.title, - error: errors ? errors[0].message : '', - } - ), - { error: true } - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectDeleted', { - value: role.title, - }) - ); - const newApplication = { - ...application, - roles: application.roles?.filter((x) => x.id !== role.id), - }; - this.application.next(newApplication); - } + next: () => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectDeleted', { + value: role.title, + }) + ); + const newApplication = { + ...application, + roles: application.roles?.filter((x) => x.id !== role.id), + }; + this.application.next(newApplication); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotDeleted', { + value: role.title, + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } @@ -1067,58 +1098,39 @@ export class ApplicationService { }, }) .subscribe({ - next: ({ errors, data }) => { - if (errors) { - if (ids.length > 1) { + next: ({ data }) => { + if (data) { + const deletedUsers = data.deleteUsersFromApplication.map( + (x) => x.id + ); + if (deletedUsers.length > 1) { this.snackBar.openSnackBar( - this.translate.instant( - 'components.users.onNotDelete.plural', - { error: errors ? errors[0].message : '' } - ), - { error: true } + this.translate.instant('components.users.onDelete.plural') ); } else { this.snackBar.openSnackBar( - this.translate.instant( - 'components.users.onNotDelete.singular', - { error: errors ? errors[0].message : '' } - ), - { error: true } + this.translate.instant('components.users.onDelete.singular') ); } + } + resolved(); + }, + error: (errors) => { + if (ids.length > 1) { + this.snackBar.openSnackBar( + this.translate.instant('components.users.onNotDelete.plural', { + error: errorMessageFormatter(errors), + }), + { error: true } + ); } else { - if (data) { - const deletedUsers = data.deleteUsersFromApplication.map( - (x) => x.id - ); - if (deletedUsers.length > 1) { - this.snackBar.openSnackBar( - this.translate.instant('components.users.onDelete.plural') - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('components.users.onDelete.singular') - ); - } - } else { - if (ids.length > 1) { - this.snackBar.openSnackBar( - this.translate.instant( - 'components.users.onNotDelete.plural', - { error: '' } - ), - { error: true } - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant( - 'components.users.onNotDelete.singular', - { error: '' } - ), - { error: true } - ); - } - } + this.snackBar.openSnackBar( + this.translate.instant( + 'components.users.onNotDelete.singular', + { error: errorMessageFormatter(errors) } + ), + { error: true } + ); } resolved(); }, @@ -1156,43 +1168,36 @@ export class ApplicationService { }, }) .subscribe({ - next: ({ errors, data }) => { - if (errors) { + next: ({ data }) => { + if (data) { this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.objectNotCreated', - { - type: this.translate - .instant('common.positionCategory.one') - .toLowerCase(), - error: errors ? errors[0].message : '', - } - ), - { error: true } + this.translate.instant('common.notifications.objectCreated', { + type: this.translate + .instant('common.positionCategory.one') + .toLowerCase(), + value: category.title, + }) ); - } else { - if (data) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectCreated', { - type: this.translate - .instant('common.positionCategory.one') - .toLowerCase(), - value: category.title, - }) - ); - const newApplication: Application = { - ...application, - positionAttributeCategories: - application.positionAttributeCategories?.concat([ - data.addPositionAttributeCategory, - ]), - }; - this.application.next(newApplication); - } + const newApplication: Application = { + ...application, + positionAttributeCategories: + application.positionAttributeCategories?.concat([ + data.addPositionAttributeCategory, + ]), + }; + this.application.next(newApplication); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotCreated', { + type: this.translate + .instant('common.positionCategory.one') + .toLowerCase(), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } @@ -1215,38 +1220,31 @@ export class ApplicationService { }, }) .subscribe({ - next: ({ errors, data }) => { - if (errors) { + next: ({ data }) => { + if (data) { this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.objectNotDeleted', - { - value: category.title, - error: errors ? errors[0].message : '', - } - ), - { error: true } + this.translate.instant('common.notifications.objectDeleted', { + value: category.title, + }) ); - } else { - if (data) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectDeleted', { - value: category.title, - }) - ); - const newApplication: Application = { - ...application, - positionAttributeCategories: - application.positionAttributeCategories?.filter( - (x) => x.id !== data?.deletePositionAttributeCategory.id - ), - }; - this.application.next(newApplication); - } + const newApplication: Application = { + ...application, + positionAttributeCategories: + application.positionAttributeCategories?.filter( + (x) => x.id !== data?.deletePositionAttributeCategory.id + ), + }; + this.application.next(newApplication); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotDeleted', { + value: category.title, + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } @@ -1273,18 +1271,8 @@ export class ApplicationService { title: value.title, }, }) - .subscribe(({ errors, data }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant('common.errors.objectDuplicated', { - type: this.translate - .instant('common.positionCategory.one') - .toLowerCase(), - value: value.title, - }), - { error: true } - ); - } else { + .subscribe({ + next: ({ data }) => { this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectUpdated', { type: this.translate.instant('common.positionCategory.one'), @@ -1305,7 +1293,18 @@ export class ApplicationService { }), }; this.application.next(newApplication); - } + }, + error: () => { + this.snackBar.openSnackBar( + this.translate.instant('common.errors.objectDuplicated', { + type: this.translate + .instant('common.positionCategory.one') + .toLowerCase(), + value: value.title, + }), + { error: true } + ); + }, }); } } @@ -1328,40 +1327,33 @@ export class ApplicationService { }, }) .subscribe({ - next: ({ errors, data }) => { - if (errors) { + next: ({ data }) => { + if (data) { this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.objectNotCreated', - { - type: this.translate - .instant('common.channel.one') - .toLowerCase(), - error: errors ? errors[0].message : '', - } - ), - { error: true } + this.translate.instant('common.notifications.objectCreated', { + type: this.translate + .instant('common.channel.one') + .toLowerCase(), + value: channel.title, + }) ); - } else { - if (data) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectCreated', { - type: this.translate - .instant('common.channel.one') - .toLowerCase(), - value: channel.title, - }) - ); - const newApplication: Application = { - ...application, - channels: application.channels?.concat([data.addChannel]), - }; - this.application.next(newApplication); - } + const newApplication: Application = { + ...application, + channels: application.channels?.concat([data.addChannel]), + }; + this.application.next(newApplication); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotCreated', { + type: this.translate + .instant('common.channel.one') + .toLowerCase(), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } @@ -1384,13 +1376,13 @@ export class ApplicationService { }, }) .subscribe({ - next: ({ errors, data }) => { + next: ({ data }) => { this.handleEditionMutationResponse( - errors, + [], this.translate.instant('common.channel.one'), title ); - if (!errors && data) { + if (data) { const newApplication: Application = { ...application, channels: application?.channels?.map((x) => { @@ -1403,8 +1395,12 @@ export class ApplicationService { this.application.next(newApplication); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.handleEditionMutationResponse( + errors, + this.translate.instant('common.channel.one'), + title + ); }, }); } @@ -1425,37 +1421,30 @@ export class ApplicationService { }, }) .subscribe({ - next: ({ errors, data }) => { - if (errors) { + next: ({ data }) => { + if (data) { this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.objectNotDeleted', - { - value: channel.title, - error: errors ? errors[0].message : '', - } - ), - { error: true } + this.translate.instant('common.notifications.objectDeleted', { + value: channel.title, + }) ); - } else { - if (data) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectDeleted', { - value: channel.title, - }) - ); - const newApplication: Application = { - ...application, - channels: application.channels?.filter( - (x) => x.id !== data?.deleteChannel.id - ), - }; - this.application.next(newApplication); - } + const newApplication: Application = { + ...application, + channels: application.channels?.filter( + (x) => x.id !== data?.deleteChannel.id + ), + }; + this.application.next(newApplication); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotDeleted', { + value: channel.title, + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } @@ -1490,42 +1479,35 @@ export class ApplicationService { }, }) .subscribe({ - next: ({ errors, data }) => { - if (errors) { + next: ({ data }) => { + if (data) { this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.objectNotCreated', - { - type: this.translate - .instant('common.subscription.one') - .toLowerCase(), - error: errors ? errors[0].message : '', - } - ), - { error: true } + this.translate.instant('common.notifications.objectCreated', { + type: this.translate + .instant('common.subscription.one') + .toLowerCase(), + value: subscription.title, + }) ); - } else { - if (data) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectCreated', { - type: this.translate - .instant('common.subscription.one') - .toLowerCase(), - value: subscription.title, - }) - ); - const newApplication: Application = { - ...application, - subscriptions: application.subscriptions?.concat([ - data.addSubscription, - ]), - }; - this.application.next(newApplication); - } + const newApplication: Application = { + ...application, + subscriptions: application.subscriptions?.concat([ + data.addSubscription, + ]), + }; + this.application.next(newApplication); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotCreated', { + type: this.translate + .instant('common.subscription.one') + .toLowerCase(), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } @@ -1548,35 +1530,28 @@ export class ApplicationService { }, }) .subscribe({ - next: ({ errors }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.objectNotDeleted', - { - value: this.translate.instant('common.subscription.one'), - error: errors ? errors[0].message : '', - } - ), - { error: true } - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectDeleted', { - value: this.translate.instant('common.subscription.one'), - }) - ); - const newApplication = { - ...application, - subscriptions: application.subscriptions?.filter( - (sub) => sub.routingKey !== subscription - ), - }; - this.application.next(newApplication); - } + next: () => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectDeleted', { + value: this.translate.instant('common.subscription.one'), + }) + ); + const newApplication = { + ...application, + subscriptions: application.subscriptions?.filter( + (sub) => sub.routingKey !== subscription + ), + }; + this.application.next(newApplication); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotDeleted', { + value: this.translate.instant('common.subscription.one'), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } @@ -1604,13 +1579,13 @@ export class ApplicationService { }, }) .subscribe({ - next: ({ errors, data }) => { + next: ({ data }) => { this.handleEditionMutationResponse( - errors, + [], this.translate.instant('common.subscription.one'), value.title ); - if (!errors && data) { + if (data) { const subscription = data.editSubscription; const newApplication = { ...application, @@ -1624,8 +1599,12 @@ export class ApplicationService { this.application.next(newApplication); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.handleEditionMutationResponse( + errors, + this.translate.instant('common.subscription.one'), + value.title + ); }, }); } @@ -1675,16 +1654,18 @@ export class ApplicationService { }, }, }) - .subscribe(({ data }) => { - if (data) { - const newApplication: Application = { - ...application, - templates: [...(application.templates || []), data.addTemplate], - }; + .subscribe({ + next: ({ data }) => { + if (data) { + const newApplication: Application = { + ...application, + templates: [...(application.templates || []), data.addTemplate], + }; - this.application.next(newApplication); - if (callback) callback(data.addTemplate); - } + this.application.next(newApplication); + if (callback) callback(data.addTemplate); + } + }, }); } } @@ -1705,14 +1686,16 @@ export class ApplicationService { id, }, }) - .subscribe(({ data }) => { - if (data) { - const newApplication: Application = { - ...application, - templates: this.templates.filter((t) => t.id !== id), - }; - this.application.next(newApplication); - } + .subscribe({ + next: ({ data }) => { + if (data) { + const newApplication: Application = { + ...application, + templates: this.templates.filter((t) => t.id !== id), + }; + this.application.next(newApplication); + } + }, }); } } @@ -1738,20 +1721,22 @@ export class ApplicationService { }, }, }) - .subscribe(({ data }) => { - if (data?.editTemplate) { - const updatedTemplate = data.editTemplate; - const newApplication: Application = { - ...application, - templates: application.templates?.map((t) => { - if (t.id === template.id) { - t = updatedTemplate; - } - return t; - }), - }; - this.application.next(newApplication); - } + .subscribe({ + next: ({ data }) => { + if (data?.editTemplate) { + const updatedTemplate = data.editTemplate; + const newApplication: Application = { + ...application, + templates: application.templates?.map((t) => { + if (t.id === template.id) { + t = updatedTemplate; + } + return t; + }), + }; + this.application.next(newApplication); + } + }, }); } } @@ -1776,20 +1761,30 @@ export class ApplicationService { }, }, }) - .subscribe(({ data }) => { - if (data?.editDistributionList) { - const updatedDistributionList = data.editDistributionList; - const newApplication: Application = { - ...application, - distributionLists: application.distributionLists?.map((dist) => { - if (dist.id === distributionList.id) { - dist = updatedDistributionList; - } - return dist; - }), - }; - this.application.next(newApplication); - } + .subscribe({ + next: ({ data }) => { + if (data?.editDistributionList) { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectUpdated', { + value: data.editDistributionList.name, + type: this.translate.instant('common.distributionList.one'), + }) + ); + const updatedDistributionList = data.editDistributionList; + const newApplication: Application = { + ...application, + distributionLists: application.distributionLists?.map( + (dist) => { + if (dist.id === distributionList.id) { + dist = updatedDistributionList; + } + return dist; + } + ), + }; + this.application.next(newApplication); + } + }, }); } } @@ -1817,18 +1812,26 @@ export class ApplicationService { }, }, }) - .subscribe(({ data }) => { - if (data?.addDistributionList) { - const newApplication: Application = { - ...application, - distributionLists: [ - ...(application.distributionLists || []), - data.addDistributionList, - ], - }; - this.application.next(newApplication); - if (callback) callback(data.addDistributionList); - } + .subscribe({ + next: ({ data }) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectCreated', { + value: distributionList.name, + type: this.translate.instant('common.distributionList.one'), + }) + ); + if (data?.addDistributionList) { + const newApplication: Application = { + ...application, + distributionLists: [ + ...(application.distributionLists || []), + data.addDistributionList, + ], + }; + this.application.next(newApplication); + if (callback) callback(data.addDistributionList); + } + }, }); } } @@ -1849,16 +1852,23 @@ export class ApplicationService { id, }, }) - .subscribe(({ data }) => { - if (data) { - const newApplication: Application = { - ...application, - distributionLists: application.distributionLists?.filter( - (dist) => dist.id !== id - ), - }; - this.application.next(newApplication); - } + .subscribe({ + next: ({ data }) => { + if (data) { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectDeleted', { + value: data.deleteDistributionList.name, + }) + ); + const newApplication: Application = { + ...application, + distributionLists: application.distributionLists?.filter( + (dist) => dist.id !== id + ), + }; + this.application.next(newApplication); + } + }, }); } } @@ -1885,16 +1895,12 @@ export class ApplicationService { }) .subscribe({ next: (res) => { - if (res.errors?.length) { - this.snackBar.openSnackBar(res.errors[0].message, { - error: true, - }); - } else { - if (callback) callback(res); - } + if (callback) callback(res); }, - error: (error) => { - this.snackBar.openSnackBar(error[0]?.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); }, }); } @@ -1919,16 +1925,12 @@ export class ApplicationService { }) .subscribe({ next: (res) => { - if (res.errors?.length) { - this.snackBar.openSnackBar(res.errors[0].message, { - error: true, - }); - } else { - if (callback) callback(res); - } + if (callback) callback(res); }, - error: (error) => { - this.snackBar.openSnackBar(error[0]?.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); }, }); } @@ -1959,16 +1961,12 @@ export class ApplicationService { }) .subscribe({ next: (res) => { - if (res.errors?.length) { - this.snackBar.openSnackBar(res.errors[0].message, { - error: true, - }); - } else { - if (callback) callback(res); - } + if (callback) callback(res); }, - error: (error) => { - this.snackBar.openSnackBar(error[0]?.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); }, }); } @@ -2047,11 +2045,11 @@ export class ApplicationService { type: string, value?: string ) { - if (errors) { + if (errors?.length) { this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectNotUpdated', { type, - error: errors ? errors[0].message : '', + error: errorMessageFormatter(errors), }), { error: true } ); @@ -2083,29 +2081,37 @@ export class ApplicationService { permissions, }, }) - .subscribe(({ errors, data }) => { - this.handleEditionMutationResponse( - errors, - this.translate.instant('common.page.one') - ); - if (!errors && data) { - const newApplication = { - ...application, - pages: application.pages?.map((x) => { - if (x.id === page.id) { - x = { - ...x, - canSee: data.editPage.permissions.canSee, - canDelete: data.editPage.permissions.canDelete, - canUpdate: data.editPage.permissions.canUpdate, - }; - } - return x; - }), - }; - this.application.next(newApplication); - if (callback) callback(data.editPage.permissions); - } + .subscribe({ + next: ({ data }) => { + this.handleEditionMutationResponse( + [], + this.translate.instant('common.page.one') + ); + if (data) { + const newApplication = { + ...application, + pages: application.pages?.map((x) => { + if (x.id === page.id) { + x = { + ...x, + canSee: data.editPage.permissions.canSee, + canDelete: data.editPage.permissions.canDelete, + canUpdate: data.editPage.permissions.canUpdate, + }; + } + return x; + }), + }; + this.application.next(newApplication); + if (callback) callback(data.editPage.permissions); + } + }, + error: (errors) => { + this.handleEditionMutationResponse( + errors, + this.translate.instant('common.page.one') + ); + }, }); } } diff --git a/libs/shared/src/lib/services/auth-interceptor/auth-interceptor.service.ts b/libs/shared/src/lib/services/auth-interceptor/auth-interceptor.service.ts index 2f215670e7..7f668fa3c1 100644 --- a/libs/shared/src/lib/services/auth-interceptor/auth-interceptor.service.ts +++ b/libs/shared/src/lib/services/auth-interceptor/auth-interceptor.service.ts @@ -65,7 +65,7 @@ export class AuthInterceptorService implements HttpInterceptor { // redirect user to the logout page } } - return throwError(() => new Error(err.error || err.message)); + return throwError(() => err); }) ); } diff --git a/libs/shared/src/lib/services/context/context.service.ts b/libs/shared/src/lib/services/context/context.service.ts index 31223a2bb9..874e7d3311 100644 --- a/libs/shared/src/lib/services/context/context.service.ts +++ b/libs/shared/src/lib/services/context/context.service.ts @@ -38,6 +38,7 @@ import { ApplicationService } from '../application/application.service'; import { ActivatedRoute, Router } from '@angular/router'; import { RecordQueryResponse } from '../../models/record.model'; import { GET_RECORD_BY_ID } from './graphql/queries'; +import { errorMessageFormatter } from '../../utils/graphql/error-handler'; /** * Dashboard context service @@ -533,13 +534,15 @@ export class ContextService { id: dContext.record, }, }) - .subscribe((res) => { - if (res?.data) { - callback({ - record: dContext.record, - recordData: res.data.record, - }); - } + .subscribe({ + next: (res) => { + if (res?.data) { + callback({ + record: dContext.record, + recordData: res.data.record, + }); + } + }, }); } } @@ -561,8 +564,13 @@ export class ContextService { }, }, }) - .subscribe(({ errors, data }) => { - this.handleFilterMutationResponse({ data, errors }, dashboard); + .subscribe({ + next: ({ data }) => { + this.handleFilterMutationResponse({ data, errors: [] }, dashboard); + }, + error: (errors) => { + this.handleFilterMutationResponse({ data: null, errors }, dashboard); + }, }); } @@ -579,11 +587,11 @@ export class ContextService { dashboard?: Dashboard ) { const { data, errors } = response; - if (errors) { + if (errors?.length) { this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectNotUpdated', { type: this.translate.instant('common.filter.one'), - error: errors ? errors[0].message : '', + error: errorMessageFormatter(errors), }), { error: true } ); diff --git a/libs/shared/src/lib/services/dashboard/dashboard.service.ts b/libs/shared/src/lib/services/dashboard/dashboard.service.ts index 19fea59c70..3c31febaae 100644 --- a/libs/shared/src/lib/services/dashboard/dashboard.service.ts +++ b/libs/shared/src/lib/services/dashboard/dashboard.service.ts @@ -15,6 +15,7 @@ import { Apollo } from 'apollo-angular'; import { EDIT_DASHBOARD, UPDATE_PAGE_CONTEXT } from './graphql/mutations'; import get from 'lodash/get'; import { GraphQLError } from 'graphql'; +import { errorMessageFormatter } from '../../utils/graphql/error-handler'; /** * Shared dashboard service. Handles dashboard events. @@ -57,11 +58,11 @@ export class DashboardService { type: string, value?: string ) { - if (errors) { + if (errors?.length) { this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectNotUpdated', { type, - error: errors ? errors[0].message : '', + error: errorMessageFormatter(errors), }), { error: true } ); @@ -130,8 +131,10 @@ export class DashboardService { name, }, }) - .subscribe(() => { - if (callback) callback(); + .subscribe({ + next: () => { + if (callback) callback(); + }, }); } @@ -178,14 +181,22 @@ export class DashboardService { gridOptions, }, }) - .subscribe(({ errors, data }) => { - this.handleEditionMutationResponse( - errors, - this.translate.instant('common.page.one') - ); - if (!errors && data) { - if (callback) callback(); - } + .subscribe({ + next: ({ data }) => { + this.handleEditionMutationResponse( + [], + this.translate.instant('common.page.one') + ); + if (data) { + if (callback) callback(); + } + }, + error: (errors) => { + this.handleEditionMutationResponse( + errors, + this.translate.instant('common.page.one') + ); + }, }); } } diff --git a/libs/shared/src/lib/services/download/download.service.ts b/libs/shared/src/lib/services/download/download.service.ts index 6f42b45f35..f22c39b38b 100644 --- a/libs/shared/src/lib/services/download/download.service.ts +++ b/libs/shared/src/lib/services/download/download.service.ts @@ -299,27 +299,27 @@ export class DownloadService { const formData = new FormData(); formData.append('file', file, file.name); return new Promise((resolve, reject) => { - this.restService - .post(path, formData, { headers }) - .subscribe((res: { path: string }) => { + this.restService.post(path, formData, { headers }).subscribe({ + next: (res: { path: string }) => { const { path } = res ?? {}; - if (path) { - snackBarRef.instance.message = this.translate.instant( - 'common.notifications.file.upload.ready' - ); - snackBarRef.instance.loading = false; - snackBarRef.instance.triggerSnackBar(SNACKBAR_DURATION); - resolve(path); - } else { - snackBarRef.instance.message = this.translate.instant( - 'common.notifications.file.upload.error' - ); - snackBarRef.instance.loading = false; - snackBarRef.instance.error = true; - snackBarRef.instance.triggerSnackBar(SNACKBAR_DURATION); - reject(); - } - }); + + snackBarRef.instance.message = this.translate.instant( + 'common.notifications.file.upload.ready' + ); + snackBarRef.instance.loading = false; + snackBarRef.instance.triggerSnackBar(SNACKBAR_DURATION); + resolve(path); + }, + error: () => { + snackBarRef.instance.message = this.translate.instant( + 'common.notifications.file.upload.error' + ); + snackBarRef.instance.loading = false; + snackBarRef.instance.error = true; + snackBarRef.instance.triggerSnackBar(SNACKBAR_DURATION); + reject(); + }, + }); }); } } diff --git a/libs/shared/src/lib/services/form-builder/form-builder.service.ts b/libs/shared/src/lib/services/form-builder/form-builder.service.ts index ee626e2886..de8dd9fd5e 100644 --- a/libs/shared/src/lib/services/form-builder/form-builder.service.ts +++ b/libs/shared/src/lib/services/form-builder/form-builder.service.ts @@ -16,6 +16,7 @@ import { BehaviorSubject } from 'rxjs'; import { SnackbarService } from '@oort-front/ui'; import { FormHelpersService } from '../form-helper/form-helper.service'; import { HttpClient } from '@angular/common/http'; +import { errorMessageFormatter } from '../../utils/graphql/error-handler'; /** * Shared form builder service. @@ -272,26 +273,22 @@ export class FormBuilderService { }, }) .subscribe({ - next: ({ errors }) => { - if (errors) { - this.snackBar.openSnackBar( - this.translate.instant( - 'common.notifications.objectNotUpdated', - { - type: this.translate.instant('common.record.one'), - error: errors ? errors[0].message : '', - } - ), - { error: true } - ); - } else { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectUpdated', { - type: this.translate.instant('common.record.one'), - value: '', - }) - ); - } + next: () => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectUpdated', { + type: this.translate.instant('common.record.one'), + value: '', + }) + ); + }, + error: (errors) => { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectNotUpdated', { + type: this.translate.instant('common.record.one'), + error: errorMessageFormatter(errors), + }), + { error: true } + ); }, }); } diff --git a/libs/shared/src/lib/services/form-helper/form-helper.service.ts b/libs/shared/src/lib/services/form-helper/form-helper.service.ts index ca9306efff..42987419aa 100644 --- a/libs/shared/src/lib/services/form-helper/form-helper.service.ts +++ b/libs/shared/src/lib/services/form-helper/form-helper.service.ts @@ -22,6 +22,7 @@ import { DELETE_DRAFT_RECORD, EDIT_DRAFT_RECORD, } from './graphql/mutations'; +import { errorMessageFormatter } from '../../utils/graphql/error-handler'; /** * Shared survey helper service. */ @@ -191,29 +192,22 @@ export class FormHelpersService { }, }) .subscribe({ - next: ({ data, errors }) => { - if (errors) { - this.snackBar.openSnackBar( - `Error. ${errors[0].message}`, - { - error: true, - } - ); - reject(errors); - } else { - question.value[question.value.indexOf(recordId)] = - question.value.includes(recordId) - ? data?.addRecord.id - : recordId; // If there is no error, we replace in the question the temporary id by the final one - surveyData[question.name] = question.value; // We update the survey data to consider our changes - resolve(); - } + next: ({ data }) => { + question.value[question.value.indexOf(recordId)] = + question.value.includes(recordId) + ? data?.addRecord.id + : recordId; // If there is no error, we replace in the question the temporary id by the final one + surveyData[question.name] = question.value; // We update the survey data to consider our changes + resolve(); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { - error: true, - }); - reject(err); + error: (errors) => { + this.snackBar.openSnackBar( + `Error. ${errorMessageFormatter(errors)}`, + { + error: true, + } + ); + reject(errors); }, }); } else { @@ -287,30 +281,34 @@ export class FormHelpersService { data, }, }) - ).then((res) => { - // change the draftId to the new recordId - const newId = res.data?.addRecord?.id; - if (!newId) return; - updateIds[draftId](newId); - // update question.newCreatedRecords too - const isResource = element.question.getType() === 'resource'; - const draftIndex = ( - isResource - ? [element.question.newCreatedRecords] - : element.question.newCreatedRecords - ).indexOf(draftId); - if (draftIndex !== -1) { - if (isResource) { - element.question.newCreatedRecords = newId; - } else { - element.question.newCreatedRecords[draftIndex] = newId; + ) + .then((res) => { + // change the draftId to the new recordId + const newId = res.data?.addRecord?.id; + if (!newId) return; + updateIds[draftId](newId); + // update question.newCreatedRecords too + const isResource = element.question.getType() === 'resource'; + const draftIndex = ( + isResource + ? [element.question.newCreatedRecords] + : element.question.newCreatedRecords + ).indexOf(draftId); + if (draftIndex !== -1) { + if (isResource) { + element.question.newCreatedRecords = newId; + } else { + element.question.newCreatedRecords[draftIndex] = newId; + } } - } - // delete old temporary/draft record and data - this.deleteRecordDraft(draftId); - delete element.question.draftData[draftId]; - return; - }) + // delete old temporary/draft record and data + this.deleteRecordDraft(draftId); + delete element.question.draftData[draftId]; + return; + }) + .catch(() => { + return; + }) ); } } @@ -474,21 +472,14 @@ export class FormHelpersService { }, }); mutation.subscribe({ - next: ({ errors, data }) => { - if (errors) { - survey.clear(false, true); - this.snackBar.openSnackBar(errors[0].message, { error: true }); - } else { - // localStorage.removeItem(this.storageId); - this.snackBar.openSnackBar( - this.translate.instant( - 'components.form.draftRecords.successSave' - ), - { - error: false, - } - ); - } + next: ({ data }) => { + // localStorage.removeItem(this.storageId); + this.snackBar.openSnackBar( + this.translate.instant('components.form.draftRecords.successSave'), + { + error: false, + } + ); // Callback to emit save but stay in record addition mode if (callback) { callback({ @@ -500,8 +491,11 @@ export class FormHelpersService { }); } }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + survey.clear(false, true); + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); }, }); } else { @@ -513,11 +507,8 @@ export class FormHelpersService { data: survey.data, }, }); - mutation.subscribe(({ errors }: any) => { - if (errors) { - survey.clear(false, true); - this.snackBar.openSnackBar(errors[0].message, { error: true }); - } else { + mutation.subscribe({ + next: () => { // localStorage.removeItem(this.storageId); this.snackBar.openSnackBar( this.translate.instant('components.form.draftRecords.successEdit'), @@ -525,17 +516,24 @@ export class FormHelpersService { error: false, } ); - } - // Callback to emit save but stay in record addition mode - if (callback) { - callback({ - id: draftId, - save: { - completed: false, - hideNewRecord: true, - }, + + // Callback to emit save but stay in record addition mode + if (callback) { + callback({ + id: draftId, + save: { + completed: false, + hideNewRecord: true, + }, + }); + } + }, + error: (errors) => { + survey.clear(false, true); + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, }); - } + }, }); } } @@ -554,10 +552,12 @@ export class FormHelpersService { id: draftId, }, }) - .subscribe(() => { - if (callback) { - callback(); - } + .subscribe({ + next: () => { + if (callback) { + callback(); + } + }, }); } diff --git a/libs/shared/src/lib/services/grid-layout/grid-layout.service.ts b/libs/shared/src/lib/services/grid-layout/grid-layout.service.ts index 36b161fd12..59e112b65d 100644 --- a/libs/shared/src/lib/services/grid-layout/grid-layout.service.ts +++ b/libs/shared/src/lib/services/grid-layout/grid-layout.service.ts @@ -60,8 +60,11 @@ export class GridLayoutService { first: options.first, }, }) - ).then(async ({ errors, data }) => { - if (errors) { + ) + .then(async ({ data }) => { + return data.resource.layouts || FALLBACK_LAYOUTS; + }) + .catch(async () => { return await firstValueFrom( this.apollo.query({ query: GET_GRID_FORM_META, @@ -71,17 +74,14 @@ export class GridLayoutService { first: options.first, }, }) - ).then((res2) => { - if (res2.errors) { - return FALLBACK_LAYOUTS; - } else { + ) + .then((res2) => { return res2.data.form.layouts || FALLBACK_LAYOUTS; - } - }); - } else { - return data.resource.layouts || FALLBACK_LAYOUTS; - } - }); + }) + .catch(() => { + return FALLBACK_LAYOUTS; + }); + }); } /** diff --git a/libs/shared/src/lib/services/map/map-layers.service.ts b/libs/shared/src/lib/services/map/map-layers.service.ts index 16f3ef41f2..ee01887de5 100644 --- a/libs/shared/src/lib/services/map/map-layers.service.ts +++ b/libs/shared/src/lib/services/map/map-layers.service.ts @@ -11,6 +11,7 @@ import { Observable, of, switchMap, + throwError, } from 'rxjs'; import { LayerFormData } from '../../components/ui/map/interfaces/layer-settings.type'; import { Layer, EMPTY_FEATURE_COLLECTION } from '../../components/ui/map/layer'; @@ -86,11 +87,9 @@ export class MapLayersService { .pipe( filter((response) => !!response.data), map((response) => { - if (response.errors) { - throw new Error(response.errors[0].message); - } return response.data?.addLayer; - }) + }), + catchError((errors) => throwError(() => errors)) ); } @@ -117,11 +116,9 @@ export class MapLayersService { .pipe( filter((response) => !!response.data), map((response) => { - if (response.errors) { - throw new Error(response.errors[0].message); - } return response.data?.editLayer; - }) + }), + catchError((errors) => throwError(() => errors)) ); } @@ -157,11 +154,9 @@ export class MapLayersService { .pipe( filter((response) => !!response.data), map((response) => { - if (response.errors) { - throw new Error(response.errors[0].message); - } return response.data.layer; - }) + }), + catchError((errors) => throwError(() => errors)) ); } @@ -192,11 +187,9 @@ export class MapLayersService { .pipe( filter((response) => !!response.data), map((response) => { - if (response.errors) { - throw new Error(response.errors[0].message); - } return response.data.layers; - }) + }), + catchError((errors) => throwError(() => errors)) ); } diff --git a/libs/shared/src/lib/services/map/map-polygons.service.ts b/libs/shared/src/lib/services/map/map-polygons.service.ts index a896f89bcf..dfedcda4fa 100644 --- a/libs/shared/src/lib/services/map/map-polygons.service.ts +++ b/libs/shared/src/lib/services/map/map-polygons.service.ts @@ -46,14 +46,14 @@ export class MapPolygonsService { * Retrieve admin0 polygons */ public getAdmin0Polygons() { - this.restService - .get(`${this.restService.apiUrl}/gis/admin0`) - .subscribe((value) => { + this.restService.get(`${this.restService.apiUrl}/gis/admin0`).subscribe({ + next: (value) => { if (value) { this.admin0s = value; this.admin0sReady.next(true); } - }); + }, + }); } /** diff --git a/libs/shared/src/lib/services/notification/notification.service.ts b/libs/shared/src/lib/services/notification/notification.service.ts index 4fd48635dc..a85fee8bbb 100644 --- a/libs/shared/src/lib/services/notification/notification.service.ts +++ b/libs/shared/src/lib/services/notification/notification.service.ts @@ -74,27 +74,37 @@ export class NotificationService { }, }); - this.notificationsQuery.valueChanges.subscribe(({ data }) => { - this.updateValues(data); + this.notificationsQuery.valueChanges.subscribe({ + next: ({ data }) => { + this.updateValues(data); + }, + error: () => { + this.firstLoad = false; + }, }); this.apollo .subscribe({ query: NOTIFICATION_SUBSCRIPTION, }) - .subscribe(({ data }) => { - if (data && data.notification) { - // prevent new notification duplication - if (this.previousNotificationId !== data.notification.id) { - const notifications = this.notifications.getValue(); - if (notifications) { - this.notifications.next([data.notification, ...notifications]); - } else { - this.notifications.next([data.notification]); + .subscribe({ + next: ({ data }) => { + if (data && data.notification) { + // prevent new notification duplication + if (this.previousNotificationId !== data.notification.id) { + const notifications = this.notifications.getValue(); + if (notifications) { + this.notifications.next([ + data.notification, + ...notifications, + ]); + } else { + this.notifications.next([data.notification]); + } } + this.previousNotificationId = data.notification.id; } - this.previousNotificationId = data.notification.id; - } + }, }); } } @@ -113,13 +123,15 @@ export class NotificationService { id: notification.id, }, }) - .subscribe(({ data }) => { - if (data && data.seeNotification) { - const seeNotification = data.seeNotification; - this.notifications.next( - notifications.filter((x) => x.id !== seeNotification.id) - ); - } + .subscribe({ + next: ({ data }) => { + if (data && data.seeNotification) { + const seeNotification = data.seeNotification; + this.notifications.next( + notifications.filter((x) => x.id !== seeNotification.id) + ); + } + }, }); } @@ -135,8 +147,10 @@ export class NotificationService { ids: notificationsIds, }, }) - .subscribe(() => { - this.fetchMore(); + .subscribe({ + next: () => { + this.fetchMore(); + }, }); } diff --git a/libs/shared/src/lib/services/query-builder/query-builder.service.ts b/libs/shared/src/lib/services/query-builder/query-builder.service.ts index c6f1fcd4b0..91822136b1 100644 --- a/libs/shared/src/lib/services/query-builder/query-builder.service.ts +++ b/libs/shared/src/lib/services/query-builder/query-builder.service.ts @@ -118,10 +118,12 @@ export class QueryBuilderService { .query({ query: GET_QUERY_TYPES, }) - .subscribe(({ data }) => { - this.isDoneLoading.next(true); - this.availableQueries.next(data.types.availableQueries); - this.userFields = data.types.userFields; + .subscribe({ + next: ({ data }) => { + this.isDoneLoading.next(true); + this.availableQueries.next(data.types.availableQueries); + this.userFields = data.types.userFields; + }, }); } diff --git a/libs/shared/src/lib/services/workflow/workflow.service.ts b/libs/shared/src/lib/services/workflow/workflow.service.ts index ec9641262e..6462f9244a 100644 --- a/libs/shared/src/lib/services/workflow/workflow.service.ts +++ b/libs/shared/src/lib/services/workflow/workflow.service.ts @@ -14,6 +14,7 @@ import { import { ApplicationService } from '../application/application.service'; import { TranslateService } from '@ngx-translate/core'; import { SnackbarService } from '@oort-front/ui'; +import { errorMessageFormatter } from '../../utils/graphql/error-handler'; /** * Workflow service. Handles modification of workflow ( step addition / step name update ) and some workflow actions. @@ -61,8 +62,10 @@ export class WorkflowService { id, }, }) - .subscribe(({ data }) => { - this.workflow.next(data.workflow); + .subscribe({ + next: ({ data }) => { + this.workflow.next(data.workflow); + }, }); } @@ -84,35 +87,38 @@ export class WorkflowService { workflow: workflow.id, }, }) - .subscribe(({ errors, data }) => { - if (data) { - this.snackBar.openSnackBar( - this.translate.instant('common.notifications.objectCreated', { - type: this.translate.instant('common.step.one').toLowerCase(), - value: data.addStep.name, - }) - ); - this.loadWorkflow(workflow.id); - if (step.type === ContentType.form) { - this.router.navigate( - ['../' + step.type + '/' + data.addStep.id], - { relativeTo: route.parent } - ); - } else { - this.router.navigate( - ['../' + step.type + '/' + data.addStep.content], - { relativeTo: route.parent } + .subscribe({ + next: ({ data }) => { + if (data) { + this.snackBar.openSnackBar( + this.translate.instant('common.notifications.objectCreated', { + type: this.translate.instant('common.step.one').toLowerCase(), + value: data.addStep.name, + }) ); + this.loadWorkflow(workflow.id); + if (step.type === ContentType.form) { + this.router.navigate( + ['../' + step.type + '/' + data.addStep.id], + { relativeTo: route.parent } + ); + } else { + this.router.navigate( + ['../' + step.type + '/' + data.addStep.content], + { relativeTo: route.parent } + ); + } } - } else { + }, + error: (errors) => { this.snackBar.openSnackBar( this.translate.instant('common.notifications.objectNotUpdated', { type: this.translate.instant('common.workflow.one'), - error: errors ? errors[0].message : '', + error: errorMessageFormatter(errors), }), { error: true } ); - } + }, }); } else { this.snackBar.openSnackBar( @@ -142,25 +148,34 @@ export class WorkflowService { name: step.name, }, }) - .subscribe(({ errors, data }) => { - this.applicationService.handleEditionMutationResponse( - errors, - this.translate.instant('common.step.one'), - step.name - ); - if (!errors && data) { - const newWorkflow: Workflow = { - ...workflow, - steps: workflow.steps?.map((x) => { - if (x.id === step.id) { - x = { ...x, name: step.name }; - } - return x; - }), - }; - this.workflow.next(newWorkflow); - if (callback) callback(); - } + .subscribe({ + next: ({ data }) => { + this.applicationService.handleEditionMutationResponse( + [], + this.translate.instant('common.step.one'), + step.name + ); + if (data) { + const newWorkflow: Workflow = { + ...workflow, + steps: workflow.steps?.map((x) => { + if (x.id === step.id) { + x = { ...x, name: step.name }; + } + return x; + }), + }; + this.workflow.next(newWorkflow); + if (callback) callback(); + } + }, + error: (errors) => { + this.applicationService.handleEditionMutationResponse( + errors, + this.translate.instant('common.step.one'), + step.name + ); + }, }); } } @@ -183,25 +198,34 @@ export class WorkflowService { icon, }, }) - .subscribe(({ errors, data }) => { - this.applicationService.handleEditionMutationResponse( - errors, - this.translate.instant('common.step.one'), - step.name - ); - if (!errors && data) { - const newWorkflow: Workflow = { - ...workflow, - steps: workflow.steps?.map((x) => { - if (x.id === step.id) { - x = { ...x, icon: data.editStep.icon }; - } - return x; - }), - }; - this.workflow.next(newWorkflow); - if (callback) callback(); - } + .subscribe({ + next: ({ data }) => { + this.applicationService.handleEditionMutationResponse( + [], + this.translate.instant('common.step.one'), + step.name + ); + if (data) { + const newWorkflow: Workflow = { + ...workflow, + steps: workflow.steps?.map((x) => { + if (x.id === step.id) { + x = { ...x, icon: data.editStep.icon }; + } + return x; + }), + }; + this.workflow.next(newWorkflow); + if (callback) callback(); + } + }, + error: (errors) => { + this.applicationService.handleEditionMutationResponse( + errors, + this.translate.instant('common.step.one'), + step.name + ); + }, }); } } @@ -224,19 +248,27 @@ export class WorkflowService { permissions, }, }) - .subscribe(({ errors, data }) => { - this.applicationService.handleEditionMutationResponse( - errors, - this.translate.instant('common.step.one') - ); - if (!errors && data) { - const newWorkflow: Workflow = { - ...workflow, - permissions: data.editStep.permissions, - }; - this.workflow.next(newWorkflow); - if (callback) callback(data.editStep.permissions); - } + .subscribe({ + next: ({ data }) => { + this.applicationService.handleEditionMutationResponse( + [], + this.translate.instant('common.step.one') + ); + if (data) { + const newWorkflow: Workflow = { + ...workflow, + permissions: data.editStep.permissions, + }; + this.workflow.next(newWorkflow); + if (callback) callback(data.editStep.permissions); + } + }, + error: (errors) => { + this.applicationService.handleEditionMutationResponse( + errors, + this.translate.instant('common.step.one') + ); + }, }); } } diff --git a/libs/shared/src/lib/survey/components/application-dropdown/application-dropdown.component.ts b/libs/shared/src/lib/survey/components/application-dropdown/application-dropdown.component.ts index 8f784881e7..3ab27f7147 100644 --- a/libs/shared/src/lib/survey/components/application-dropdown/application-dropdown.component.ts +++ b/libs/shared/src/lib/survey/components/application-dropdown/application-dropdown.component.ts @@ -118,10 +118,12 @@ export class ApplicationDropdownComponent }, }, }) - .subscribe(({ data }) => { - this.selectedApplications = data.applications.edges.map( - (x) => x.node - ); + .subscribe({ + next: ({ data }) => { + this.selectedApplications = data.applications.edges.map( + (x) => x.node + ); + }, }); } @@ -138,8 +140,13 @@ export class ApplicationDropdownComponent this.applications$ = this.applications.asObservable(); this.applicationsQuery.valueChanges .pipe(takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { - this.updateValues(data, loading); + .subscribe({ + next: ({ data, loading }) => { + this.updateValues(data, loading); + }, + error: () => { + this.loading = false; + }, }); } diff --git a/libs/shared/src/lib/survey/components/owner.ts b/libs/shared/src/lib/survey/components/owner.ts index 64845fd1e8..3d4ad455a6 100644 --- a/libs/shared/src/lib/survey/components/owner.ts +++ b/libs/shared/src/lib/survey/components/owner.ts @@ -56,14 +56,16 @@ export const init = ( applications: question.applications, }, }) - .subscribe(({ data }) => { - if (data.rolesFromApplications) { - const roles = []; - for (const role of data.rolesFromApplications) { - roles.push({ value: role.id, text: role.title }); + .subscribe({ + next: ({ data }) => { + if (data.rolesFromApplications) { + const roles = []; + for (const role of data.rolesFromApplications) { + roles.push({ value: role.id, text: role.title }); + } + question.contentQuestion.choices = roles; } - question.contentQuestion.choices = roles; - } + }, }); }, // eslint-disable-next-line @typescript-eslint/no-empty-function diff --git a/libs/shared/src/lib/survey/components/resource-available-fields/config-display-grid-fields-modal/config-display-grid-fields-modal.component.ts b/libs/shared/src/lib/survey/components/resource-available-fields/config-display-grid-fields-modal/config-display-grid-fields-modal.component.ts index 74998c3c2d..52047a40f0 100644 --- a/libs/shared/src/lib/survey/components/resource-available-fields/config-display-grid-fields-modal/config-display-grid-fields-modal.component.ts +++ b/libs/shared/src/lib/survey/components/resource-available-fields/config-display-grid-fields-modal/config-display-grid-fields-modal.component.ts @@ -75,24 +75,29 @@ export class ConfigDisplayGridFieldsModalComponent ngOnInit(): void { this.queryBuilder.availableQueries$ .pipe(takeUntil(this.destroy$)) - .subscribe((res) => { - if (res.length > 0) { - const hasDataForm = this.data.form !== null; - const queryName = hasDataForm - ? this.data.form.value.name - : this.queryBuilder.getQueryNameFromResourceName( - this.data.resourceName - ); + .subscribe({ + next: (res) => { + if (res.length > 0) { + const hasDataForm = this.data.form !== null; + const queryName = hasDataForm + ? this.data.form.value.name + : this.queryBuilder.getQueryNameFromResourceName( + this.data.resourceName + ); - this.form = createQueryForm({ - name: queryName, - fields: hasDataForm ? this.data.form.value.fields : [], - sort: hasDataForm ? this.data.form.value.sort : {}, - filter: hasDataForm ? this.data.form.value.filter : {}, - }); + this.form = createQueryForm({ + name: queryName, + fields: hasDataForm ? this.data.form.value.fields : [], + sort: hasDataForm ? this.data.form.value.sort : {}, + filter: hasDataForm ? this.data.form.value.filter : {}, + }); + this.loading = false; + } + }, + error: () => { this.loading = false; - } + }, }); } } diff --git a/libs/shared/src/lib/survey/components/resource-dropdown/resource-dropdown.component.ts b/libs/shared/src/lib/survey/components/resource-dropdown/resource-dropdown.component.ts index 7f74858dd0..8daf0851af 100644 --- a/libs/shared/src/lib/survey/components/resource-dropdown/resource-dropdown.component.ts +++ b/libs/shared/src/lib/survey/components/resource-dropdown/resource-dropdown.component.ts @@ -69,10 +69,12 @@ export class ResourceDropdownComponent id: this.model.value, }, }) - .subscribe(({ data }) => { - if (data.resource) { - this.selectedResource = data.resource; - } + .subscribe({ + next: ({ data }) => { + if (data.resource) { + this.selectedResource = data.resource; + } + }, }); } } diff --git a/libs/shared/src/lib/survey/components/resource.ts b/libs/shared/src/lib/survey/components/resource.ts index 3a0a253c49..a42477d4d6 100644 --- a/libs/shared/src/lib/survey/components/resource.ts +++ b/libs/shared/src/lib/survey/components/resource.ts @@ -183,16 +183,18 @@ export const init = ( visibleIndex: 3, choices: (obj: QuestionResource, choicesCallback: any) => { if (obj.resource) { - getResourceById({ id: obj.resource }).subscribe(({ data }) => { - const choices = (data.resource.fields || []) - .filter((item: any) => item.type !== 'matrix') - .map((item: any) => { - return { - value: item.name, - }; - }); - choices.unshift({ value: null }); - choicesCallback(choices); + getResourceById({ id: obj.resource }).subscribe({ + next: ({ data }) => { + const choices = (data.resource.fields || []) + .filter((item: any) => item.type !== 'matrix') + .map((item: any) => { + return { + value: item.name, + }; + }); + choices.unshift({ value: null }); + choicesCallback(choices); + }, }); } }, @@ -272,12 +274,14 @@ export const init = ( visibleIndex: 3, choices: (obj: QuestionResource, choicesCallback: any) => { if (obj.resource && obj.addRecord) { - getResourceById({ id: obj.resource }).subscribe(({ data }) => { - const choices = (data.resource.forms || []).map((item: any) => { - return { value: item.id, text: item.name }; - }); - choices.unshift({ value: null, text: '' }); - choicesCallback(choices); + getResourceById({ id: obj.resource }).subscribe({ + next: ({ data }) => { + const choices = (data.resource.forms || []).map((item: any) => { + return { value: item.id, text: item.name }; + }); + choices.unshift({ value: null, text: '' }); + choicesCallback(choices); + }, }); } }, @@ -336,11 +340,15 @@ export const init = ( !!obj && !!obj.selectQuestion && !!obj.displayField, choices: (obj: QuestionResource, choicesCallback: any) => { if (obj.resource) { - getResourceById({ id: obj.resource }).subscribe(({ data }) => { - const choices = (data.resource.fields || []).map((item: any) => { - return { value: item.name }; - }); - choicesCallback(choices); + getResourceById({ id: obj.resource }).subscribe({ + next: ({ data }) => { + const choices = (data.resource.fields || []).map( + (item: any) => { + return { value: item.name }; + } + ); + choicesCallback(choices); + }, }); } }, diff --git a/libs/shared/src/lib/survey/components/resources.ts b/libs/shared/src/lib/survey/components/resources.ts index e067629d65..39ba438e53 100644 --- a/libs/shared/src/lib/survey/components/resources.ts +++ b/libs/shared/src/lib/survey/components/resources.ts @@ -166,14 +166,16 @@ export const init = ( visibleIndex: 3, choices: (obj: any, choicesCallback: any) => { if (obj.resource) { - getResourceById({ id: obj.resource }).subscribe(({ data }) => { - const choices = (data.resource.fields || []) - .filter((item: any) => item.type !== 'matrix') - .map((item: any) => { - return { value: item.name }; - }); - choices.unshift({ value: null }); - choicesCallback(choices); + getResourceById({ id: obj.resource }).subscribe({ + next: ({ data }) => { + const choices = (data.resource.fields || []) + .filter((item: any) => item.type !== 'matrix') + .map((item: any) => { + return { value: item.name }; + }); + choices.unshift({ value: null }); + choicesCallback(choices); + }, }); } }, @@ -308,12 +310,14 @@ export const init = ( visibleIndex: 3, choices: (obj: any, choicesCallback: any) => { if (obj.resource && obj.addRecord) { - getResourceById({ id: obj.resource }).subscribe(({ data }) => { - const choices = (data.resource.forms || []).map((item: any) => { - return { value: item.id, text: item.name }; - }); - choices.unshift({ value: null, text: '' }); - choicesCallback(choices); + getResourceById({ id: obj.resource }).subscribe({ + next: ({ data }) => { + const choices = (data.resource.forms || []).map((item: any) => { + return { value: item.id, text: item.name }; + }); + choices.unshift({ value: null, text: '' }); + choicesCallback(choices); + }, }); } }, @@ -381,11 +385,15 @@ export const init = ( visibleIf: (obj: any) => obj.selectQuestion && obj.displayField, choices: (obj: any, choicesCallback: any) => { if (obj.resource) { - getResourceById({ id: obj.resource }).subscribe(({ data }) => { - const choices = (data.resource.fields || []).map((item: any) => { - return { value: item.name }; - }); - choicesCallback(choices); + getResourceById({ id: obj.resource }).subscribe({ + next: ({ data }) => { + const choices = (data.resource.fields || []).map( + (item: any) => { + return { value: item.name }; + } + ); + choicesCallback(choices); + }, }); } }, @@ -506,13 +514,15 @@ export const init = ( this.populateChoices(question); } } - getResourceById({ id: question.resource }).subscribe(({ data }) => { - // const choices = mapQuestionChoices(data, question); - // question.contentQuestion.choices = choices; - if (!question.placeholder) { - question.contentQuestion.optionsCaption = - 'Select a record from ' + data.resource.name + '...'; - } + getResourceById({ id: question.resource }).subscribe({ + next: ({ data }) => { + // const choices = mapQuestionChoices(data, question); + // question.contentQuestion.choices = choices; + if (!question.placeholder) { + question.contentQuestion.optionsCaption = + 'Select a record from ' + data.resource.name + '...'; + } + }, }); if (question.selectQuestion) { if (question.selectQuestion === '#staticValue') { diff --git a/libs/shared/src/lib/survey/components/test-service-dropdown/test-service-dropdown.component.ts b/libs/shared/src/lib/survey/components/test-service-dropdown/test-service-dropdown.component.ts index 75e94e0ab1..1788222e97 100644 --- a/libs/shared/src/lib/survey/components/test-service-dropdown/test-service-dropdown.component.ts +++ b/libs/shared/src/lib/survey/components/test-service-dropdown/test-service-dropdown.component.ts @@ -113,10 +113,12 @@ export class TestServiceDropdownComponent id: this.model.value, }, }) - .subscribe(({ data }) => { - if (data) { - this.selectedRecord = data.record; - } + .subscribe({ + next: ({ data }) => { + if (data) { + this.selectedRecord = data.record; + } + }, }); } if (this.resource) { diff --git a/libs/shared/src/lib/survey/components/users-dropdown/users-dropdown.component.ts b/libs/shared/src/lib/survey/components/users-dropdown/users-dropdown.component.ts index a9739653cb..30caa5e51b 100644 --- a/libs/shared/src/lib/survey/components/users-dropdown/users-dropdown.component.ts +++ b/libs/shared/src/lib/survey/components/users-dropdown/users-dropdown.component.ts @@ -111,10 +111,12 @@ export class UsersDropdownComponent }, }, }) - .subscribe(({ data }) => { - if (data.users) { - this.initialSelection = data.users.edges.map((x) => x.node); - } + .subscribe({ + next: ({ data }) => { + if (data.users) { + this.initialSelection = data.users.edges.map((x) => x.node); + } + }, }); } diff --git a/libs/shared/src/lib/utils/graphql/error-handler.ts b/libs/shared/src/lib/utils/graphql/error-handler.ts new file mode 100644 index 0000000000..4af01db4ed --- /dev/null +++ b/libs/shared/src/lib/utils/graphql/error-handler.ts @@ -0,0 +1,74 @@ +import { ApolloLink, Observable } from '@apollo/client'; +import { isNil } from 'lodash'; + +/** + * Gets the message in the graphql error + * + * @param errors GraphQL error + * @returns formatted message + */ +export const errorMessageFormatter = (errors: any): string => { + let messages = []; + if (errors.networkError.length) { + messages = errors.networkError.map((x: any) => x.message); + } + if (errors.protocolErrors.length) { + messages = errors.protocolErrors.map((x: any) => x.message); + } + if (errors.clientErrors.length) { + messages = errors.clientErrors.map((x: any) => x.message); + } + if (errors.graphQLErrors.length) { + messages = errors.graphQLErrors.map((x: any) => x.message); + } + return messages.join(', '); +}; + +/** + * Create apollo link to handle any incoming graphQL error + * + * @param errorCallback error callback action when encountering an error + * @returns current graphql observable + */ +export const createGraphQlErrorHandler = (errorCallback: any) => + new ApolloLink((operation, forward) => { + return new Observable((observer) => { + const observable = forward(operation); + const subscription = observable.subscribe({ + /** + * Handle successful request + * + * @param value Value sent from the GraphQL request + */ + next(value) { + if ( + value.errors && + // And all involved data in the request are nullish + Object.keys(value.data ?? {}).every((key) => + isNil(value.data?.[key]) + ) + ) { + observer.error(value.errors); + } else { + observer.next(value); + } + }, + /** + * Handle error request + * + * @param networkError Error sent from GraphQL request + */ + error(networkError) { + errorCallback(networkError); + observer.error(networkError); + }, + /** + * Complete given observable by default + */ + complete() { + observer.complete(); + }, + }); + return () => subscription.unsubscribe(); + }); + }); diff --git a/libs/shared/src/lib/utils/public-api.ts b/libs/shared/src/lib/utils/public-api.ts index c14a6f4fc3..9249a4c85e 100644 --- a/libs/shared/src/lib/utils/public-api.ts +++ b/libs/shared/src/lib/utils/public-api.ts @@ -1,3 +1,4 @@ export * from './validators/cron.validator'; export * from './graphql/connection.type'; +export * from './graphql/error-handler'; export * from './update-queries'; diff --git a/libs/shared/src/lib/views/application-users/application-users.component.ts b/libs/shared/src/lib/views/application-users/application-users.component.ts index b74fd76e16..eb8b8f2012 100644 --- a/libs/shared/src/lib/views/application-users/application-users.component.ts +++ b/libs/shared/src/lib/views/application-users/application-users.component.ts @@ -2,7 +2,14 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { Dialog } from '@angular/cdk/dialog'; import { TranslateService } from '@ngx-translate/core'; import { Apollo } from 'apollo-angular'; -import { Subject, filter, switchMap, takeUntil } from 'rxjs'; +import { + Subject, + catchError, + filter, + switchMap, + takeUntil, + throwError, +} from 'rxjs'; import { UnsubscribeComponent } from '../../components/utils/unsubscribe/unsubscribe.component'; import { PositionAttributeCategory } from '../../models/position-attribute-category.model'; import { AddUsersMutationResponse, Role } from '../../models/user.model'; @@ -11,6 +18,7 @@ import { UserListComponent } from './components/user-list/user-list.component'; import { ADD_USERS } from './graphql/mutations'; import { SnackbarService } from '@oort-front/ui'; import { CompositeFilterDescriptor } from '@progress/kendo-data-query'; +import { errorMessageFormatter } from '../../utils/graphql/error-handler'; import { isNil } from 'lodash'; /** @@ -94,18 +102,29 @@ export class ApplicationUsersComponent .pipe( filter((value: any) => !isNil(value)), switchMap((value: any) => { - return this.apollo.mutate({ - mutation: ADD_USERS, - variables: { - users: value, - application: this.roles[0].application?.id, - }, - }); + return this.apollo + .mutate({ + mutation: ADD_USERS, + variables: { + users: value, + application: this.roles[0].application?.id, + }, + }) + .pipe( + catchError((errors) => + throwError(() => { + return { + errors, + addUsers: value, + }; + }) + ) + ); }), takeUntil(this.destroy$) ) - .subscribe(({ errors, data }) => { - if (!errors) { + .subscribe({ + next: ({ data }) => { if (data?.addUsers.length) { this.snackBar.openSnackBar( this.translate.instant('components.users.onInvite.plural') @@ -116,23 +135,24 @@ export class ApplicationUsersComponent ); } this.userList?.fetchUsers(true); - } else { - if (data?.addUsers?.length) { + }, + error: ({ errors, addUsers }) => { + if (addUsers?.length) { this.snackBar.openSnackBar( this.translate.instant('components.users.onNotInvite.plural', { - error: errors[0].message, + error: errorMessageFormatter(errors), }), { error: true } ); } else { this.snackBar.openSnackBar( this.translate.instant('components.users.onNotInvite.singular', { - error: errors[0].message, + error: errorMessageFormatter(errors), }), { error: true } ); } - } + }, }); } diff --git a/libs/shared/src/lib/views/application-users/components/user-list/user-list.component.ts b/libs/shared/src/lib/views/application-users/components/user-list/user-list.component.ts index a4962f23ae..a9a013497f 100644 --- a/libs/shared/src/lib/views/application-users/components/user-list/user-list.component.ts +++ b/libs/shared/src/lib/views/application-users/components/user-list/user-list.component.ts @@ -144,8 +144,14 @@ export class UserListComponent }), takeUntil(this.destroy$) ) - .subscribe(({ data, loading }) => { - this.updateValues(data, loading); + .subscribe({ + next: ({ data, loading }) => { + this.updateValues(data, loading); + }, + error: () => { + this.loading.next(false); + this.updating = false; + }, }); } diff --git a/libs/shared/src/lib/views/profile/profile.component.ts b/libs/shared/src/lib/views/profile/profile.component.ts index effba854aa..a903f698ae 100644 --- a/libs/shared/src/lib/views/profile/profile.component.ts +++ b/libs/shared/src/lib/views/profile/profile.component.ts @@ -8,6 +8,7 @@ import { UnsubscribeComponent } from '../../components/utils/unsubscribe/unsubsc import { takeUntil } from 'rxjs/operators'; import { SnackbarService } from '@oort-front/ui'; import { EditUserProfileMutationResponse, User } from '../../models/user.model'; +import { errorMessageFormatter } from '../../utils/graphql/error-handler'; /** * Shared profile page. @@ -79,11 +80,13 @@ export class ProfileComponent extends UnsubscribeComponent implements OnInit { }, }) .subscribe({ - next: ({ errors, data }) => { - this.handleUserProfileMutationResponse({ data, errors }, 'name'); + next: ({ data }) => { + this.handleUserProfileMutationResponse({ data, errors: [] }, 'name'); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); }, }); } @@ -105,14 +108,16 @@ export class ProfileComponent extends UnsubscribeComponent implements OnInit { }, }) .subscribe({ - next: ({ errors, data }) => { + next: ({ data }) => { this.handleUserProfileMutationResponse( - { data, errors }, + { data, errors: [] }, 'favoriteApp' ); }, - error: (err) => { - this.snackBar.openSnackBar(err.message, { error: true }); + error: (errors) => { + this.snackBar.openSnackBar(errorMessageFormatter(errors), { + error: true, + }); }, }); } @@ -145,7 +150,7 @@ export class ProfileComponent extends UnsubscribeComponent implements OnInit { profileProperty: 'name' | 'favoriteApp' ) { const { errors, data } = response; - if (errors) { + if (errors?.length) { this.snackBar.openSnackBar( this.translate.instant('pages.profile.notifications.notUpdated'), { error: true } diff --git a/libs/ui/src/lib/graphql-select/graphql-select.component.ts b/libs/ui/src/lib/graphql-select/graphql-select.component.ts index 9632bb529a..dc17103d21 100644 --- a/libs/ui/src/lib/graphql-select/graphql-select.component.ts +++ b/libs/ui/src/lib/graphql-select/graphql-select.component.ts @@ -306,9 +306,14 @@ export class GraphQLSelectComponent if (this.query) { this.query.valueChanges .pipe(takeUntil(this.queryChange$), takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { - this.queryName = Object.keys(data)[0]; - this.updateValues(data, loading); + .subscribe({ + next: ({ data, loading }) => { + this.queryName = Object.keys(data)[0]; + this.updateValues(data, loading); + }, + error: () => { + this.loading = false; + }, }); } this.ngControl?.valueChanges @@ -370,9 +375,14 @@ export class GraphQLSelectComponent // Subscribe to the new query this.query.valueChanges .pipe(takeUntil(this.queryChange$), takeUntil(this.destroy$)) - .subscribe(({ data, loading }) => { - this.queryName = Object.keys(data)[0]; - this.updateValues(data, loading); + .subscribe({ + next: ({ data, loading }) => { + this.queryName = Object.keys(data)[0]; + this.updateValues(data, loading); + }, + error: () => { + this.loading = false; + }, }); } else { const elements = this.elements.getValue(); diff --git a/libs/ui/src/lib/snackbar/snackbar.component.html b/libs/ui/src/lib/snackbar/snackbar.component.html index 90715f5d9f..6cf58b1912 100644 --- a/libs/ui/src/lib/snackbar/snackbar.component.html +++ b/libs/ui/src/lib/snackbar/snackbar.component.html @@ -23,7 +23,9 @@ >
-

+

{{ message }}