Merge branch '21-integration-des-erreurs-standard-du-backend' into 'master'

Resolve "Intégration des erreurs standard du Backend"

Closes #21

See merge request color-recipes-explorer/frontend!17
This commit is contained in:
William Nolin 2021-04-13 21:00:40 +00:00
commit 04a8ba9246
23 changed files with 273 additions and 240 deletions

View File

@ -1,23 +1,16 @@
import {Component, OnInit} from '@angular/core'
import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms'
import {AccountService} from '../../services/account.service'
import {Router} from '@angular/router'
import {ErrorHandler, ErrorModel, ErrorService} from '../../../shared/service/error.service'
import {ActivatedRoute, Router} from '@angular/router'
import {ErrorService} from '../../../shared/service/error.service'
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
@Component({
selector: 'cre-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.sass']
})
export class LoginComponent implements ErrorHandler, OnInit {
handledErrorModels: ErrorModel[] = [{
filter: error => error.status === 401,
messageProducer: () => 'Les identifiants entrés sont invalides.'
}, {
filter: error => error.status === 404 || error.status === 403,
consumer: () => console.warn('No default user is defined on this computer')
}]
export class LoginComponent extends ErrorHandlingComponent implements OnInit {
form: FormGroup
idFormControl: FormControl
passwordFormControl: FormControl
@ -25,9 +18,11 @@ export class LoginComponent implements ErrorHandler, OnInit {
constructor(
private formBuilder: FormBuilder,
private accountService: AccountService,
private errorService: ErrorService,
private router: Router
errorService: ErrorService,
router: Router,
activatedRoute: ActivatedRoute
) {
super(errorService, activatedRoute, router)
}
ngOnInit(): void {

View File

@ -8,6 +8,7 @@ import {ApiService} from '../../shared/service/api.service'
import {Employee, EmployeePermission} from '../../shared/model/employee'
import {ErrorService} from '../../shared/service/error.service'
import {globalLoadingWheel} from '../../shared/components/loading-wheel/loading-wheel.component'
import {AlertService} from '../../shared/service/alert.service'
@Injectable({
providedIn: 'root'
@ -19,7 +20,8 @@ export class AccountService implements OnDestroy {
private http: HttpClient,
private api: ApiService,
private appState: AppState,
private errorService: ErrorService
private errorService: ErrorService,
private alertService: AlertService
) {
}
@ -39,10 +41,17 @@ export class AccountService implements OnDestroy {
.pipe(
take(1),
takeUntil(this.destroy$),
).subscribe({
next: employee => this.appState.authenticatedEmployee = employee,
error: err => this.errorService.handleError(err)
})
).subscribe(
{
next: employee => this.appState.authenticatedEmployee = employee,
error: err => {
if (err.status === 404 || err.status === 403) {
console.warn('No default user is defined on this computer')
} else {
this.errorService.handleError(err)
}
}
})
}
}
@ -65,7 +74,11 @@ export class AccountService implements OnDestroy {
success()
},
error: err => {
this.errorService.handleError(err)
if (err.status === 401) {
this.alertService.pushError('Les identifiants entrés sont invalides')
} else {
this.errorService.handleError(err)
}
globalLoadingWheel.hide()
}
})

View File

@ -52,13 +52,15 @@ export class MixEditorComponent extends ErrorHandlingComponent {
columns = ['position', 'buttonsPosition', 'material', 'quantity', 'units', 'buttonRemove']
deleting = false
handledErrorModels = [{
filter: error => error.status === 409 && !this.deleting,
messageProducer: error => `Un mélange avec le nom '${error.id}' existe déjà dans cette recette`
errorHandlers = [{
filter: error => error.type === 'notfound-mix-id',
consumer: error => this.urlUtils.navigateTo('/color/list')
}, {
filter: error => error.error && error.error.status === 409 && this.deleting,
consumer: () => this.deleting = false,
messageProducer: () => 'Ce mélange est utilisé par un ou plusieurs autres mélanges'
filter: error => error.type === 'exists-material-name',
messageProducer: error => `Un produit avec le nom '${error.name}' existe déjà`
}, {
filter: error => error.type === 'cannotdelete-mix',
messageProducer: error => 'Ce mélange est utilisé par un ou plusieurs autres mélanges'
}]
constructor(
@ -95,8 +97,7 @@ export class MixEditorComponent extends ErrorHandlingComponent {
this.addBlankMixMaterial()
}
this.generateForm()
},
'/color/list'
}
)
}

View File

@ -128,7 +128,7 @@ export class MixTableComponent extends SubscribingComponent {
isInLowQuantity(materialId: number): boolean {
return this.deductErrorBody.mix === this.mix.id &&
this.deductErrorBody.lowQuantities.filter(l => l.material === materialId).length > 0
this.deductErrorBody.lowQuantities.filter(l => l.materialId == materialId).length > 0
}
round(quantity: number): number {

View File

@ -10,7 +10,7 @@ import {AccountService} from '../../../accounts/services/account.service'
import {EmployeePermission} from '../../../shared/model/employee'
import {EntityEditComponent} from '../../../shared/components/entity-edit/entity-edit.component'
import {ImagesEditorComponent} from '../../components/images-editor/images-editor.component'
import {ErrorModel, ErrorService} from '../../../shared/service/error.service'
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
import {AlertService} from '../../../shared/service/alert.service'
import {GroupService} from '../../../groups/services/group.service'
import {AppState} from '../../../shared/app-state'
@ -105,9 +105,9 @@ export class EditComponent extends ErrorHandlingComponent {
units$ = new Subject<string>()
submittedValues: any | null
handledErrorModels: ErrorModel[] = [{
filter: error => error.status === 409,
messageProducer: () => `Une couleur avec le nom '${this.submittedValues.name}' et la bannière '${this.recipe.company.name}' existe déjà`
errorHandlers: ErrorHandler[] = [{
filter: error => error.type === 'notfound-recipe-id',
consumer: error => this.urlUtils.navigateTo('/color/list')
}]
constructor(
@ -137,8 +137,7 @@ export class EditComponent extends ErrorHandlingComponent {
if (recipeStepCount(this.recipe) == 0) {
this.alertService.pushWarning('Il n\'y a aucune étape dans cette recette')
}
},
'/color/list'
}
)
}

View File

@ -2,9 +2,9 @@ import {Component} from '@angular/core'
import {RecipeService} from '../../services/recipe.service'
import {ActivatedRoute, Router} from '@angular/router'
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
import {MixMaterialDto, Recipe, recipeMixCount, recipeNoteForGroupId, recipeStepCount, recipeApprobationExpired} from '../../../shared/model/recipe.model'
import {MixMaterialDto, Recipe, recipeMixCount, recipeNoteForGroupId, recipeStepCount} from '../../../shared/model/recipe.model'
import {Observable, Subject} from 'rxjs'
import {ErrorModel, ErrorService} from '../../../shared/service/error.service'
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
import {AlertService} from '../../../shared/service/alert.service'
import {GlobalAlertHandlerComponent} from '../../../shared/components/global-alert-handler/global-alert-handler.component'
import {InventoryService} from '../../../material/service/inventory.service'
@ -32,9 +32,13 @@ export class ExploreComponent extends ErrorHandlingComponent {
groupsNote = new Map<number, string>()
deductedMixId: number | null
handledErrorModels: ErrorModel[] = [{
filter: error => error.status === 409,
consumer: error => this.deductErrorBody = {mix: this.deductedMixId, lowQuantities: error.error.lowQuantities},
errorHandlers: ErrorHandler[] = [{
filter: error => error.type === 'notfound-recipe-id',
consumer: error => this.urlUtils.navigateTo('/color/list')
}, {
filter: error => error.type === 'notenoughinventory-multiple',
consumer: error => this.deductErrorBody = {mix: this.deductedMixId, lowQuantities: error.lowQuantities},
messageProducer: () => 'Certains produit ne sont pas en quantité suffisante dans l\'inventaire'
}]
@ -68,8 +72,7 @@ export class ExploreComponent extends ErrorHandlingComponent {
if (recipeMixCount(this.recipe) <= 0 || recipeStepCount(this.recipe) <= 0) {
this.alertService.pushWarning('Cette recette n\'est pas complète')
}
},
'/colors/list'
}
)
}
@ -82,7 +85,7 @@ export class ExploreComponent extends ErrorHandlingComponent {
this.units$.next(unit)
}
changeQuantity(event: { mixId: number, mixMaterial: MixMaterialDto}) {
changeQuantity(event: { mixId: number, mixMaterial: MixMaterialDto }) {
if (!this.quantitiesChanges.has(event.mixId)) {
this.quantitiesChanges.set(event.mixId, new Map<number, number>())
}

View File

@ -3,9 +3,9 @@ import {ErrorHandlingComponent} from '../../../shared/components/subscribing.com
import {RecipeService} from '../../services/recipe.service'
import {EmployeePermission} from '../../../shared/model/employee'
import {AccountService} from '../../../accounts/services/account.service'
import {getRecipeLuma, recipeApprobationExpired, Recipe} from '../../../shared/model/recipe.model'
import {getRecipeLuma, Recipe, recipeApprobationExpired} from '../../../shared/model/recipe.model'
import {ActivatedRoute, Router} from '@angular/router'
import {ErrorModel, ErrorService} from '../../../shared/service/error.service'
import {ErrorService} from '../../../shared/service/error.service'
@Component({
selector: 'cre-list',
@ -19,8 +19,6 @@ export class ListComponent extends ErrorHandlingComponent {
panelForcedExpanded = false
hiddenRecipes = []
handledErrorModels: ErrorModel[]
constructor(
private recipeService: RecipeService,
private accountService: AccountService,

View File

@ -2,9 +2,9 @@ import {Component} from '@angular/core'
import {Material} from '../../../../shared/model/material.model'
import {MaterialService} from '../../../../material/service/material.service'
import {ActivatedRoute, Router} from '@angular/router'
import {ErrorHandlingComponent, SubscribingComponent} from '../../../../shared/components/subscribing.component'
import {ErrorHandlingComponent} from '../../../../shared/components/subscribing.component'
import {MixService} from '../../../services/mix.service'
import {ErrorHandler, ErrorModel, ErrorService} from '../../../../shared/service/error.service'
import {ErrorService} from '../../../../shared/service/error.service'
@Component({
selector: 'cre-mix-add',
@ -15,8 +15,6 @@ export class MixAddComponent extends ErrorHandlingComponent {
recipeId: number | null
materials: Material[] | null
handledErrorModels: ErrorModel[]
constructor(
private materialService: MaterialService,
private mixService: MixService,

View File

@ -4,7 +4,7 @@ import {ErrorHandlingComponent} from '../../../../shared/components/subscribing.
import {Material} from '../../../../shared/model/material.model'
import {MaterialService} from '../../../../material/service/material.service'
import {MixService} from '../../../services/mix.service'
import {ErrorModel, ErrorService} from '../../../../shared/service/error.service'
import {ErrorHandlerComponent, ErrorService} from '../../../../shared/service/error.service'
import {MixMaterialDto} from '../../../../shared/model/recipe.model'
import {AlertService} from '../../../../shared/service/alert.service'
@ -18,8 +18,6 @@ export class MixEditComponent extends ErrorHandlingComponent {
recipeId: number | null
materials: Material[] | null
handledErrorModels: ErrorModel[]
constructor(
private materialService: MaterialService,
private mixService: MixService,

View File

@ -3,7 +3,7 @@ import {CompanyService} from '../../service/company.service'
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
import {FormField} from '../../../shared/components/entity-add/entity-add.component'
import {ActivatedRoute, Router} from '@angular/router'
import {ErrorModel, ErrorService} from '../../../shared/service/error.service'
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
@Component({
selector: 'cre-add',
@ -25,9 +25,9 @@ export class AddComponent extends ErrorHandlingComponent {
]
submittedValues: any | null
handledErrorModels: ErrorModel[] = [{
filter: error => error.status === 409,
messageProducer: () => `Une bannière avec le nom '${this.submittedValues.name}' existe déjà`
errorHandlers: ErrorHandler[] = [{
filter: error => error.type === 'exists-company-name',
messageProducer: error => `Une bannière avec le nom '${error.name}' existe déjà`
}]
constructor(

View File

@ -4,7 +4,7 @@ import {Company} from '../../../shared/model/company.model'
import {FormField} from '../../../shared/components/entity-add/entity-add.component'
import {CompanyService} from '../../service/company.service'
import {ActivatedRoute, Router} from '@angular/router'
import {ErrorModel, ErrorService} from '../../../shared/service/error.service'
import {ErrorHandler, ErrorHandlerComponent, ErrorService} from '../../../shared/service/error.service'
@Component({
selector: 'cre-edit',
@ -26,13 +26,15 @@ export class EditComponent extends ErrorHandlingComponent {
}
]
deleting = false
handledErrorModels: ErrorModel[] = [{
filter: error => error.status === 409 && !this.deleting,
messageProducer: error => `Une bannière avec le nom '${error.error.id}' existe déjà`
errorHandlers: ErrorHandler[] = [{
filter: error => error.type === 'notfound-company-id',
consumer: error => this.urlUtils.navigateTo('/catalog/company/list')
}, {
filter: error => error.status === 409 && this.deleting,
messageProducer: () => 'Cette bannière est utilisée par une ou plusieurs recettes'
filter: error => error.type === 'exists-company-name',
messageProducer: error => `Une bannière avec le nom '${error.name}' existe déjà`
}, {
filter: error => error.type === 'cannotdelete-company',
messageProducer: error => 'Cette bannière est utilisée par une ou plusieurs recettes'
}]
constructor(
@ -51,8 +53,7 @@ export class EditComponent extends ErrorHandlingComponent {
this.subscribeEntityById(
this.companyService,
id,
company => this.company = company,
'/catalog/company/list'
company => this.company = company
)
}
@ -64,7 +65,6 @@ export class EditComponent extends ErrorHandlingComponent {
}
delete() {
this.deleting = true
this.subscribeAndNavigate(
this.companyService.delete(this.company.id),
'/catalog/company/list'

View File

@ -8,7 +8,7 @@ import {GroupService} from '../../../groups/services/group.service'
import {EmployeeService} from '../../services/employee.service'
import {ActivatedRoute, Router} from '@angular/router'
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
import {ErrorService} from '../../../shared/service/error.service'
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
import {FormField} from '../../../shared/components/entity-add/entity-add.component'
import {map} from 'rxjs/operators'
@ -75,6 +75,14 @@ export class AddComponent extends ErrorHandlingComponent {
type: 'permissions'
}]
errorHandlers: ErrorHandler[] = [{
filter: error => error.type === 'exists-employee-id',
messageProducer: error => `Un utilisateur avec l'identifiant ${error.id} existe déjà`
}, {
filter: error => error.type === 'exists-employee-fullName',
messageProducer: error => `Un utilisateur nommé '${error.fullName}' existe déjà`
}]
constructor(
private employeeService: EmployeeService,
private groupService: GroupService,

View File

@ -6,7 +6,7 @@ import {ActivatedRoute, Router} from '@angular/router'
import {Employee} from '../../../shared/model/employee'
import {AccountService} from '../../../accounts/services/account.service'
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
import {ErrorService} from '../../../shared/service/error.service'
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
import {FormField} from '../../../shared/components/entity-add/entity-add.component'
import {map} from 'rxjs/operators'
@ -58,6 +58,14 @@ export class EditComponent extends ErrorHandlingComponent {
type: 'permissions'
}]
errorHandlers: ErrorHandler[] = [{
filter: error => error.type === 'notfound-employee-id',
consumer: error => this.urlUtils.navigateTo('/employee/list')
}, {
filter: error => error.type === 'exists-employee-fullName',
messageProducer: error => `Un utilisateur nommé '${error.fullName}' existe déjà`
}]
constructor(
private accountService: AccountService,
private employeeService: EmployeeService,
@ -74,8 +82,7 @@ export class EditComponent extends ErrorHandlingComponent {
this.subscribeEntityById(
this.employeeService,
id,
employee => this.employee = employee,
'/employee/list'
employee => this.employee = employee
)
this.formFields[this.formFields.length - 1].template = this.permissionsTemplateRef

View File

@ -4,7 +4,7 @@ import {EmployeeService} from '../../services/employee.service'
import {Employee} from '../../../shared/model/employee'
import {ActivatedRoute, Router} from '@angular/router'
import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms'
import {ErrorService} from '../../../shared/service/error.service'
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
@Component({
selector: 'cre-password-edit',
@ -17,6 +17,11 @@ export class PasswordEditComponent extends ErrorHandlingComponent {
form: FormGroup
passwordControl = new FormControl(null, Validators.compose([Validators.required, Validators.minLength(8)]))
errorHandlers: ErrorHandler[] = [{
filter: error => error.type === 'notfound-employee-id',
consumer: error => this.urlUtils.navigateTo('/employee/list')
}]
constructor(
private employeeService: EmployeeService,
private formBuilder: FormBuilder,
@ -32,8 +37,7 @@ export class PasswordEditComponent extends ErrorHandlingComponent {
this.subscribeEntityById(
this.employeeService,
id,
employee => this.employee = employee,
'/employee/list'
employee => this.employee = employee
)
this.form = this.formBuilder.group({

View File

@ -4,7 +4,7 @@ import {GroupService} from '../../services/group.service'
import {ActivatedRoute, Router} from '@angular/router'
import {currentPermissionsFieldComponent} from '../../../shared/components/permissions-field/permissions-field.component'
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
import {ErrorService} from '../../../shared/service/error.service'
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
import {FormField} from '../../../shared/components/entity-add/entity-add.component'
@Component({
@ -32,6 +32,11 @@ export class AddComponent extends ErrorHandlingComponent {
type: 'permissions'
}]
errorHandlers: ErrorHandler[] = [{
filter: error => error.type === 'exists-employeegroup-name',
messageProducer: error => `Un groupe avec le nom '${error.name}' existe déjà`
}]
constructor(
private groupService: GroupService,
errorService: ErrorService,

View File

@ -6,7 +6,7 @@ import {Validators} from '@angular/forms'
import {currentPermissionsFieldComponent} from '../../../shared/components/permissions-field/permissions-field.component'
import {AccountService} from '../../../accounts/services/account.service'
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
import {ErrorService} from '../../../shared/service/error.service'
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
import {FormField} from '../../../shared/components/entity-add/entity-add.component'
@Component({
@ -35,6 +35,14 @@ export class EditComponent extends ErrorHandlingComponent {
}]
group: EmployeeGroup | null
errorHandlers: ErrorHandler[] = [{
filter: error => error.type === 'notfound-employeegroup-id',
consumer: error => this.urlUtils.navigateTo('/group/list')
}, {
filter: error => error.type === 'exists-employeegroup-name',
messageProducer: error => `Un groupe avec le nom '${error.name}' existe déjà`
}]
constructor(
private accountService: AccountService,
private groupService: GroupService,
@ -50,8 +58,7 @@ export class EditComponent extends ErrorHandlingComponent {
this.subscribeEntityById(
this.groupService,
id,
group => this.group = group,
'/group/list'
group => this.group = group
)
this.formFields[this.formFields.length - 1].template = this.permissionsTemplateRef

View File

@ -4,7 +4,7 @@ import {EmployeeGroup, EmployeePermission} from '../../../shared/model/employee'
import {AccountService} from '../../../accounts/services/account.service'
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
import {ActivatedRoute, Router} from '@angular/router'
import {ErrorModel, ErrorService} from '../../../shared/service/error.service'
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
import {AlertService} from '../../../shared/service/alert.service'
@Component({
@ -29,8 +29,8 @@ export class ListComponent extends ErrorHandlingComponent {
permission: EmployeePermission.EDIT_USERS
}]
handledErrorModels: ErrorModel[] = [{
filter: error => error.status === 404,
errorHandlers: ErrorHandler[] = [{
filter: error => error.type === 'nodefaultgroup',
consumer: () => this.alertService.pushWarning('Aucun groupe par défaut n\'a été défini sur cet ordinateur')
}]

View File

@ -4,7 +4,7 @@ import {Validators} from '@angular/forms'
import {MaterialTypeService} from '../../service/material-type.service'
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
import {ActivatedRoute, Router} from '@angular/router'
import {ErrorModel, ErrorService} from '../../../shared/service/error.service'
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
@Component({
selector: 'cre-add',
@ -45,14 +45,13 @@ export class AddComponent extends ErrorHandlingComponent {
type: 'checkbox'
}
]
submittedValues: any | null
handledErrorModels: ErrorModel[] = [{
filter: error => error.status === 409 && error.error.id === this.submittedValues.name,
messageProducer: error => `Un type de produit avec le nom '${error.error.id}' existe déjà`
errorHandlers: ErrorHandler[] = [{
filter: error => error.type === 'exists-materialtype-name',
messageProducer: error => `Un type de produit avec le nom '${error.name}' existe déjà`
}, {
filter: error => error.status === 409 && error.error.id === this.submittedValues.prefix,
messageProducer: error => `Un type de produit avec le préfixe '${error.error.id}' existe déjà`
filter: error => error.type === 'exists-materialtype-prefix',
messageProducer: error => `Un type de produit avec le préfixe '${error.prefix}' existe déjà`
}]
constructor(
@ -65,7 +64,6 @@ export class AddComponent extends ErrorHandlingComponent {
}
submit(values) {
this.submittedValues = values
this.subscribeAndNavigate(
this.materialTypeService.save(values.name, values.prefix, values.usePercentages),
'/catalog/materialtype/list'

View File

@ -5,7 +5,7 @@ import {ErrorHandlingComponent} from '../../../shared/components/subscribing.com
import {MaterialTypeService} from '../../service/material-type.service'
import {FormField} from '../../../shared/components/entity-add/entity-add.component'
import {Validators} from '@angular/forms'
import {ErrorModel, ErrorService} from '../../../shared/service/error.service'
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
@Component({
selector: 'cre-edit',
@ -42,18 +42,18 @@ export class EditComponent extends ErrorHandlingComponent {
}
]
deleting = false
submittedValues: any | null
handledErrorModels: ErrorModel[] = [{
filter: error => error.status === 409 && !this.deleting && error.error.id === this.submittedValues.name,
messageProducer: error => `Un type de produit avec le nom '${error.error.id}' existe déjà`
errorHandlers: ErrorHandler[] = [{
filter: error => error.type === 'notfound-materialtype-id',
consumer: error => this.urlUtils.navigateTo('/catalog/materialtype/list')
}, {
filter: error => error.status === 409 && !this.deleting && error.error.id === this.submittedValues.prefix,
messageProducer: error => `Un type de produit avec le préfixe '${error.error.id}' existe déjà`
filter: error => error.type === 'exists-materialtype-name',
messageProducer: error => `Un type de produit avec le nom '${error.name}' existe déjà`
}, {
filter: error => error.status === 409 && this.deleting,
consumer: () => this.deleting = true,
messageProducer: () => 'Ce type de produit est utilisé dans une ou plusieurs recettes ou produits'
filter: error => error.type === 'exists-materialtype-prefix',
messageProducer: error => `Un type de produit avec le préfixe '${error.prefix}' existe déjà`
}, {
filter: error => error.type === 'cannotdelete-materialtype',
messageProducer: error => 'Ce type de produit est utilisé dans une ou plusieurs recettes ou produits'
}]
constructor(
@ -72,13 +72,11 @@ export class EditComponent extends ErrorHandlingComponent {
this.subscribeEntityById(
this.materialTypeService,
id,
materialType => this.materialType = materialType,
'/employee/list'
materialType => this.materialType = materialType
)
}
submit(values) {
this.submittedValues = values
this.subscribeAndNavigate(
this.materialTypeService.update(this.materialType.id, values.name, values.prefix),
'/catalog/materialtype/list'
@ -86,7 +84,6 @@ export class EditComponent extends ErrorHandlingComponent {
}
delete() {
this.deleting = true
this.subscribeAndNavigate(
this.materialTypeService.delete(this.materialType.id),
'/catalog/materialtype/list'

View File

@ -6,7 +6,7 @@ import {MaterialTypeService} from '../../../material-type/service/material-type.
import {ActivatedRoute, Router} from '@angular/router'
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
import {map} from 'rxjs/operators'
import {ErrorModel, ErrorService} from '../../../shared/service/error.service'
import {ErrorHandler, ErrorHandlerComponent, ErrorService} from '../../../shared/service/error.service'
@Component({
selector: 'cre-add',
@ -60,9 +60,9 @@ export class AddComponent extends ErrorHandlingComponent {
}
]
handledErrorModels: ErrorModel[] = [{
filter: error => error.status === 409,
messageProducer: error => `Un produit avec le nom '${error.error.id}' existe déjà`
errorHandlers: ErrorHandler[] = [{
filter: error => error.type === 'exists-material-name',
messageProducer: error => `Un produit avec le nom '${error.name}' existe déjà`
}]
constructor(

View File

@ -8,122 +8,121 @@ import {ActivatedRoute, Router} from '@angular/router'
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
import {Material} from '../../../shared/model/material.model'
import {environment} from '../../../../../environments/environment'
import {ErrorModel, ErrorService} from '../../../shared/service/error.service'
import {ErrorHandler, ErrorService} from '../../../shared/service/error.service'
@Component({
selector: 'cre-edit',
templateUrl: './edit.component.html',
styleUrls: ['./edit.component.sass']
selector: 'cre-edit',
templateUrl: './edit.component.html',
styleUrls: ['./edit.component.sass']
})
export class EditComponent extends ErrorHandlingComponent {
@ViewChild('simdutTemplate', {static: true}) simdutTemplateRef
@ViewChild('simdutTemplate', {static: true}) simdutTemplateRef
material: Material | null
formFields: FormField[] = [
{
name: 'name',
label: 'Code',
icon: 'form-textbox',
type: 'text',
required: true,
errorMessages: [
{conditionFn: (errors) => errors.required, message: 'Un code est requis'}
]
},
{
name: 'inventoryQuantity',
label: 'Quantité en inventaire',
icon: 'beaker-outline',
type: 'number',
required: true,
validator: Validators.min(0),
errorMessages: [
{conditionFn: errors => errors.required, message: 'Une quantité en inventaire est requise'},
{conditionFn: errors => errors.min, message: 'La quantité doit être supérieure ou égale à 0'}
],
step: '0.01'
},
{
name: 'materialType',
label: 'Type de produit',
icon: 'shape-outline',
type: 'select',
required: true,
errorMessages: [
{conditionFn: errors => errors.required, message: 'Un type de produit est requis'}
],
valueFn: material => material.materialType.id,
options$: this.materialTypeService.all.pipe(map(types => types.map(t => {
return {value: t.id, label: t.name}
})))
},
{
name: 'simdutFile',
label: 'Fiche signalitique',
icon: 'file-outline',
type: 'file',
fileType: 'application/pdf'
}
]
hasSimdut = false
selectedSimdutFile: File | null
deleting = false
handledErrorModels: ErrorModel[] = [{
filter: error => error.status === 409 && !this.deleting,
messageProducer: error => `Un produit avec le nom '${error.error.id}' existe déjà`
}, {
filter: error => error.status === 409 && this.deleting,
consumer: () => this.deleting = false,
messageProducer: () => `Ce produit est utilisé dans une plusieurs recettes`
}]
constructor(
private materialService: MaterialService,
private materialTypeService: MaterialTypeService,
errorService: ErrorService,
router: Router,
activatedRoute: ActivatedRoute
) {
super(errorService, activatedRoute, router)
material: Material | null
formFields: FormField[] = [
{
name: 'name',
label: 'Code',
icon: 'form-textbox',
type: 'text',
required: true,
errorMessages: [
{conditionFn: (errors) => errors.required, message: 'Un code est requis'}
]
},
{
name: 'inventoryQuantity',
label: 'Quantité en inventaire',
icon: 'beaker-outline',
type: 'number',
required: true,
validator: Validators.min(0),
errorMessages: [
{conditionFn: errors => errors.required, message: 'Une quantité en inventaire est requise'},
{conditionFn: errors => errors.min, message: 'La quantité doit être supérieure ou égale à 0'}
],
step: '0.01'
},
{
name: 'materialType',
label: 'Type de produit',
icon: 'shape-outline',
type: 'select',
required: true,
errorMessages: [
{conditionFn: errors => errors.required, message: 'Un type de produit est requis'}
],
valueFn: material => material.materialType.id,
options$: this.materialTypeService.all.pipe(map(types => types.map(t => {
return {value: t.id, label: t.name}
})))
},
{
name: 'simdutFile',
label: 'Fiche signalitique',
icon: 'file-outline',
type: 'file',
fileType: 'application/pdf'
}
]
hasSimdut = false
selectedSimdutFile: File | null
ngOnInit() {
super.ngOnInit()
errorHandlers: ErrorHandler[] = [{
filter: error => error.type === 'notfound-material-id',
consumer: error => this.urlUtils.navigateTo('/catalog/material/list')
}, {
filter: error => error.type === 'exists-material-name',
messageProducer: error => `Un produit avec le nom '${error.name}' existe déjà`
}, {
filter: error => error.type === 'cannotdelete-material',
messageProducer: error => `Ce produit est utilisé dans une plusieurs recettes`
}]
this.formFields[3].template = this.simdutTemplateRef
constructor(
private materialService: MaterialService,
private materialTypeService: MaterialTypeService,
errorService: ErrorService,
router: Router,
activatedRoute: ActivatedRoute
) {
super(errorService, activatedRoute, router)
}
const id = parseInt(this.activatedRoute.snapshot.paramMap.get('id'))
this.subscribeEntityById(
this.materialService,
id,
material => this.material = material,
'/catalog/material/list'
)
ngOnInit() {
super.ngOnInit()
this.subscribe(
this.materialService.hasSimdut(id),
b => this.hasSimdut = b
)
}
this.formFields[3].template = this.simdutTemplateRef
submit(values) {
this.subscribeAndNavigate(
this.materialService.update(this.material.id, values.name, values.inventoryQuantity, values.materialType, this.selectedSimdutFile),
'/catalog/material/list'
)
}
const id = parseInt(this.activatedRoute.snapshot.paramMap.get('id'))
this.subscribeEntityById(
this.materialService,
id,
material => this.material = material
)
delete() {
this.deleting = true
this.subscribeAndNavigate(
this.materialService.delete(this.material.id),
'/catalog/material/list'
)
}
this.subscribe(
this.materialService.hasSimdut(id),
b => this.hasSimdut = b
)
}
openSimdutUrl() {
const simdutUrl = environment.apiUrl + `/material/${this.material.id}/simdut`
window.open(simdutUrl, '_blank')
}
submit(values) {
this.subscribeAndNavigate(
this.materialService.update(this.material.id, values.name, values.inventoryQuantity, values.materialType, this.selectedSimdutFile),
'/catalog/material/list'
)
}
delete() {
this.subscribeAndNavigate(
this.materialService.delete(this.material.id),
'/catalog/material/list'
)
}
openSimdutUrl() {
const simdutUrl = environment.apiUrl + `/material/${this.material.id}/simdut`
window.open(simdutUrl, '_blank')
}
}

View File

@ -3,7 +3,7 @@ import {OnDestroy, OnInit} from '@angular/core'
import {Observable, Subject} from 'rxjs'
import {ActivatedRoute, Router} from '@angular/router'
import {UrlUtils} from '../utils/url.utils'
import {ErrorHandler, ErrorModel, ErrorService} from '../service/error.service'
import {ErrorHandler, ErrorHandlerComponent, ErrorService} from '../service/error.service'
import {globalLoadingWheel} from './loading-wheel/loading-wheel.component'
export abstract class SubscribingComponent implements OnInit, OnDestroy {
@ -47,7 +47,7 @@ export abstract class SubscribingComponent implements OnInit, OnDestroy {
)
}
subscribeEntityById<T>(service: any, id: number, resultConsumer: (T) => void, notFoundRoute: string, showWheel = true) {
subscribeEntityById<T>(service: any, id: number, resultConsumer: (T) => void, showWheel = true) {
this.showLoadingWheel(showWheel)
this.subscribers$.push(service.getById(id)
.pipe(take(1), takeUntil(this.destroy$))
@ -57,8 +57,8 @@ export abstract class SubscribingComponent implements OnInit, OnDestroy {
this.hideLoadingWheel(showWheel)
},
error: err => {
this.handleNotFoundError(err, notFoundRoute)
this.hideLoadingWheel(showWheel)
this.errorService.handleError(err)
}
}))
}
@ -71,14 +71,6 @@ export abstract class SubscribingComponent implements OnInit, OnDestroy {
this.destroy$.complete()
}
handleNotFoundError(error: any, route: string) {
if (error.status === 404) {
this.urlUtils.navigateTo(route)
} else {
this.errorService.handleError(error)
}
}
protected showLoadingWheel(shouldShowWheel) {
if (shouldShowWheel) {
globalLoadingWheel.show()
@ -92,8 +84,8 @@ export abstract class SubscribingComponent implements OnInit, OnDestroy {
}
}
export abstract class ErrorHandlingComponent extends SubscribingComponent implements ErrorHandler {
handledErrorModels: ErrorModel[] = []
export abstract class ErrorHandlingComponent extends SubscribingComponent implements ErrorHandlerComponent {
errorHandlers: ErrorHandler[] = []
protected constructor(
errorService: ErrorService,

View File

@ -7,13 +7,10 @@ import {AppState} from '../app-state'
})
export class ErrorService {
private static readonly UNKNOWN_ERROR_MESSAGE = 'Une erreur inconnue est survenue'
private defaultHandledErrorModels: ErrorModel[] = [{
filter: error => error.status === 0 && error.statusText === 'Unknown Error' || error.status === 502,
consumer: () => this.appState.isServerOnline = false
}, {
private defaultHandledErrorModels: ErrorHandler[] = [{
filter: error => error.status === 400,
consumer: error => console.error(error),
messageProducer: () => 'Certaines informations dans la requête étaient invalides'
messageProducer: () => 'Certaines informations étaient invalides'
}, {
filter: error => error.status === 401,
messageProducer: () => 'Vous devez être connecté pour effectuer cette action'
@ -31,7 +28,7 @@ export class ErrorService {
messageProducer: () => ErrorService.UNKNOWN_ERROR_MESSAGE
}]
private activeHandler: ErrorHandler
private activeHandler: ErrorHandlerComponent
constructor(
private alertService: AlertService,
@ -39,17 +36,25 @@ export class ErrorService {
) {
}
handleError(error: any) {
handleError(response: any) {
let matchingModels
if (this.isServerOfflineError(response)) {
this.appState.isServerOnline = false
return
}
const error = response.error
if (this.activeHandler) {
matchingModels = this.activeHandler.handledErrorModels.filter(m => m.filter(error)) // Find error models whose filter matches the current error
matchingModels = this.activeHandler.errorHandlers.filter(m => m.filter(error)) // Find error models whose filter matches the current error
} else {
console.warn('An error occurred but no handler was set')
console.error(error)
}
if (!matchingModels || matchingModels.length == 0) { // If none are found, search in defaults handlers
matchingModels = this.defaultHandledErrorModels.filter(m => m.filter(error))
matchingModels = errorHandlers.filter(m => m.filter(error))
}
if (!matchingModels || matchingModels.length == 0) { // If still none are found, handle as an unknown error
@ -72,7 +77,7 @@ export class ErrorService {
}
consumeUnknownError(error: any) {
console.error(error)
console.error('An unknown error occurred', error)
this.pushUnknownError()
}
@ -80,16 +85,20 @@ export class ErrorService {
this.alertService.pushError(ErrorService.UNKNOWN_ERROR_MESSAGE)
}
set activeErrorHandler(handler: ErrorHandler) {
set activeErrorHandler(handler: ErrorHandlerComponent) {
this.activeHandler = handler
}
private isServerOfflineError(response: any): boolean {
return response.status === 0 && response.statusText === 'Unknown Error'
}
}
/**
* An error handler, defining models of errors that this type will handle
*/
export interface ErrorHandler {
handledErrorModels: ErrorModel[]
export interface ErrorHandlerComponent {
errorHandlers: ErrorHandler[]
}
/**
@ -100,7 +109,7 @@ export interface ErrorHandler {
*
* To work correctly a model must define at least one handler (consumer or message producer).
*/
export class ErrorModel {
export class ErrorHandler {
constructor(
public filter: (error: any) => Boolean,
public consumer?: (error: any) => void,
@ -108,3 +117,5 @@ export class ErrorModel {
) {
}
}
const errorHandlers: ErrorHandler[] = []