Skip to content
Snippets Groups Projects
Commit fa979bfe authored by FORESTIER Fabien's avatar FORESTIER Fabien
Browse files

Creation of resource Format in resource view

parent 912f5ee9
No related branches found
No related tags found
1 merge request!1version 1.0.0
Pipeline #
...@@ -27,4 +27,4 @@ ...@@ -27,4 +27,4 @@
</div> </div>
</div> </div>
</section> </section>
</ng-container> </ng-container>
\ No newline at end of file
<ng-container *ngIf="format"> <ng-container *ngIf="format">
<app-back-button [route]="'/organizations'" [title]="'Retourner à la liste des formats'"></app-back-button> <app-back-button [route]="'/formats'" [title]="'Retourner à la liste des formats'"></app-back-button>
<h1>{{ title }}</h1> <h1>{{ title }}</h1>
...@@ -21,9 +21,15 @@ ...@@ -21,9 +21,15 @@
</div> </div>
<div class="field"> <div class="field">
<label class="label" for="mapServerType">Type MapServer</label> <label class="label required" for="mapServerType">Type MapServer</label>
<div class="control"> <div class="control">
<input class="input" type="text" [value]="format.mapServerType" formControlName="mapServerType" id="mapServerType"> <input class="input" type="text" [value]="format.mapServerType" formControlName="mapServerType"
id="mapServerType">
</div>
<div *ngIf="mapServerType.invalid && (mapServerType.dirty || mapServerType.touched)" class="alert alert-danger">
<p *ngIf="mapServerType.errors['required']" class="help is-danger">
Le nom du type MapServer est obligatoire.
</p>
</div> </div>
</div> </div>
...@@ -32,4 +38,4 @@ ...@@ -32,4 +38,4 @@
</div> </div>
</div> </div>
</form> </form>
</ng-container> </ng-container>
\ No newline at end of file
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
</p> </p>
</header> </header>
<div class="card-content"> <div class="card-content">
<div class="content"> <div class="content">
<p> <p>
<span class="has-text-weight-bold">Id: </span> <span class="has-text-weight-bold">Id: </span>
...@@ -20,67 +19,88 @@ ...@@ -20,67 +19,88 @@
</p> </p>
<p> <p>
<span class="has-text-weight-bold">Acronyme: </span> <span class="has-text-weight-bold">Acronyme: </span>
<span>{{resource.acronym}}</span> <span *ngIf="resource.acronym; else emptyAcronymWarning">{{resource.acronym}}</span>
<ng-template #emptyAcronymWarning>
<span class="empty-property">Non renseigné</span>
</ng-template>
</p> </p>
<p> <p>
<span class="has-text-weight-bold">Type: </span> <span class="has-text-weight-bold">Type: </span>
<span>{{resource.type}}</span> <span *ngIf="resource.type; else emptyTypeWarning">{{resource.type}}</span>
<ng-template #emptyTypeWarning>
<span class="empty-property">Non renseigné</span>
</ng-template>
</p> </p>
<div *ngIf="resource.description"> <div *ngIf="resource.description">
<p class="has-text-weight-bold">Description:</p> <span class="has-text-weight-bold">Description: </span>
<p>{{resource.description}}</p> <span *ngIf="resource.description; else emptyDescriptionWarning">{{resource.description}}</span>
<ng-template #emptyDescriptionWarning>
<span class="empty-property">Non renseigné</span>
</ng-template>
</div> </div>
<br> <br>
<p> <p>
<span class="has-text-weight-bold">Requêtable:</span> <span class="has-text-weight-bold">Requêtable: </span>
<span class="icon has-text-success" *ngIf="resource.isQueryable"> <span class="icon has-text-success"
<i class="far fa-check-circle"></i> [ngClass]="{'has-text-success': resource.isQueryable, 'has-text-danger': !resource.isQueryable}">
</span> <i class="far fa-check-circle"
<span class="icon has-text-danger" *ngIf="!resource.isQueryable"> [ngClass]="{'fa-check-circle': resource.isQueryable, 'fa-times-circle': !resource.isQueryable}"></i>
<i class="far fa-times-circle"></i>
</span> </span>
</p> </p>
<p> <p>
<span class="has-text-weight-bold">Téléchargeable:</span> <span class="has-text-weight-bold">Téléchargeable: </span>
<span class="icon has-text-success" *ngIf="resource.isDownloadable"> <span class="icon has-text-success"
<i class="far fa-check-circle"></i> [ngClass]="{'has-text-success': resource.isDownloadable, 'has-text-danger': !resource.isDownloadable}">
</span> <i class="far fa-check-circle"
<span class="icon has-text-danger" *ngIf="!resource.isDownloadable"> [ngClass]="{'fa-check-circle': resource.isDownloadable, 'fa-times-circle': !resource.isDownloadable}"></i>
<i class="far fa-times-circle"></i>
</span> </span>
</p> </p>
<p> <p>
<span class="has-text-weight-bold">Standardisé:</span> <span class="has-text-weight-bold">Standardisé: </span>
<span class="icon has-text-success" *ngIf="resource.isStandard"> <span class="icon has-text-success"
<i class="far fa-check-circle"></i> [ngClass]="{'has-text-success': resource.isStandard, 'has-text-danger': !resource.isStandard}">
</span> <i class="far fa-check-circle"
<span class="icon has-text-danger" *ngIf="!resource.isStandard"> [ngClass]="{'fa-check-circle': resource.isStandard, 'fa-times-circle': !resource.isStandard}"></i>
<i class="far fa-times-circle"></i>
</span> </span>
</p> </p>
<div *ngIf="resource.description"> <div *ngIf="resource.parametersUrl">
<p class="has-text-weight-bold">Parametres URL:</p> <span class="has-text-weight-bold">Parametres URL: </span>
<p>{{resource.parametersUrl}}</p> <span *ngIf="resource.parametersUrl; else emptyParameterUrlWarning">{{resource.parametersUrl}}</span>
<ng-template #emptyParameterUrlWarning>
<span class="empty-property">Non renseigné</span>
</ng-template>
</div> </div>
<br> <br>
<div *ngIf="resource.description"> <div *ngIf="resource.messageWarning">
<p class="has-text-weight-bold">Message d'alerte:</p> <span class="has-text-weight-bold">Message d'alerte: </span>
<p>{{resource.messageWarning}}</p> <span *ngIf="resource.messageWarning; else emptyMessageWarning">{{resource.messageWarning}}</span>
<ng-template #emptyMessageWarning>
<span class="empty-property">Non renseigné</span>
</ng-template>
</div> </div>
<br> <br>
<!-- <div> <div>
<span class="has-text-weight-bold">Formats de sortie: </span> <span class="has-text-weight-bold">Formats de sortie: </span>
<span *ngFor="let format of resource.outputFormats; let isLast=last"> <ul
{{ format }}{{ isLast ? '' : ',' }} *ngIf="resource.resourceFormats && resource.resourceFormats.length > 0; else noResourceFormatTemplate">
</span> <li *ngFor="let resourceFormat of resource.resourceFormats">
</div> --> {{ resourceFormat.format.name }}<span *ngIf="resourceFormat.isCuttable">, découpable</span><span
*ngIf="resourceFormat.isProjectable">, projectable</span>
</li>
</ul>
<ng-template #noResourceFormatTemplate>
<span class="empty-property">Non renseigné</span>
</ng-template>
</div>
</div> </div>
</div> </div>
...@@ -92,4 +112,4 @@ ...@@ -92,4 +112,4 @@
</section> </section>
</ng-container> </ng-container>
\ No newline at end of file
.card-header-title { .card-header-title {
justify-content: center; justify-content: center;
} }
\ No newline at end of file
.empty-property {
font-style: italic;
color: #818080;
}
...@@ -103,13 +103,73 @@ ...@@ -103,13 +103,73 @@
</div> </div>
</div> </div>
<div class="field links">
<!-- <div class="field"> <div class="columns">
<label class="label" for="outputFormats">Formats de sortie (Séparer chaque format par une virgule)</label> <div class="column is-11">
<div class="control"> <label class="label">Formats</label>
<input class="input" type="text" formControlName="outputFormats" id="outputFormats"> </div>
<div class="column is-1">
<span class="icon" (click)="addResourceFormat()" title="Ajouter un format">
<i class="fas fa-plus"></i>
</span>
</div>
</div>
<div formArrayName="resourceFormats">
<div *ngFor="let resourceFormat of formResourceFormats.controls; let i = index;" [formGroupName]="i"
class="columns is-multiline">
<div class="field column is-5">
<label class="label required" for="format">Format</label>
<div class="control">
<div class="select">
<select formControlName="formatId">
<option [ngValue]="format.id" *ngFor="let format of formatsList"> {{format.name}}</option>
</select>
</div>
</div>
<div
*ngIf="resourceFormat['controls'].formatId.invalid && (resourceFormat['controls'].formatId.dirty || resourceFormat['controls'].formatId.touched)"
class="alert alert-danger">
<p *ngIf="resourceFormat.hasError('required', 'format')" class="help is-danger">
Le format est requis.
</p>
</div>
</div>
<div class="field column is-3">
<label class="label required" for="isProjectable">Projectable</label>
<div class="control">
<label class="radio">
<input type="radio" formControlName="isProjectable" [value]="1">
Oui
</label>
<label class="radio">
<input type="radio" formControlName="isProjectable" [value]="0">
Non
</label>
</div>
</div>
<div class="field column is-3">
<label class="label required" for="isCuttable">Découpable</label>
<div class="control">
<label class="radio">
<input type="radio" formControlName="isCuttable" [value]="1">
Oui
</label>
<label class="radio">
<input type="radio" formControlName="isCuttable" [value]="0">
Non
</label>
</div>
</div>
<div class="column is-1">
<span class="icon" (click)="removeResourceFormat(i)" title="Supprimer le format">
<i class="fas fa-trash"></i>
</span>
</div>
</div>
</div> </div>
</div> --> </div>
<br> <br>
<div class="has-text-right"> <div class="has-text-right">
...@@ -118,4 +178,4 @@ ...@@ -118,4 +178,4 @@
</div> </div>
</form> </form>
</ng-container> </ng-container>
\ No newline at end of file
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, ParamMap, Router } from '@angular/router'; import { ActivatedRoute, ParamMap, Router } from '@angular/router';
import { Resource } from 'src/app/models/resource.model'; import { Resource, IResource } from 'src/app/models/resource.model';
import { ResourceService } from 'src/app/services/resource.service'; import { ResourceService } from 'src/app/services/resource.service';
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { FormBuilder, FormGroup, Validators, FormArray } from '@angular/forms';
import { filter, switchMap } from 'rxjs/operators'; import { filter, switchMap, mergeMap, merge, concatMap, map } from 'rxjs/operators';
import { Format } from 'src/app/models/format.model';
import { FormatService } from 'src/app/services';
import { from, forkJoin, Observable, of } from 'rxjs';
@Component({ @Component({
selector: 'app-resource-form', selector: 'app-resource-form',
...@@ -13,24 +16,30 @@ import { filter, switchMap } from 'rxjs/operators'; ...@@ -13,24 +16,30 @@ import { filter, switchMap } from 'rxjs/operators';
export class ResourceFormComponent implements OnInit { export class ResourceFormComponent implements OnInit {
resource: Resource = new Resource(); resource: Resource = new Resource();
formatsList: Format[] = [];
form: FormGroup; form: FormGroup;
title: string; title: string;
constructor( constructor(
private resourceService: ResourceService, private _resourceService: ResourceService,
private route: ActivatedRoute, private _formatService: FormatService,
private router: Router, private _route: ActivatedRoute,
private _router: Router,
private _fb: FormBuilder, private _fb: FormBuilder,
) { ) {
} }
ngOnInit() { ngOnInit() {
this.title = this.route.snapshot.data.title; this.title = this._route.snapshot.data.title;
this.initForm(); this.initForm();
this.route.paramMap.pipe( this._formatService.getAllFormats().subscribe((res) => {
this.formatsList = res;
});
this._route.paramMap.pipe(
filter((paramMap: ParamMap) => (paramMap.get('id') !== null)), filter((paramMap: ParamMap) => (paramMap.get('id') !== null)),
switchMap((paramMap: ParamMap) => this.resourceService.findById(paramMap.get('id')))) switchMap((paramMap: ParamMap) => this._resourceService.findById(paramMap.get('id'))))
.subscribe((resource: Resource) => { .subscribe((resource: Resource) => {
this.resource = resource; this.resource = resource;
...@@ -41,8 +50,19 @@ export class ResourceFormComponent implements OnInit { ...@@ -41,8 +50,19 @@ export class ResourceFormComponent implements OnInit {
} }
initForm() { initForm() {
const resourceFormats = new FormArray([]);
this.resource.resourceFormats.forEach((resourceFormat) => {
resourceFormats.push(this._fb.group({
formatId: [resourceFormat.format.id, Validators.required],
isProjectable: resourceFormat.isProjectable,
isCuttable: resourceFormat.isCuttable,
id: resourceFormat.id,
}));
});
this.form = this._fb.group( this.form = this._fb.group(
{ {
resourceFormats,
id: [this.resource.id], id: [this.resource.id],
name: [this.resource.name, Validators.required], name: [this.resource.name, Validators.required],
acronym: [this.resource.acronym], acronym: [this.resource.acronym],
...@@ -58,17 +78,45 @@ export class ResourceFormComponent implements OnInit { ...@@ -58,17 +78,45 @@ export class ResourceFormComponent implements OnInit {
onSubmit() { onSubmit() {
if (!this.formInvalid) { if (!this.formInvalid) {
this.resource = new Resource(this.form.value); const resourceFormats = this.form.controls.resourceFormats['controls'].filter(e => e.dirty).map(e => e.value);
// this.resource.outputFormats = this.form.value.outputFormats.split(','); const newResource = new Resource(this.form.value);
this.resourceService.replaceOrCreate(this.resource) let savedResource: Resource;
.subscribe( this._resourceService.replaceOrCreate(newResource).pipe(
(resourceCreated) => { mergeMap((resource) => {
this.router.navigate(['/resources', resourceCreated.id]); savedResource = resource;
}, let actions: Observable<any>[] = [];
(err) => {
alert(err.message); const toAdd = resourceFormats.filter(e => !e.id);
}, const toUpdate = resourceFormats.filter(e => e.id)
); const toDelete = this.resource.resourceFormats.map(e => e.id).filter((id) => {
return !this.form.controls.resourceFormats['controls'].map(e => e.value.id).find(rfId => rfId === id);
});
if (toAdd.length > 0) {
actions.push(this._resourceService.createResourceFormats(resource.id, toAdd));
}
if (toUpdate.length > 0) {
actions.push(this._resourceService.updateResourceFormats(resource.id, toUpdate));
}
if (toDelete.length > 0) {
actions.push(this._resourceService.deleteResourceFormats(resource.id, toDelete));
}
let res;
(actions.length > 0) ? res = forkJoin(actions) : res = of(null);
return res;
}),
map(() => savedResource.id),
).subscribe(
(resourceCreatedId) => {
this._router.navigate(['/resources', resourceCreatedId]);
},
(err) => {
},
);
} }
} }
...@@ -80,6 +128,25 @@ export class ResourceFormComponent implements OnInit { ...@@ -80,6 +128,25 @@ export class ResourceFormComponent implements OnInit {
return val; return val;
} }
addResourceFormat() {
// if (!this.form.controls.links) {
// this.organization.links = [];
// }
(this.form.controls.resourceFormats as FormArray).push(this._fb.group({
formatId: [null, Validators.required],
isProjectable: 0,
isCuttable: 0,
}));
}
removeResourceFormat(index) {
(this.form.controls.resourceFormats as FormArray).removeAt(index);
}
compareFormats(format1: Format, format2: Format) {
return format1 && format2 ? format1.id === format2.id : false;
}
// Getters for each property // Getters for each property
get name() { get name() {
return this.form.controls['name']; return this.form.controls['name'];
...@@ -97,6 +164,10 @@ export class ResourceFormComponent implements OnInit { ...@@ -97,6 +164,10 @@ export class ResourceFormComponent implements OnInit {
return this.form.controls['description']; return this.form.controls['description'];
} }
get formResourceFormats() {
return this.form.controls.resourceFormats as FormArray;
}
// get outputFormats() { // get outputFormats() {
// return this.form.controls['outputFormats']; // return this.form.controls['outputFormats'];
// } // }
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<div class="header columns is-marginless"> <div class="header columns is-marginless">
<div class="column is-2 has-text-centered"> <div class="column is-2 has-text-centered">
<span (click)="sortBy('name')" class="is-sortable"> <span (click)="sortBy('name')" class="is-sortable">
<span class="column-title" [ngClass]="{'active': sortOptions.value === name}">Name</span> <span class="column-title" [ngClass]="{'active': sortOptions.value === name}">Nom</span>
<span *ngIf="sortOptions.value === 'name'" class="has-text-danger"> <span *ngIf="sortOptions.value === 'name'" class="has-text-danger">
<i class="fas sort-order-icon" <i class="fas sort-order-icon"
[ngClass]="{'fa-arrow-up': sortOptions.order === 'asc', 'fa-arrow-down': sortOptions.order === 'desc'}"></i> [ngClass]="{'fa-arrow-up': sortOptions.order === 'asc', 'fa-arrow-down': sortOptions.order === 'desc'}"></i>
...@@ -102,4 +102,4 @@ ...@@ -102,4 +102,4 @@
</div> </div>
</div> </div>
</ng-container> </ng-container>
\ No newline at end of file
import { Format } from './format.model';
export class Resource { export class Resource {
id?: number; id?: string;
name: string; name: string;
acronym: string; acronym: string;
type: string; type: string;
...@@ -9,8 +11,10 @@ export class Resource { ...@@ -9,8 +11,10 @@ export class Resource {
isStandard: number; isStandard: number;
parametersUrl: string; parametersUrl: string;
messageWarning: string; messageWarning: string;
resourceFormats: IResourceFormat[];
constructor(resource?: IResource) { constructor(resource?: IResource) {
if (resource) { if (resource) {
if (resource.id) { if (resource.id) {
this.id = resource.id; this.id = resource.id;
...@@ -24,6 +28,7 @@ export class Resource { ...@@ -24,6 +28,7 @@ export class Resource {
this.isStandard = resource.isStandard; this.isStandard = resource.isStandard;
this.parametersUrl = resource.parametersUrl; this.parametersUrl = resource.parametersUrl;
this.messageWarning = resource.messageWarning; this.messageWarning = resource.messageWarning;
this.resourceFormats = resource.resourceFormats;
} else { } else {
this.name = ''; this.name = '';
this.acronym = ''; this.acronym = '';
...@@ -34,6 +39,7 @@ export class Resource { ...@@ -34,6 +39,7 @@ export class Resource {
this.isStandard = 0; this.isStandard = 0;
this.parametersUrl = ''; this.parametersUrl = '';
this.messageWarning = ''; this.messageWarning = '';
this.resourceFormats = [];
} }
} }
} }
...@@ -49,7 +55,7 @@ export class ResourceRO { ...@@ -49,7 +55,7 @@ export class ResourceRO {
} }
export interface IResource { export interface IResource {
id: number; id: string;
name: string; name: string;
acronym: string; acronym: string;
type: string; type: string;
...@@ -59,11 +65,13 @@ export interface IResource { ...@@ -59,11 +65,13 @@ export interface IResource {
isStandard: number; isStandard: number;
parametersUrl: string; parametersUrl: string;
messageWarning: string; messageWarning: string;
resourceFormats: IResourceFormat[];
} }
interface ILink { export interface IResourceFormat {
id?: number; format: Format;
name: string; formatId: string;
url: string; isProjectable: number;
organizationId: number; isCuttable: number;
id?: string;
} }
...@@ -26,7 +26,7 @@ export class FormatService { ...@@ -26,7 +26,7 @@ export class FormatService {
this.pageNumber = 1; this.pageNumber = 1;
} }
getFormats(options?): Observable<FormatRO> { getFormats(): Observable<FormatRO> {
let query = '?'; let query = '?';
query += `limit=${(this.limit ? this.limit : 20)}`; query += `limit=${(this.limit ? this.limit : 20)}`;
query += `&offset=${(this.pageNumber ? (this.pageNumber - 1) * this.limit : 0)}`; query += `&offset=${(this.pageNumber ? (this.pageNumber - 1) * this.limit : 0)}`;
...@@ -43,6 +43,12 @@ export class FormatService { ...@@ -43,6 +43,12 @@ export class FormatService {
})); }));
} }
getAllFormats(): Observable<Format[]> {
return this._httpClient.get<IFormat[]>(this.formatServiceUrl).pipe(
map(body => body.map(format => new Format(format))),
);
}
findById(id): Observable<Format> { findById(id): Observable<Format> {
return this._httpClient.get<IFormat>(this.formatServiceUrl + id).pipe( return this._httpClient.get<IFormat>(this.formatServiceUrl + id).pipe(
map((response) => { map((response) => {
......
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs'; import { Observable, Subject, from } from 'rxjs';
import { map } from 'rxjs/operators'; import { map, concatMap } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Resource, IResource, ResourceRO } from '../models/resource.model'; import { Resource, IResource, ResourceRO, IResourceFormat } from '../models/resource.model';
import { APP_CONFIG } from './app-config.service'; import { APP_CONFIG } from './app-config.service';
@Injectable() @Injectable()
...@@ -26,7 +26,7 @@ export class ResourceService { ...@@ -26,7 +26,7 @@ export class ResourceService {
this.pageNumber = 1; this.pageNumber = 1;
} }
getResources(options?): Observable<ResourceRO> { getResources(): Observable<ResourceRO> {
let query = '?'; let query = '?';
query += `limit=${(this.limit ? this.limit : 20)}`; query += `limit=${(this.limit ? this.limit : 20)}`;
query += `&offset=${(this.pageNumber ? (this.pageNumber - 1) * this.limit : 0)}`; query += `&offset=${(this.pageNumber ? (this.pageNumber - 1) * this.limit : 0)}`;
...@@ -70,6 +70,30 @@ export class ResourceService { ...@@ -70,6 +70,30 @@ export class ResourceService {
); );
} }
createResourceFormats(resourceId: string, resourceFormats: IResourceFormat[]): Observable<IResourceFormat> {
return from(resourceFormats).pipe(
concatMap((rf) => {
return this._httpClient.post<IResourceFormat>(`${this.resourceServiceUrl}${resourceId}/formats`, rf);
}),
);
}
updateResourceFormats(resourceId: string, resourceFormats: IResourceFormat[]) {
return from(resourceFormats).pipe(
concatMap((rf) => {
return this._httpClient.put<IResourceFormat>(`${this.resourceServiceUrl}${resourceId}/formats/${rf.id}`, rf);
}),
);
}
deleteResourceFormats(resourceId: string, resourceFormatsId: string[]) {
return from(resourceFormatsId).pipe(
concatMap((rfId) => {
return this._httpClient.delete<IResourceFormat>(`${this.resourceServiceUrl}${resourceId}/formats/${rfId}`);
}),
);
}
/* PAGINATION */ /* PAGINATION */
paginationChanged(limit: number, pageNumber: number) { paginationChanged(limit: number, pageNumber: number) {
this.limit = limit; this.limit = limit;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment