Merge pull request 'develop' (#8) from develop into master
Reviewed-on: #8
This commit is contained in:
commit
3c630914b0
51
.drone.yml
51
.drone.yml
|
@ -1,12 +1,13 @@
|
||||||
---
|
---
|
||||||
global-variables:
|
global-variables:
|
||||||
release: &release ${DRONE_BRANCH##**/}
|
release: &release ${DRONE_TAG}
|
||||||
environment: &environment
|
environment: &environment
|
||||||
CRE_REGISTRY_IMAGE: registry.fyloz.dev:5443/colorrecipesexplorer/frontend
|
CRE_REGISTRY_IMAGE: registry.fyloz.dev/colorrecipesexplorer/frontend
|
||||||
CRE_PORT: 9102
|
CRE_PORT: 9102
|
||||||
CRE_RELEASE: *release
|
CRE_RELEASE: *release
|
||||||
alpine-image: &alpine-image alpine:latest
|
alpine-image: &alpine-image alpine:latest
|
||||||
docker-registry-repo: &docker-registry-repo registry.fyloz.dev:5443/colorrecipesexplorer/frontend
|
docker-registry: &docker-registry registry.fyloz.dev
|
||||||
|
docker-registry-repo: &docker-registry-repo registry.fyloz.dev/colorrecipesexplorer/frontend
|
||||||
|
|
||||||
kind: pipeline
|
kind: pipeline
|
||||||
name: default
|
name: default
|
||||||
|
@ -21,6 +22,9 @@ steps:
|
||||||
- echo -n "latest" > .tags
|
- echo -n "latest" > .tags
|
||||||
when:
|
when:
|
||||||
branch: develop
|
branch: develop
|
||||||
|
event:
|
||||||
|
exclude:
|
||||||
|
- pull_request
|
||||||
|
|
||||||
- name: set-docker-tags-release
|
- name: set-docker-tags-release
|
||||||
image: *alpine-image
|
image: *alpine-image
|
||||||
|
@ -29,18 +33,40 @@ steps:
|
||||||
commands:
|
commands:
|
||||||
- echo -n "latest-release,$CRE_RELEASE" > .tags
|
- echo -n "latest-release,$CRE_RELEASE" > .tags
|
||||||
when:
|
when:
|
||||||
branch: release/**
|
event:
|
||||||
|
- tag
|
||||||
|
|
||||||
- name: containerize
|
- name: containerize-dev
|
||||||
image: plugins/docker
|
image: plugins/docker
|
||||||
environment:
|
environment:
|
||||||
<<: *environment
|
<<: *environment
|
||||||
settings:
|
settings:
|
||||||
repo: *docker-registry-repo
|
repo: *docker-registry-repo
|
||||||
|
registry: *docker-registry
|
||||||
|
username:
|
||||||
|
from_secret: docker_username
|
||||||
|
password:
|
||||||
|
from_secret: docker_password
|
||||||
when:
|
when:
|
||||||
branch:
|
branch: develop
|
||||||
- develop
|
event:
|
||||||
- release/**
|
exclude:
|
||||||
|
- pull_request
|
||||||
|
|
||||||
|
- name: containerize-release
|
||||||
|
image: plugins/docker
|
||||||
|
environment:
|
||||||
|
<<: *environment
|
||||||
|
settings:
|
||||||
|
repo: *docker-registry-repo
|
||||||
|
registry: *docker-registry
|
||||||
|
username:
|
||||||
|
from_secret: docker_username
|
||||||
|
password:
|
||||||
|
from_secret: docker_password
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- tag
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
image: alpine:latest
|
image: alpine:latest
|
||||||
|
@ -70,10 +96,5 @@ steps:
|
||||||
- ssh -p $DEPLOY_SERVER_SSH_PORT $DEPLOY_SERVER_USERNAME@$DEPLOY_SERVER "docker pull $CRE_REGISTRY_IMAGE:$CRE_RELEASE"
|
- ssh -p $DEPLOY_SERVER_SSH_PORT $DEPLOY_SERVER_USERNAME@$DEPLOY_SERVER "docker pull $CRE_REGISTRY_IMAGE:$CRE_RELEASE"
|
||||||
- ssh -p $DEPLOY_SERVER_SSH_PORT $DEPLOY_SERVER_USERNAME@$DEPLOY_SERVER "docker run -d -p $CRE_PORT:80 --name=$DEPLOY_CONTAINER_NAME $CRE_REGISTRY_IMAGE:$CRE_RELEASE"
|
- ssh -p $DEPLOY_SERVER_SSH_PORT $DEPLOY_SERVER_USERNAME@$DEPLOY_SERVER "docker run -d -p $CRE_PORT:80 --name=$DEPLOY_CONTAINER_NAME $CRE_REGISTRY_IMAGE:$CRE_RELEASE"
|
||||||
when:
|
when:
|
||||||
branch: release/**
|
event:
|
||||||
|
- tag
|
||||||
trigger:
|
|
||||||
branch:
|
|
||||||
- develop
|
|
||||||
- release/**
|
|
||||||
- master
|
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
import {NgModule} from '@angular/core'
|
import {NgModule} from '@angular/core'
|
||||||
import {RouterModule, Routes} from '@angular/router'
|
import {RouterModule, Routes} from '@angular/router'
|
||||||
import {LogoutComponent} from './pages/logout/logout.component'
|
import {Login, Logout} from './accounts'
|
||||||
import {Login} from './accounts'
|
|
||||||
|
|
||||||
const routes: Routes = [{
|
const routes: Routes = [{
|
||||||
path: 'login',
|
path: 'login',
|
||||||
component: Login
|
component: Login
|
||||||
}, {
|
}, {
|
||||||
path: 'logout',
|
path: 'logout',
|
||||||
component: LogoutComponent
|
component: Logout
|
||||||
}, {
|
}, {
|
||||||
path: '',
|
path: '',
|
||||||
redirectTo: 'login'
|
redirectTo: 'login'
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
import {NgModule} from '@angular/core'
|
import {NgModule} from '@angular/core'
|
||||||
|
|
||||||
import {AccountsRoutingModule} from './accounts-routing.module'
|
import {AccountsRoutingModule} from './accounts-routing.module'
|
||||||
import {LoginComponent} from './pages/login/login.component'
|
|
||||||
import {SharedModule} from '../shared/shared.module'
|
import {SharedModule} from '../shared/shared.module'
|
||||||
import {LogoutComponent} from './pages/logout/logout.component'
|
import {Login, Logout} from './accounts'
|
||||||
import {Login} from './accounts'
|
|
||||||
import {CreInputsModule} from '../shared/components/inputs/inputs.module'
|
import {CreInputsModule} from '../shared/components/inputs/inputs.module'
|
||||||
import {CreButtonsModule} from '../shared/components/buttons/buttons.module'
|
import {CreButtonsModule} from '../shared/components/buttons/buttons.module'
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
LoginComponent,
|
Login,
|
||||||
LogoutComponent,
|
Logout
|
||||||
Login
|
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
SharedModule,
|
SharedModule,
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import {Component, HostListener, ViewChild} from '@angular/core'
|
import {Component, HostListener, ViewChild} from '@angular/core'
|
||||||
import {FormControl, Validators} from '@angular/forms'
|
import {FormControl, Validators} from '@angular/forms'
|
||||||
import {ErrorHandlingComponent} from '../shared/components/subscribing.component'
|
import {ErrorHandlingComponent, SubscribingComponent} from '../shared/components/subscribing.component'
|
||||||
import {AccountService} from './services/account.service'
|
import {AccountService} from './services/account.service'
|
||||||
import {AppState} from '../shared/app-state'
|
import {AppState} from '../shared/app-state'
|
||||||
import {ErrorHandler, ErrorService} from '../shared/service/error.service'
|
import {ErrorHandler, ErrorService} from '../shared/service/error.service'
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
import {CreForm, ICreForm} from "../shared/components/forms/forms";
|
import {CreForm, ICreForm} from "../shared/components/forms/forms";
|
||||||
import {take, takeUntil} from "rxjs/operators";
|
|
||||||
import {AlertService} from "../shared/service/alert.service";
|
import {AlertService} from "../shared/service/alert.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -61,3 +60,32 @@ export class Login extends ErrorHandlingComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'cre-logout',
|
||||||
|
template: ''
|
||||||
|
})
|
||||||
|
export class Logout extends SubscribingComponent {
|
||||||
|
constructor(
|
||||||
|
private accountService: AccountService,
|
||||||
|
private alertService: AlertService,
|
||||||
|
private appState: AppState,
|
||||||
|
errorService: ErrorService,
|
||||||
|
router: Router,
|
||||||
|
activatedRoute: ActivatedRoute
|
||||||
|
) {
|
||||||
|
super(errorService, activatedRoute, router)
|
||||||
|
this.appState.title = 'Connexion'
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
if (!this.appState.isAuthenticated) {
|
||||||
|
this.urlUtils.navigateTo('/account/login')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.subscribeAndNavigate(
|
||||||
|
this.accountService.logout(),
|
||||||
|
'/account/login'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
<form [formGroup]="form">
|
|
||||||
<mat-card class="x-centered y-centered">
|
|
||||||
<mat-card-header>
|
|
||||||
<mat-card-title>Connexion au système</mat-card-title>
|
|
||||||
</mat-card-header>
|
|
||||||
<mat-card-content>
|
|
||||||
<mat-form-field>
|
|
||||||
<mat-label>Numéro d'utilisateur</mat-label>
|
|
||||||
<input matInput [formControl]="idFormControl" type="text"/>
|
|
||||||
<mat-icon matSuffix>person</mat-icon>
|
|
||||||
<mat-error *ngIf="idFormControl.invalid">
|
|
||||||
<span *ngIf="idFormControl.errors.required">Un numéro d'utilisateur est requis</span>
|
|
||||||
<span *ngIf="idFormControl.errors.pattern">Le numéro d'utilisateur doit être un nombre</span>
|
|
||||||
</mat-error>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field>
|
|
||||||
<mat-label>Mot de passe</mat-label>
|
|
||||||
<input matInput [formControl]="passwordFormControl" type="password"/>
|
|
||||||
<mat-icon matSuffix>lock</mat-icon>
|
|
||||||
<mat-error *ngIf="passwordFormControl.invalid">
|
|
||||||
<span *ngIf="passwordFormControl.errors.required">Un mot de passe est requis</span>
|
|
||||||
</mat-error>
|
|
||||||
</mat-form-field>
|
|
||||||
</mat-card-content>
|
|
||||||
<mat-card-actions class="justify-content-end">
|
|
||||||
<button
|
|
||||||
mat-raised-button
|
|
||||||
type="submit"
|
|
||||||
color="accent"
|
|
||||||
[disabled]="form.invalid"
|
|
||||||
(click)="submit()">
|
|
||||||
Connexion
|
|
||||||
</button>
|
|
||||||
</mat-card-actions>
|
|
||||||
</mat-card>
|
|
||||||
</form>
|
|
|
@ -1,8 +0,0 @@
|
||||||
mat-card
|
|
||||||
width: 25rem
|
|
||||||
|
|
||||||
.alert p
|
|
||||||
margin: 0
|
|
||||||
|
|
||||||
mat-form-field
|
|
||||||
width: 100%
|
|
|
@ -1,55 +0,0 @@
|
||||||
import {Component, OnInit} from '@angular/core'
|
|
||||||
import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms'
|
|
||||||
import {AccountService} from '../../services/account.service'
|
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
|
||||||
import {ErrorService} from '../../../shared/service/error.service'
|
|
||||||
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
|
|
||||||
import {AppState} from '../../../shared/app-state'
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'cre-login',
|
|
||||||
templateUrl: './login.component.html',
|
|
||||||
styleUrls: ['./login.component.sass']
|
|
||||||
})
|
|
||||||
export class LoginComponent extends ErrorHandlingComponent implements OnInit {
|
|
||||||
form: FormGroup
|
|
||||||
idFormControl: FormControl
|
|
||||||
passwordFormControl: FormControl
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private formBuilder: FormBuilder,
|
|
||||||
private accountService: AccountService,
|
|
||||||
private appState: AppState,
|
|
||||||
errorService: ErrorService,
|
|
||||||
router: Router,
|
|
||||||
activatedRoute: ActivatedRoute
|
|
||||||
) {
|
|
||||||
super(errorService, activatedRoute, router)
|
|
||||||
this.appState.title = 'Connexion'
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.errorService.activeErrorHandler = this
|
|
||||||
|
|
||||||
if (this.appState.isAuthenticated) {
|
|
||||||
this.router.navigate(['/color'])
|
|
||||||
}
|
|
||||||
|
|
||||||
this.idFormControl = this.formBuilder.control(null, Validators.compose([Validators.required, Validators.pattern(new RegExp('^[0-9]+$'))]))
|
|
||||||
this.passwordFormControl = this.formBuilder.control(null, Validators.required)
|
|
||||||
this.form = this.formBuilder.group({
|
|
||||||
id: this.idFormControl,
|
|
||||||
password: this.passwordFormControl
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
submit() {
|
|
||||||
this.subscribe(
|
|
||||||
this.accountService.login(
|
|
||||||
this.idFormControl.value,
|
|
||||||
this.passwordFormControl.value
|
|
||||||
),
|
|
||||||
response => console.log(response)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
import {Component} from '@angular/core';
|
|
||||||
import {AccountService} from "../../services/account.service";
|
|
||||||
import {ActivatedRoute, Router} from "@angular/router";
|
|
||||||
import {AppState} from "../../../shared/app-state";
|
|
||||||
import {SubscribingComponent} from "../../../shared/components/subscribing.component";
|
|
||||||
import {ErrorService} from "../../../shared/service/error.service";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'cre-logout',
|
|
||||||
templateUrl: './logout.component.html',
|
|
||||||
styleUrls: ['./logout.component.sass']
|
|
||||||
})
|
|
||||||
export class LogoutComponent extends SubscribingComponent {
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private accountService: AccountService,
|
|
||||||
private appState: AppState,
|
|
||||||
errorService: ErrorService,
|
|
||||||
router: Router,
|
|
||||||
activatedRoute: ActivatedRoute
|
|
||||||
) {
|
|
||||||
super(errorService, activatedRoute, router)
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
if (!this.appState.isAuthenticated) {
|
|
||||||
this.urlUtils.navigateTo('/account/login')
|
|
||||||
}
|
|
||||||
|
|
||||||
this.subscribeAndNavigate(
|
|
||||||
this.accountService.logout(),
|
|
||||||
'/account/login'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -16,8 +16,8 @@
|
||||||
<button
|
<button
|
||||||
mat-raised-button
|
mat-raised-button
|
||||||
color="primary"
|
color="primary"
|
||||||
[disabled]="!hasSimdut"
|
[disabled]="!material.hasSimdut"
|
||||||
[attr.title]="!hasSimdut ? 'Ce produit n\'a pas de fiche signalitique' : null"
|
[attr.title]="!material.hasSimdut ? 'Ce produit n\'a pas de fiche signalitique' : null"
|
||||||
(click)="openSimdut()">
|
(click)="openSimdut()">
|
||||||
Voir la fiche signalitique
|
Voir la fiche signalitique
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -119,10 +119,6 @@ export class EditComponent extends ErrorHandlingComponent {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
get hasSimdut(): boolean {
|
|
||||||
return this.material.simdutUrl != null
|
|
||||||
}
|
|
||||||
|
|
||||||
openSimdut() {
|
openSimdut() {
|
||||||
openSimdut(this.material)
|
openSimdut(this.material)
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,7 +98,7 @@
|
||||||
|
|
||||||
<ng-container matColumnDef="simdutIcon">
|
<ng-container matColumnDef="simdutIcon">
|
||||||
<th mat-header-cell *matHeaderCellDef></th>
|
<th mat-header-cell *matHeaderCellDef></th>
|
||||||
<td mat-cell *matCellDef="let material" [class.disabled]="materialHasSimdut(material)">
|
<td mat-cell *matCellDef="let material" [class.disabled]="material.hasSimdut">
|
||||||
<mat-icon
|
<mat-icon
|
||||||
svgIcon="text-box-remove"
|
svgIcon="text-box-remove"
|
||||||
color="warn"
|
color="warn"
|
||||||
|
@ -123,7 +123,7 @@
|
||||||
<td mat-cell *matCellDef="let material; let i = index" [class.disabled]="canEditMaterial">
|
<td mat-cell *matCellDef="let material; let i = index" [class.disabled]="canEditMaterial">
|
||||||
<cre-accent-button
|
<cre-accent-button
|
||||||
[creInteractiveCell]="i"
|
[creInteractiveCell]="i"
|
||||||
[disabled]="!materialHasSimdut(material)"
|
[disabled]="!material.hasSimdut"
|
||||||
(click)="openSimdut(material)">
|
(click)="openSimdut(material)">
|
||||||
Fiche signalitique
|
Fiche signalitique
|
||||||
</cre-accent-button>
|
</cre-accent-button>
|
||||||
|
|
|
@ -64,7 +64,7 @@ export class InventoryComponent extends ErrorHandlingComponent {
|
||||||
super.ngOnInit()
|
super.ngOnInit()
|
||||||
|
|
||||||
this.subscribe(
|
this.subscribe(
|
||||||
this.materialService.allNotMixType,
|
this.materialService.all,
|
||||||
materials => this.materials = materials,
|
materials => this.materials = materials,
|
||||||
true,
|
true,
|
||||||
1
|
1
|
||||||
|
@ -94,10 +94,6 @@ export class InventoryComponent extends ErrorHandlingComponent {
|
||||||
return round(convertQuantity(material.inventoryQuantity, UNIT_MILLILITER, this.units), 2)
|
return round(convertQuantity(material.inventoryQuantity, UNIT_MILLILITER, this.units), 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
materialHasSimdut(material: Material): boolean {
|
|
||||||
return material.simdutUrl != null
|
|
||||||
}
|
|
||||||
|
|
||||||
openSimdut(material: Material) {
|
openSimdut(material: Material) {
|
||||||
openSimdut(material)
|
openSimdut(material)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,6 @@ export class MaterialService {
|
||||||
return this.api.get<Material[]>('/material')
|
return this.api.get<Material[]>('/material')
|
||||||
}
|
}
|
||||||
|
|
||||||
get allNotMixType(): Observable<Material[]> {
|
|
||||||
return this.api.get<Material[]>('/material/notmixtype')
|
|
||||||
}
|
|
||||||
|
|
||||||
getAllForMixCreation(recipeId: number): Observable<Material[]> {
|
getAllForMixCreation(recipeId: number): Observable<Material[]> {
|
||||||
return this.api.get<Material[]>(`/material/mix/create/${recipeId}`)
|
return this.api.get<Material[]>(`/material/mix/create/${recipeId}`)
|
||||||
}
|
}
|
||||||
|
@ -33,14 +29,6 @@ export class MaterialService {
|
||||||
return this.api.get<Material>(`/material/${id}`)
|
return this.api.get<Material>(`/material/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
hasSimdut(id: number): Observable<boolean> {
|
|
||||||
return this.api.get<boolean>(`/material/${id}/simdut/exists`)
|
|
||||||
}
|
|
||||||
|
|
||||||
getSimduts(): Observable<number[]> {
|
|
||||||
return this.api.get<number[]>('/material/simdut')
|
|
||||||
}
|
|
||||||
|
|
||||||
save(name: string, inventoryQuantity: number, materialType: number, simdutFile: FileInput): Observable<void> {
|
save(name: string, inventoryQuantity: number, materialType: number, simdutFile: FileInput): Observable<void> {
|
||||||
const body = new FormData()
|
const body = new FormData()
|
||||||
body.append('name', name)
|
body.append('name', name)
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
<mat-card *ngIf="editionMode || imagesUrls">
|
<mat-card *ngIf="editionMode || imagesIds">
|
||||||
<mat-card-header>
|
<mat-card-header>
|
||||||
<mat-card-title>Images</mat-card-title>
|
<mat-card-title>Images</mat-card-title>
|
||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
<mat-card-content [class.no-action]="!editionMode">
|
<mat-card-content [class.no-action]="!editionMode">
|
||||||
<div class="d-flex flex-row justify-content-around flex-wrap">
|
<div class="d-flex flex-row justify-content-around flex-wrap">
|
||||||
<p *ngIf="imagesUrls.length <= 0" class="light-text text-center mb-0">Aucune image n'est associée à cette couleur</p>
|
<p *ngIf="imagesIds.length <= 0" class="light-text text-center mb-0">Aucune image n'est associée à cette couleur</p>
|
||||||
|
|
||||||
<div *ngFor="let imageUrl of imagesUrls" class="d-flex flex-column align-self-center m-3">
|
<div *ngFor="let imageId of imagesIds" class="d-flex flex-column align-self-center m-3">
|
||||||
<div class="image-wrapper">
|
<div class="image-wrapper">
|
||||||
<img [src]="imageUrl" width="300px"/>
|
<img [src]="getImageUrl(imageId)" width="300px"/>
|
||||||
<div class="d-flex flex-row justify-content-end mt-2" [class.justify-content-between]="editionMode">
|
<div class="d-flex flex-row justify-content-end mt-2" [class.justify-content-between]="editionMode">
|
||||||
<button mat-raised-button color="primary" (click)="openImage(imageUrl)">Afficher</button>
|
<button mat-raised-button color="primary" (click)="openImage(imageId)">Afficher</button>
|
||||||
<button *ngIf="editionMode" mat-raised-button color="warn" (click)="delete(imageUrl)">Retirer</button>
|
<button *ngIf="editionMode" mat-raised-button color="warn" (click)="delete(imageId)">Retirer</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,7 +4,8 @@ import {SubscribingComponent} from '../../../shared/components/subscribing.compo
|
||||||
import {ActivatedRoute, Router} from '@angular/router'
|
import {ActivatedRoute, Router} from '@angular/router'
|
||||||
import {RecipeImageService} from '../../services/recipe-image.service'
|
import {RecipeImageService} from '../../services/recipe-image.service'
|
||||||
import {ErrorService} from '../../../shared/service/error.service'
|
import {ErrorService} from '../../../shared/service/error.service'
|
||||||
import {openJpg} from '../../../shared/utils/utils'
|
import {getImageUrl, openJpg} from '../../../shared/utils/utils'
|
||||||
|
import {RecipeService} from "../../services/recipe.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cre-images-editor',
|
selector: 'cre-images-editor',
|
||||||
|
@ -15,10 +16,11 @@ export class ImagesEditorComponent extends SubscribingComponent {
|
||||||
@Input() recipe: Recipe
|
@Input() recipe: Recipe
|
||||||
@Input() editionMode = false
|
@Input() editionMode = false
|
||||||
|
|
||||||
imagesUrls: string[]
|
imagesIds: string[] = []
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private recipeImageService: RecipeImageService,
|
private recipeImageService: RecipeImageService,
|
||||||
|
private recipeService: RecipeService,
|
||||||
errorService: ErrorService,
|
errorService: ErrorService,
|
||||||
router: Router,
|
router: Router,
|
||||||
activatedRoute: ActivatedRoute
|
activatedRoute: ActivatedRoute
|
||||||
|
@ -29,19 +31,26 @@ export class ImagesEditorComponent extends SubscribingComponent {
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
super.ngOnInit()
|
super.ngOnInit()
|
||||||
|
|
||||||
this.imagesUrls = this.recipe.imagesUrls
|
this.subscribe(
|
||||||
|
this.recipeService.getImagesIds(this.recipe.id),
|
||||||
|
imagesIds => this.imagesIds = imagesIds ?? []
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
submit(event) {
|
submit(event) {
|
||||||
const image = event.target.files[0]
|
const image = event.target.files[0]
|
||||||
this.subscribe(
|
this.subscribe(
|
||||||
this.recipeImageService.save(image, this.recipe.id),
|
this.recipeImageService.save(image, this.recipe.id),
|
||||||
r => this.imagesUrls = r.imagesUrls
|
imageId => this.imagesIds.push(imageId)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
openImage(url: string) {
|
getImageUrl(id: string): string {
|
||||||
openJpg(url)
|
return getImageUrl(this.getImagePath(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
openImage(id: string) {
|
||||||
|
openJpg(this.getImagePath(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(url: string) {
|
delete(url: string) {
|
||||||
|
@ -52,6 +61,10 @@ export class ImagesEditorComponent extends SubscribingComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
private removeUrl(url: string) {
|
private removeUrl(url: string) {
|
||||||
this.imagesUrls = this.imagesUrls.filter(u => u !== url)
|
this.imagesIds = this.imagesIds.filter(u => u !== url)
|
||||||
|
}
|
||||||
|
|
||||||
|
private getImagePath(id: string): string {
|
||||||
|
return `recipes/${this.recipe.id}/${id}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,7 @@
|
||||||
<button
|
<button
|
||||||
mat-raised-button
|
mat-raised-button
|
||||||
color="accent"
|
color="accent"
|
||||||
[disabled]="!hasSimdut(getMixMaterialFromDto(mixMaterial).material)"
|
[disabled]="!getMixMaterialFromDto(mixMaterial).material.hasSimdut"
|
||||||
(click)="openSimdut(getMixMaterialFromDto(mixMaterial))">
|
(click)="openSimdut(getMixMaterialFromDto(mixMaterial))">
|
||||||
Fiche signalitique
|
Fiche signalitique
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core'
|
import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core'
|
||||||
import {Mix, MixMaterial, MixMaterialDto, mixMaterialsToMixMaterialsDto, Recipe} from '../../../shared/model/recipe.model'
|
import {
|
||||||
|
Mix,
|
||||||
|
MixQuantity,
|
||||||
|
MixMaterialDto,
|
||||||
|
mixMaterialsToMixMaterialsDto,
|
||||||
|
Recipe
|
||||||
|
} from '../../../shared/model/recipe.model'
|
||||||
import {Subject} from 'rxjs'
|
import {Subject} from 'rxjs'
|
||||||
import {SubscribingComponent} from '../../../shared/components/subscribing.component'
|
import {SubscribingComponent} from '../../../shared/components/subscribing.component'
|
||||||
import {convertMixMaterialQuantity, UNIT_MILLILITER} from '../../../shared/units'
|
import {convertMixMaterialQuantity, UNIT_MILLILITER} from '../../../shared/units'
|
||||||
|
@ -37,7 +43,7 @@ export class MixTableComponent extends SubscribingComponent {
|
||||||
mixColumns = this.COLUMNS
|
mixColumns = this.COLUMNS
|
||||||
units = UNIT_MILLILITER
|
units = UNIT_MILLILITER
|
||||||
mixMaterials: MixMaterialDto[] = []
|
mixMaterials: MixMaterialDto[] = []
|
||||||
hoveredMixMaterial: MixMaterial | null
|
hoveredMixMaterial: MixQuantity | null
|
||||||
|
|
||||||
// BPac printer
|
// BPac printer
|
||||||
printer: PtouchPrinter | null
|
printer: PtouchPrinter | null
|
||||||
|
@ -68,11 +74,7 @@ export class MixTableComponent extends SubscribingComponent {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
hasSimdut(material: Material): boolean {
|
openSimdut(mixMaterial: MixQuantity) {
|
||||||
return material.simdutUrl != null
|
|
||||||
}
|
|
||||||
|
|
||||||
openSimdut(mixMaterial: MixMaterial) {
|
|
||||||
openSimdut(mixMaterial.material)
|
openSimdut(mixMaterial.material)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,8 +104,8 @@ export class MixTableComponent extends SubscribingComponent {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
getMixMaterialFromDto(mixMaterialDto: MixMaterialDto): MixMaterial {
|
getMixMaterialFromDto(mixMaterialDto: MixMaterialDto): MixQuantity {
|
||||||
return this.mix.mixMaterials.find(m => m.material.id === mixMaterialDto.materialId)
|
return this.mix.mixQuantities.find(m => m.material.id === mixMaterialDto.materialId)
|
||||||
}
|
}
|
||||||
|
|
||||||
getMixMaterialQuantityRounded(mixMaterial: MixMaterialDto): number {
|
getMixMaterialQuantityRounded(mixMaterial: MixMaterialDto): number {
|
||||||
|
@ -121,7 +123,7 @@ export class MixTableComponent extends SubscribingComponent {
|
||||||
return totalQuantity
|
return totalQuantity
|
||||||
}
|
}
|
||||||
|
|
||||||
getCalculatedQuantityHtml(mixMaterial: MixMaterial, index: number): string {
|
getCalculatedQuantityHtml(mixMaterial: MixQuantity, index: number): string {
|
||||||
const totalQuantity = this.round(this.getTotalQuantity(index))
|
const totalQuantity = this.round(this.getTotalQuantity(index))
|
||||||
const addedQuantity = this.round(this.calculateQuantity(index))
|
const addedQuantity = this.round(this.calculateQuantity(index))
|
||||||
return `<span class="mix-calculated-quantity">+${addedQuantity}</span> <span class="mix-calculated-quantity">(${totalQuantity})</span>`
|
return `<span class="mix-calculated-quantity">+${addedQuantity}</span> <span class="mix-calculated-quantity">(${totalQuantity})</span>`
|
||||||
|
@ -137,7 +139,7 @@ export class MixTableComponent extends SubscribingComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
async print() {
|
async print() {
|
||||||
const base = this.mix.mixMaterials
|
const base = this.mix.mixQuantities
|
||||||
.map(ma => ma.material)
|
.map(ma => ma.material)
|
||||||
.filter(m => m.materialType.name === 'Base')[0]
|
.filter(m => m.materialType.name === 'Base')[0]
|
||||||
if (!base) {
|
if (!base) {
|
||||||
|
@ -192,7 +194,8 @@ export class MixTableComponent extends SubscribingComponent {
|
||||||
quantity: this.calculateQuantity(index),
|
quantity: this.calculateQuantity(index),
|
||||||
isPercents: quantity.isPercents,
|
isPercents: quantity.isPercents,
|
||||||
position: quantity.position,
|
position: quantity.position,
|
||||||
units: UNIT_MILLILITER
|
units: UNIT_MILLILITER,
|
||||||
|
isMixType: false // TODO
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Images -->
|
<!-- Images -->
|
||||||
<div *ngIf="recipe.imagesUrls">
|
<div>
|
||||||
<cre-images-editor [recipe]="recipe" [editionMode]="false"></cre-images-editor>
|
<cre-images-editor [recipe]="recipe" [editionMode]="false"></cre-images-editor>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -143,7 +143,7 @@ export class CreRecipeExplore extends ErrorHandlingComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
deductMix() {
|
deductMix() {
|
||||||
const firstMixMaterial = this.recipe.mixes.filter(m => m.id === this.deductedMixId)[0].mixMaterials[0]
|
const firstMixMaterial = this.recipe.mixes.filter(m => m.id === this.deductedMixId)[0].mixQuantities[0]
|
||||||
if (this.quantitiesChanges.has(this.deductedMixId) && this.quantitiesChanges.get(this.deductedMixId).has(firstMixMaterial.material.id)) {
|
if (this.quantitiesChanges.has(this.deductedMixId) && this.quantitiesChanges.get(this.deductedMixId).has(firstMixMaterial.material.id)) {
|
||||||
const originalQuantity = firstMixMaterial.quantity
|
const originalQuantity = firstMixMaterial.quantity
|
||||||
const currentQuantity = this.quantitiesChanges.get(this.deductedMixId).get(firstMixMaterial.material.id)
|
const currentQuantity = this.quantitiesChanges.get(this.deductedMixId).get(firstMixMaterial.material.id)
|
||||||
|
|
|
@ -4,11 +4,8 @@
|
||||||
<cre-primary-button routerLink="/color/edit/{{recipe.id}}">Retour</cre-primary-button>
|
<cre-primary-button routerLink="/color/edit/{{recipe.id}}">Retour</cre-primary-button>
|
||||||
</cre-action-group>
|
</cre-action-group>
|
||||||
<cre-action-group>
|
<cre-action-group>
|
||||||
<cre-accent-button
|
<cre-warn-button (click)="deleteConfirmBox.show()">Supprimer</cre-warn-button>
|
||||||
[disabled]="!form.valid"
|
<cre-accent-button [disabled]="!form.valid" (click)="submit(form.formValues)">Enregistrer</cre-accent-button>
|
||||||
(click)="submit(form.formValues)">
|
|
||||||
Enregistrer
|
|
||||||
</cre-accent-button>
|
|
||||||
</cre-action-group>
|
</cre-action-group>
|
||||||
</cre-action-bar>
|
</cre-action-bar>
|
||||||
|
|
||||||
|
@ -22,4 +19,10 @@
|
||||||
Modification du mélange {{mix.mixType.name}} de la recette {{recipe.company.name}} - {{recipe.name}}
|
Modification du mélange {{mix.mixType.name}} de la recette {{recipe.company.name}} - {{recipe.name}}
|
||||||
</cre-form-title>
|
</cre-form-title>
|
||||||
</cre-mix-form>
|
</cre-mix-form>
|
||||||
|
|
||||||
|
<cre-confirm-box
|
||||||
|
#deleteConfirmBox
|
||||||
|
message="Voulez-vous vraiment supprimer le mélange {{mix.mixType.name}} de la recette {{recipe.company.name}} - {{recipe.name}}?"
|
||||||
|
(confirm)="delete()">
|
||||||
|
</cre-confirm-box>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
[mix]="mix"
|
[mix]="mix"
|
||||||
[mixMaterials]="mixMaterials"
|
[mixMaterials]="mixMaterials"
|
||||||
[control]="getControls(mixMaterial.position).materialId"
|
[control]="getControls(mixMaterial.position).materialId"
|
||||||
[materials]="allMaterials"
|
[materials]="allMaterialsValues"
|
||||||
[position]="mixMaterial.position">
|
[position]="mixMaterial.position">
|
||||||
</cre-mix-materials-form-combo-box>
|
</cre-mix-materials-form-combo-box>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -1,4 +1,13 @@
|
||||||
import {AfterViewInit, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, ViewChild, ViewChildren} from '@angular/core'
|
import {
|
||||||
|
AfterViewInit,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
Component,
|
||||||
|
Input,
|
||||||
|
OnDestroy,
|
||||||
|
OnInit,
|
||||||
|
ViewChild,
|
||||||
|
ViewChildren
|
||||||
|
} from '@angular/core'
|
||||||
import {CreTable} from '../../shared/components/tables/tables'
|
import {CreTable} from '../../shared/components/tables/tables'
|
||||||
import {Mix, MixMaterialDto, mixMaterialsToMixMaterialsDto, sortMixMaterialsDto} from '../../shared/model/recipe.model'
|
import {Mix, MixMaterialDto, mixMaterialsToMixMaterialsDto, sortMixMaterialsDto} from '../../shared/model/recipe.model'
|
||||||
import {Observable, Subject} from 'rxjs'
|
import {Observable, Subject} from 'rxjs'
|
||||||
|
@ -38,10 +47,6 @@ export class MixMaterialsFormComboBox implements OnInit {
|
||||||
private filterMaterials(): CreInputEntry[] {
|
private filterMaterials(): CreInputEntry[] {
|
||||||
return this.materials
|
return this.materials
|
||||||
.filter(material => {
|
.filter(material => {
|
||||||
if (this.mix && this.mix.mixType.material.id === material.id) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prevent use of percents in first position
|
// Prevent use of percents in first position
|
||||||
if (material.materialType.usePercentages && this.mixMaterial.position <= 1) {
|
if (material.materialType.usePercentages && this.mixMaterial.position <= 1) {
|
||||||
return false
|
return false
|
||||||
|
@ -54,7 +59,18 @@ export class MixMaterialsFormComboBox implements OnInit {
|
||||||
return this.mixMaterials.filter(x => x.materialId === material.id).length <= 0
|
return this.mixMaterials.filter(x => x.materialId === material.id).length <= 0
|
||||||
})
|
})
|
||||||
.sort(materialComparator)
|
.sort(materialComparator)
|
||||||
.map(material => new CreInputEntry(material.id, material.name, material.materialType.prefix ? `[${material.materialType.prefix}] ${material.name}` : material.name))
|
.map(this.materialAsInputEntry)
|
||||||
|
}
|
||||||
|
|
||||||
|
private materialAsInputEntry(material: Material): CreInputEntry {
|
||||||
|
return new CreInputEntry(
|
||||||
|
material.id,
|
||||||
|
material.name,
|
||||||
|
material.materialType.prefix ? `[${material.materialType.prefix}] ${material.name}` : material.name,
|
||||||
|
{
|
||||||
|
bold: material.isMixType
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +87,8 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy {
|
||||||
|
|
||||||
mixMaterials: MixMaterialDto[] = []
|
mixMaterials: MixMaterialDto[] = []
|
||||||
columns = ['position', 'positionButtons', 'material', 'quantity', 'units', 'endButton']
|
columns = ['position', 'positionButtons', 'material', 'quantity', 'units', 'endButton']
|
||||||
allMaterials: Material[]
|
allMaterials = new Map<number, Material>();
|
||||||
|
allMaterialsValues = [];
|
||||||
|
|
||||||
private _controls: ControlsByPosition[] = []
|
private _controls: ControlsByPosition[] = []
|
||||||
private _destroy$ = new Subject<boolean>()
|
private _destroy$ = new Subject<boolean>()
|
||||||
|
@ -85,7 +102,9 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy {
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
this.materials.subscribe({
|
this.materials.subscribe({
|
||||||
next: materials => {
|
next: materials => {
|
||||||
this.allMaterials = materials
|
this.allMaterials.clear()
|
||||||
|
this.allMaterialsValues = materials
|
||||||
|
materials.forEach(m => this.allMaterials.set(m.id, m))
|
||||||
|
|
||||||
if (!this.mix) {
|
if (!this.mix) {
|
||||||
this.addRow()
|
this.addRow()
|
||||||
|
@ -105,7 +124,7 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
addRow() {
|
addRow() {
|
||||||
const mixMaterial = new MixMaterialDto(null, 0, false, this.nextPosition, UNIT_MILLILITER)
|
const mixMaterial = new MixMaterialDto(null, 0, false, this.nextPosition, UNIT_MILLILITER, false)
|
||||||
this.insertRow(mixMaterial)
|
this.insertRow(mixMaterial)
|
||||||
this.table.renderRows()
|
this.table.renderRows()
|
||||||
}
|
}
|
||||||
|
@ -170,7 +189,7 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return mixMaterial.materialId ? this.allMaterials?.filter(x => x.id === mixMaterial.materialId)[0].materialType.usePercentages : false
|
return mixMaterial.materialId ? this.allMaterials.get(mixMaterial.materialId)?.materialType.usePercentages : false
|
||||||
}
|
}
|
||||||
|
|
||||||
isDecreasePositionButtonDisabled(mixMaterial: MixMaterialDto): boolean {
|
isDecreasePositionButtonDisabled(mixMaterial: MixMaterialDto): boolean {
|
||||||
|
@ -195,19 +214,23 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
get materialCount(): number {
|
get materialCount(): number {
|
||||||
return this.allMaterials ? this.allMaterials.length : 0
|
return this.allMaterials.size
|
||||||
}
|
}
|
||||||
|
|
||||||
get updatedMixMaterials(): MixMaterialDto[] {
|
get updatedMixMaterials(): MixMaterialDto[] {
|
||||||
const updatedMixMaterials: MixMaterialDto[] = []
|
const updatedMixMaterials: MixMaterialDto[] = []
|
||||||
this.mixMaterials.forEach(mixMaterial => {
|
this.mixMaterials.forEach(mixMaterial => {
|
||||||
const controls = this.getControlsByPosition(mixMaterial.position).controls
|
const controls = this.getControlsByPosition(mixMaterial.position).controls
|
||||||
|
const materialId = controls.materialId.value;
|
||||||
|
const material = this.allMaterials.get(materialId)
|
||||||
|
|
||||||
updatedMixMaterials.push({
|
updatedMixMaterials.push({
|
||||||
materialId: controls.materialId.value,
|
...mixMaterial,
|
||||||
|
materialId,
|
||||||
quantity: controls.quantity.value,
|
quantity: controls.quantity.value,
|
||||||
position: mixMaterial.position,
|
|
||||||
units: controls.units.value,
|
units: controls.units.value,
|
||||||
isPercents: this.areUnitsPercents(mixMaterial)
|
isPercents: material.materialType.usePercentages,
|
||||||
|
isMixType: material.isMixType
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
return updatedMixMaterials
|
return updatedMixMaterials
|
||||||
|
|
|
@ -27,7 +27,7 @@ abstract class _BaseMixPage extends SubscribingComponent {
|
||||||
protected mixService: MixService,
|
protected mixService: MixService,
|
||||||
private recipeService: RecipeService,
|
private recipeService: RecipeService,
|
||||||
private materialTypeService: MaterialTypeService,
|
private materialTypeService: MaterialTypeService,
|
||||||
private materialService: MaterialService,
|
protected materialService: MaterialService,
|
||||||
errorService: ErrorService,
|
errorService: ErrorService,
|
||||||
router: Router,
|
router: Router,
|
||||||
activatedRoute: ActivatedRoute
|
activatedRoute: ActivatedRoute
|
||||||
|
@ -50,13 +50,15 @@ abstract class _BaseMixPage extends SubscribingComponent {
|
||||||
|
|
||||||
set recipe(recipe: Recipe) {
|
set recipe(recipe: Recipe) {
|
||||||
this._recipe = recipe
|
this._recipe = recipe
|
||||||
this.materials$ = this.materialService.getAllForMixCreation(recipe.id)
|
this.materials$ = this.fetchMaterials(recipe.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
get recipe(): Recipe {
|
get recipe(): Recipe {
|
||||||
return this._recipe
|
return this._recipe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract fetchMaterials(recipeId: number): Observable<Material[]>
|
||||||
|
|
||||||
abstract submit(dto: MixSaveDto)
|
abstract submit(dto: MixSaveDto)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +67,10 @@ abstract class _BaseMixPage extends SubscribingComponent {
|
||||||
templateUrl: 'add.html'
|
templateUrl: 'add.html'
|
||||||
})
|
})
|
||||||
export class MixAdd extends _BaseMixPage {
|
export class MixAdd extends _BaseMixPage {
|
||||||
|
protected fetchMaterials(recipeId: number): Observable<Material[]> {
|
||||||
|
return this.materialService.getAllForMixCreation(recipeId)
|
||||||
|
}
|
||||||
|
|
||||||
submit(dto: MixSaveDto) {
|
submit(dto: MixSaveDto) {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.mixService.saveDto(dto),
|
this.mixService.saveDto(dto),
|
||||||
|
@ -80,27 +86,40 @@ export class MixAdd extends _BaseMixPage {
|
||||||
export class MixEdit extends _BaseMixPage {
|
export class MixEdit extends _BaseMixPage {
|
||||||
mix: Mix
|
mix: Mix
|
||||||
|
|
||||||
|
private mixId: number
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
super.ngOnInit()
|
super.ngOnInit()
|
||||||
|
|
||||||
|
this.mixId = this.urlUtils.parseIntUrlParam('id')
|
||||||
|
|
||||||
this.fetchMix()
|
this.fetchMix()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fetchMix() {
|
private fetchMix() {
|
||||||
const mixId = this.urlUtils.parseIntUrlParam('id')
|
|
||||||
|
|
||||||
this.subscribe(
|
this.subscribe(
|
||||||
this.mixService.getById(mixId),
|
this.mixService.getById(this.mixId),
|
||||||
mix => this.mix = mix
|
mix => this.mix = mix
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fetchMaterials(recipeId: number): Observable<Material[]> {
|
||||||
|
return this.materialService.getAllForMixUpdate(this.mixId)
|
||||||
|
}
|
||||||
|
|
||||||
submit(dto: MixSaveDto) {
|
submit(dto: MixSaveDto) {
|
||||||
this.subscribeAndNavigate(
|
this.subscribeAndNavigate(
|
||||||
this.mixService.updateDto({...dto, id: this.mix.id}),
|
this.mixService.updateDto({...dto, id: this.mix.id}),
|
||||||
`/color/edit/${this.recipe.id}`
|
`/color/edit/${this.recipe.id}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete() {
|
||||||
|
this.subscribeAndNavigate(
|
||||||
|
this.mixService.delete(this.mixId),
|
||||||
|
'/color/edit/' + this.recipe.id
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -126,7 +145,7 @@ export class MixInfoForm implements OnInit {
|
||||||
|
|
||||||
this.controls = {
|
this.controls = {
|
||||||
name: new FormControl(this.mix?.mixType.name, Validators.required),
|
name: new FormControl(this.mix?.mixType.name, Validators.required),
|
||||||
materialType: new FormControl(this.mix?.mixType.material.materialType.id, Validators.required)
|
materialType: new FormControl(this.mix?.mixType.materialType.id, Validators.required)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +180,7 @@ export class MixForm {
|
||||||
name: this.infoForm.mixName,
|
name: this.infoForm.mixName,
|
||||||
recipeId: this.recipe.id,
|
recipeId: this.recipe.id,
|
||||||
materialTypeId: this.infoForm.mixMaterialTypeId,
|
materialTypeId: this.infoForm.mixMaterialTypeId,
|
||||||
mixMaterials: this.mixMaterialsForm.updatedMixMaterials
|
mixQuantities: this.mixMaterialsForm.updatedMixMaterials
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ export class MixService {
|
||||||
dto.name,
|
dto.name,
|
||||||
dto.recipeId,
|
dto.recipeId,
|
||||||
dto.materialTypeId,
|
dto.materialTypeId,
|
||||||
dto.mixMaterials,
|
dto.mixQuantities,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ export class MixService {
|
||||||
name,
|
name,
|
||||||
recipeId,
|
recipeId,
|
||||||
materialTypeId,
|
materialTypeId,
|
||||||
mixMaterials: []
|
mixQuantities: []
|
||||||
}
|
}
|
||||||
this.appendMixMaterialsToBody(mixMaterials, body)
|
this.appendMixMaterialsToBody(mixMaterials, body)
|
||||||
return this.api.post('/recipe/mix', body)
|
return this.api.post('/recipe/mix', body)
|
||||||
|
@ -50,7 +50,7 @@ export class MixService {
|
||||||
dto.id,
|
dto.id,
|
||||||
dto.name,
|
dto.name,
|
||||||
dto.materialTypeId,
|
dto.materialTypeId,
|
||||||
dto.mixMaterials
|
dto.mixQuantities
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ export class MixService {
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
materialTypeId,
|
materialTypeId,
|
||||||
mixMaterials: []
|
mixQuantities: []
|
||||||
}
|
}
|
||||||
|
|
||||||
this.appendMixMaterialsToBody(mixMaterials, body)
|
this.appendMixMaterialsToBody(mixMaterials, body)
|
||||||
|
@ -84,10 +84,11 @@ export class MixService {
|
||||||
|
|
||||||
private appendMixMaterialsToBody(mixMaterials: MixMaterialDto[], body: any) {
|
private appendMixMaterialsToBody(mixMaterials: MixMaterialDto[], body: any) {
|
||||||
mixMaterials.filter(m => m.materialId != null && m.quantity != null).forEach(m => {
|
mixMaterials.filter(m => m.materialId != null && m.quantity != null).forEach(m => {
|
||||||
body.mixMaterials.push({
|
body.mixQuantities.push({
|
||||||
materialId: m.materialId,
|
materialId: m.materialId,
|
||||||
quantity: m.quantity,
|
quantity: m.quantity,
|
||||||
position: m.position
|
position: m.position,
|
||||||
|
isMixType: m.isMixType
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -97,13 +98,13 @@ export interface MixSaveDto {
|
||||||
name: string
|
name: string
|
||||||
recipeId: number
|
recipeId: number
|
||||||
materialTypeId: number
|
materialTypeId: number
|
||||||
mixMaterials: MixMaterialDto[]
|
mixQuantities: MixMaterialDto[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MixUpdateDto {
|
export interface MixUpdateDto {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
materialTypeId: number
|
materialTypeId: number
|
||||||
mixMaterials: MixMaterialDto[]
|
mixQuantities: MixMaterialDto[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,10 +12,10 @@ export class RecipeImageService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
save(image: File, recipeId: number): Observable<Recipe> {
|
save(image: File, recipeId: number): Observable<string> {
|
||||||
const body = new FormData()
|
const body = new FormData()
|
||||||
body.append('image', image)
|
body.append('image', image)
|
||||||
return this.api.put<Recipe>(`/recipe/${recipeId}/image`, body)
|
return this.api.put<string>(`/recipe/${recipeId}/image`, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(url: string, recipeId: number): Observable<void> {
|
delete(url: string, recipeId: number): Observable<void> {
|
||||||
|
|
|
@ -84,4 +84,8 @@ export class RecipeService {
|
||||||
delete(id: number): Observable<void> {
|
delete(id: number): Observable<void> {
|
||||||
return this.api.delete<void>(`/recipe/${id}`)
|
return this.api.delete<void>(`/recipe/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getImagesIds(id: number): Observable<string[]> {
|
||||||
|
return this.api.get<string[]>(`/recipe/${id}/image`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,11 @@
|
||||||
</mat-error>
|
</mat-error>
|
||||||
|
|
||||||
<mat-autocomplete #auto="matAutocomplete">
|
<mat-autocomplete #auto="matAutocomplete">
|
||||||
<mat-option *ngFor="let entry of filteredEntries" [value]="entry.value">
|
<mat-option
|
||||||
|
*ngFor="let entry of filteredEntries"
|
||||||
|
[value]="entry.value"
|
||||||
|
[class.font-weight-bold]="entry.styleOptions?.bold"
|
||||||
|
[title]="entry.value">
|
||||||
{{entry.display ? entry.display : entry.value}}
|
{{entry.display ? entry.display : entry.value}}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-autocomplete>
|
</mat-autocomplete>
|
||||||
|
|
|
@ -167,7 +167,6 @@ export class CreComboBoxComponent {
|
||||||
|
|
||||||
internalControl: FormControl
|
internalControl: FormControl
|
||||||
filteredEntries: CreInputEntry[]
|
filteredEntries: CreInputEntry[]
|
||||||
validValue = false
|
|
||||||
|
|
||||||
private _destroy$ = new Subject<boolean>()
|
private _destroy$ = new Subject<boolean>()
|
||||||
private _entries: CreInputEntry[]
|
private _entries: CreInputEntry[]
|
||||||
|
@ -466,11 +465,16 @@ export class CreInputEntry {
|
||||||
constructor(
|
constructor(
|
||||||
public key: any,
|
public key: any,
|
||||||
public value: any,
|
public value: any,
|
||||||
public display?: any
|
public display?: any,
|
||||||
|
public styleOptions?: CreInputEntryStyleOptions
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CreInputEntryStyleOptions {
|
||||||
|
bold?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export function chipListRequired(): ValidatorFn {
|
export function chipListRequired(): ValidatorFn {
|
||||||
return (control: AbstractControl): ValidationErrors | null => {
|
return (control: AbstractControl): ValidationErrors | null => {
|
||||||
return !control.value || control.value.length <= 0 ? {required: true} : null
|
return !control.value || control.value.length <= 0 ? {required: true} : null
|
||||||
|
|
|
@ -7,13 +7,14 @@ export class Material {
|
||||||
public name: string,
|
public name: string,
|
||||||
public inventoryQuantity: number,
|
public inventoryQuantity: number,
|
||||||
public materialType: MaterialType,
|
public materialType: MaterialType,
|
||||||
public simdutUrl: string
|
public isMixType: boolean,
|
||||||
|
public hasSimdut: boolean
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function openSimdut(material: Material) {
|
export function openSimdut(material: Material) {
|
||||||
openPdf(material.simdutUrl)
|
openPdf(`simdut/${material.name}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const materialComparator = (a: Material, b: Material): number => {
|
export const materialComparator = (a: Material, b: Material): number => {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import {Material} from './material.model'
|
||||||
import {Company} from './company.model'
|
import {Company} from './company.model'
|
||||||
import {Group} from './user'
|
import {Group} from './user'
|
||||||
import {UNIT_MILLILITER} from "../units";
|
import {UNIT_MILLILITER} from "../units";
|
||||||
|
import {MaterialType} from "./materialtype.model";
|
||||||
|
|
||||||
export class Recipe {
|
export class Recipe {
|
||||||
public id: number
|
public id: number
|
||||||
|
@ -16,7 +17,6 @@ export class Recipe {
|
||||||
public mixes: Mix[]
|
public mixes: Mix[]
|
||||||
public approbationExpired: boolean
|
public approbationExpired: boolean
|
||||||
public groupsInformation: RecipeGroupInformation[]
|
public groupsInformation: RecipeGroupInformation[]
|
||||||
public imagesUrls: string[]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RecipeGroupInformation {
|
export class RecipeGroupInformation {
|
||||||
|
@ -33,13 +33,13 @@ export class Mix {
|
||||||
constructor(
|
constructor(
|
||||||
public id: number,
|
public id: number,
|
||||||
public mixType: MixType,
|
public mixType: MixType,
|
||||||
public mixMaterials: MixMaterial[],
|
public mixQuantities: MixQuantity[],
|
||||||
public location: string,
|
public location: string,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MixMaterial {
|
export class MixQuantity {
|
||||||
constructor(
|
constructor(
|
||||||
public id: number,
|
public id: number,
|
||||||
public material: Material,
|
public material: Material,
|
||||||
|
@ -55,7 +55,8 @@ export class MixMaterialDto {
|
||||||
public quantity: number,
|
public quantity: number,
|
||||||
public isPercents: boolean,
|
public isPercents: boolean,
|
||||||
public position: number,
|
public position: number,
|
||||||
public units: string
|
public units: string,
|
||||||
|
public isMixType: boolean
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +65,7 @@ class MixType {
|
||||||
constructor(
|
constructor(
|
||||||
public id: number,
|
public id: number,
|
||||||
public name: string,
|
public name: string,
|
||||||
public material: Material
|
public materialType: MaterialType
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,12 +102,13 @@ export function sortRecipeSteps(steps: RecipeStep[]): RecipeStep[] {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mixMaterialsToMixMaterialsDto(mix: Mix): MixMaterialDto[] {
|
export function mixMaterialsToMixMaterialsDto(mix: Mix): MixMaterialDto[] {
|
||||||
return sortMixMaterialsDto(mix.mixMaterials.map(m => new MixMaterialDto(
|
return sortMixMaterialsDto(mix.mixQuantities.map(m => new MixMaterialDto(
|
||||||
m.material.id,
|
m.material.id,
|
||||||
m.quantity,
|
m.quantity,
|
||||||
m.material.materialType.usePercentages,
|
m.material.materialType.usePercentages,
|
||||||
m.position,
|
m.position,
|
||||||
UNIT_MILLILITER
|
UNIT_MILLILITER,
|
||||||
|
m.material.isMixType
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,20 +10,28 @@ export function valueOr<T>(value: T, or: T): T {
|
||||||
const MEDIA_TYPE_PDF = 'application/pdf'
|
const MEDIA_TYPE_PDF = 'application/pdf'
|
||||||
const MEDIA_TYPE_JPG = 'image/jpeg'
|
const MEDIA_TYPE_JPG = 'image/jpeg'
|
||||||
|
|
||||||
export function openPdf(url: string) {
|
export function getImageUrl(path: string): string {
|
||||||
openUrl(url, MEDIA_TYPE_PDF)
|
return getFileUri(`images/${path}`, MEDIA_TYPE_JPG)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function openJpg(url: string) {
|
export function getFileUri(path: string, mediaType: string): string {
|
||||||
openUrl(url, MEDIA_TYPE_JPG)
|
return `${environment.apiUrl}/file?path=${encodeURIComponent(path)}&mediaType=${encodeURIComponent(mediaType)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function openPdf(path: string) {
|
||||||
|
openFileUri(`pdf/${path}.pdf`, MEDIA_TYPE_PDF)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function openJpg(path: string) {
|
||||||
|
openFileUri(`images/${path}`, MEDIA_TYPE_JPG)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function openTouchUpKit(touchUpKit: TouchUpKit) {
|
export function openTouchUpKit(touchUpKit: TouchUpKit) {
|
||||||
openRawUrl(`${environment.apiUrl}/touchupkit/pdf?project=${touchUpKit.project}`)
|
openRawUrl(`${environment.apiUrl}/touchupkit/pdf?project=${touchUpKit.project}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function openUrl(url: string, mediaType: string) {
|
export function openFileUri(path: string, mediaType: string) {
|
||||||
openRawUrl(`${url}&mediaType=${encodeURIComponent(mediaType)}`)
|
openRawUrl(getFileUri(path, mediaType))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function openRawUrl(url: string) {
|
export function openRawUrl(url: string) {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: true,
|
production: true,
|
||||||
|
apiBaseUrl: window.location.origin,
|
||||||
apiUrl: window.location.origin + '/api'
|
apiUrl: window.location.origin + '/api'
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: false,
|
production: false,
|
||||||
|
apiBaseUrl: 'http://localhost:9090',
|
||||||
apiUrl: 'http://localhost:9090/api'
|
apiUrl: 'http://localhost:9090/api'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue