diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 7e2451faf86e6d1ced189bf80254847619468dba..dae310cdf7818a05bfd15bbada78b3fcfc82a10e 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -13,6 +13,10 @@ import { WelcomeComponent } from './components/welcome/welcome.component'; import { OrganizationDetailComponent } from './components/organizations/detail/organization-detail.component'; import { OrganizationFormComponent } from './components/organizations/edit/organization-form.component'; import { PaginatorComponent } from './components/paginator/paginator.component'; +import { ResourcesComponent } from './components/resources/list/resources.component'; +import { ResourceService } from './services/resource.service'; +import { ResourceFormComponent } from './components/resources/edit/resource-form.component'; +import { ResourceDetailComponent } from './components/resources/detail/resource-detail.component'; @NgModule({ declarations: [ @@ -23,6 +27,9 @@ import { PaginatorComponent } from './components/paginator/paginator.component'; OrganizationFormComponent, MenuComponent, WelcomeComponent, + ResourcesComponent, + ResourceFormComponent, + ResourceDetailComponent, ], imports: [ AppRoutingModule, @@ -35,6 +42,7 @@ import { PaginatorComponent } from './components/paginator/paginator.component'; ], providers: [ OrganizationService, + ResourceService, ], bootstrap: [AppComponent] }) diff --git a/src/app/app.routing.module.ts b/src/app/app.routing.module.ts index 597ca7389b040a6bca7f9252938390411486b4c8..23e3d791e5f1e9615cc870ed1b5260219d76c007 100644 --- a/src/app/app.routing.module.ts +++ b/src/app/app.routing.module.ts @@ -4,6 +4,9 @@ import { OrganizationsComponent } from './components/organizations/list/organiza import { NgModule } from '@angular/core'; import { OrganizationDetailComponent } from './components/organizations/detail/organization-detail.component'; import { OrganizationFormComponent } from './components/organizations/edit/organization-form.component'; +import { ResourcesComponent } from './components/resources/list/resources.component'; +import { ResourceFormComponent } from './components/resources/edit/resource-form.component'; +import { ResourceDetailComponent } from './components/resources/detail/resource-detail.component'; const appRoutes: Routes = [ @@ -39,7 +42,35 @@ const appRoutes: Routes = [ path: 'organizations/:id', component: OrganizationDetailComponent, data: { - title: 'Organisations', + title: 'Organisation', + }, + }, + { + path: 'resources', + component: ResourcesComponent, + data: { + title: 'Ressources', + }, + }, + { + path: 'resources/new', + component: ResourceFormComponent, + data: { + title: 'Nouvelle ressource', + }, + }, + { + path: 'resources/:id/edit', + component: ResourceFormComponent, + data: { + title: 'Modifier la ressource', + }, + }, + { + path: 'resources/:id', + component: ResourceDetailComponent, + data: { + title: 'Ressource', }, }, ]; diff --git a/src/app/components/menu/menu.component.html b/src/app/components/menu/menu.component.html index 890e492f1af8beed9b015486cf7f397d8edc48ff..63c9727b0315c031bea447c498e166b48b913e8a 100644 --- a/src/app/components/menu/menu.component.html +++ b/src/app/components/menu/menu.component.html @@ -15,5 +15,12 @@ <span class="label-menu">Organisations</span> </a> </li> + <li><a [routerLink]="['/', 'resources']" routerLinkActive="active-link"> + <span class="icon"> + <i class="fas fa-tint"></i> + </span> + <span class="label-menu">Ressources</span> + </a> + </li> </ul> </aside> diff --git a/src/app/components/organizations/list/organizations.component.html b/src/app/components/organizations/list/organizations.component.html index 375795393a6d32c00a60f306939eab7f515ab420..928edaa6786593a55caf99b0ee256041cc2ec517 100644 --- a/src/app/components/organizations/list/organizations.component.html +++ b/src/app/components/organizations/list/organizations.component.html @@ -6,7 +6,7 @@ <h2>{{ totalElement }} organisations trouvées</h2> </div> </div> - <div class="add-organization"> + <div class="add-item"> <a class="button is-link" [routerLink]="['new']"> Ajouter </a> diff --git a/src/app/components/organizations/list/organizations.component.scss b/src/app/components/organizations/list/organizations.component.scss index e445bc77f63ae5d209c7a1729cc41a3cb19582ea..5b91182b06c8b66f96e30646c55767d96bc0a805 100644 --- a/src/app/components/organizations/list/organizations.component.scss +++ b/src/app/components/organizations/list/organizations.component.scss @@ -82,6 +82,6 @@ i { } -.add-organization { +.add-item { margin-bottom: 20px; } diff --git a/src/app/components/resources/detail/resource-detail.component.html b/src/app/components/resources/detail/resource-detail.component.html new file mode 100644 index 0000000000000000000000000000000000000000..fac0e690cee7db63941a75eb4d472c7aa9a9cbf2 --- /dev/null +++ b/src/app/components/resources/detail/resource-detail.component.html @@ -0,0 +1,72 @@ +<ng-container *ngIf="resource"> + + <div class="back-button"> + <a routerLink="/resources" title="Retourner à la liste des organisations"> + <span class="icon is-medium"> + <i class="fas fa-arrow-left fa-lg"></i> + </span> + Retour + </a> + </div> + + + <section class="section"> + <div class="columns is-centered"> + <div class="column is-8"> + <div class="card"> + <header class="card-header"> + <p class="card-header-title has-text-centered"> + {{resource.name}} + </p> + </header> + <div class="card-content"> + + <div class="content"> + <p> + <span class="has-text-weight-bold">Type: </span> + <span>{{resource.type}}</span> + </p> + + <p *ngIf="resource.description"> + <span class="has-text-weight-bold">Description</span> <br> + <span>{{resource.description}}</span> + </p> + + <p> + <span class="has-text-weight-bold">Requêtable</span> + <span class="icon has-text-success" *ngIf="resource.queryable"> + <i class="far fa-check-circle"></i> + </span> + <span class="icon has-text-danger" *ngIf="!resource.queryable"> + <i class="far fa-times-circle"></i> + </span> + </p> + + <p> + <span class="has-text-weight-bold">Téléchargeable</span> + <span class="icon has-text-success" *ngIf="resource.downloadable"> + <i class="far fa-check-circle"></i> + </span> + <span class="icon has-text-danger" *ngIf="!resource.downloadable"> + <i class="far fa-times-circle"></i> + </span> + </p> + + <div> + <span class="has-text-weight-bold">Formats de sortie: </span> + <span *ngFor="let format of resource.outputFormats; let isLast=last"> + {{ format }}{{ isLast ? '' : ',' }} + </span> + </div> + + </div> + </div> + </div> + </div> + + </div> + + + </section> + +</ng-container> diff --git a/src/app/components/resources/detail/resource-detail.component.scss b/src/app/components/resources/detail/resource-detail.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..9198904fe9916e79864faf708db4350f7d80bae6 --- /dev/null +++ b/src/app/components/resources/detail/resource-detail.component.scss @@ -0,0 +1,17 @@ + +.back-button { + a { + color: unset; // Remove default link color + } + padding: 1rem 1.5rem; + a:hover { + color: #d5232a; + span, a { + color: #d5232a; + } + } +} + +.card-header-title { + justify-content: center; +} \ No newline at end of file diff --git a/src/app/components/resources/detail/resource-detail.component.ts b/src/app/components/resources/detail/resource-detail.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..7c0afe51e35173eaadf8b4047b88acd4dfc67267 --- /dev/null +++ b/src/app/components/resources/detail/resource-detail.component.ts @@ -0,0 +1,27 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, ParamMap } from '@angular/router'; +import 'rxjs/add/operator/switchMap'; +import { Resource } from 'src/app/models/resource.model'; +import { ResourceService } from 'src/app/services/resource.service'; + +@Component({ + selector: 'app-resource-detail', + templateUrl: './resource-detail.component.html', + styleUrls: ['./resource-detail.component.scss'], +}) +export class ResourceDetailComponent implements OnInit { + + resource: Resource; + + constructor( + private route: ActivatedRoute, + private resourceService: ResourceService, + ) { + } + + ngOnInit(): void { + this.route.paramMap + .switchMap((params: ParamMap) => this.resourceService.findById(params.get('id'))) + .subscribe((resource: Resource) => this.resource = resource); + } +} diff --git a/src/app/components/resources/edit/resource-form.component.html b/src/app/components/resources/edit/resource-form.component.html new file mode 100644 index 0000000000000000000000000000000000000000..984aa5d6b31947a1e6594b3e3edf0b18cbbbe54a --- /dev/null +++ b/src/app/components/resources/edit/resource-form.component.html @@ -0,0 +1,96 @@ +<ng-container *ngIf="resource"> + + <div class="back-button"> + <a routerLink="/resources" title="Retourner à la liste des organisations"> + <span class="icon is-medium"> + <i class="fas fa-arrow-left fa-lg"></i> + </span> + Retour + </a> + </div> + + <h1>{{ title }}</h1> + + <form [formGroup]="form" (ngSubmit)="onSubmit()" class="columns is-centered is-marginless"> + <div class="column is-7"> + <input type="hidden" formControlName="id" value="{{resource.id}}"> + + <div class="field"> + <label class="label required" for="name">Nom</label> + <div class="control"> + <input class="input" type="text" formControlName="name" id="name" required> + </div> + <div *ngIf="name.invalid && (name.dirty || name.touched)" class="alert alert-danger"> + <p *ngIf="name.errors['required']" class="help is-danger"> + Le nom de la ressource est obligatoire. + </p> + </div> + </div> + + <div class="field"> + <label class="label required" for="type">Type</label> + <div class="control"> + <input class="input" type="text" formControlName="type" id="type" required> + </div> + <div *ngIf="type.invalid && (type.dirty || type.touched)" class="alert alert-danger"> + <p *ngIf="type.errors['required']" class="help is-danger"> + Le type de la ressource est obligatoire. + </p> + </div> + </div> + + <div class="field"> + <label class="label required" for="queryable">Requêtable</label> + <div class="control"> + <label class="radio"> + <input type="radio" formControlName="queryable" [value]="1"> + Oui + </label> + <label class="radio"> + <input type="radio" formControlName="queryable" [value]="0"> + Non + </label> + </div> + </div> + + <div class="field"> + <label class="label required" for="downloadable">Téléchargeable</label> + <div class="control"> + <label class="radio"> + <input type="radio" formControlName="downloadable" [value]="1"> + Oui + </label> + <label class="radio"> + <input type="radio" formControlName="downloadable" [value]="0"> + Non + </label> + </div> + </div> + + <div class="field"> + <label class="label" for="description">Description</label> + <div class="control"> + <textarea class="textarea" formControlName="description" id="description"> + {{ resource.description }} + </textarea> + </div> + </div> + + <div class="field"> + <label class="label" for="outputFormats">Formats de sortie (Séparer chaque format par une virgule)</label> + <div class="control"> + <input class="input" type="text" formControlName="outputFormats" id="outputFormats"> + </div> + + </div> + <div class="field"> + <div class="control"> + <button class="button validate" [disabled]="formInvalid == true">Valider</button> + </div> + </div> + + </div> + </form> + + +</ng-container> diff --git a/src/app/components/resources/edit/resource-form.component.scss b/src/app/components/resources/edit/resource-form.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..8522a9ab88fb48e0ae39d622940fa851978291f8 --- /dev/null +++ b/src/app/components/resources/edit/resource-form.component.scss @@ -0,0 +1,37 @@ +.full-width { + width: 100%; +} + +h1 { + text-align: center +} + +.icon { + cursor: pointer; + &:hover { + .fa-plus { + color: lightblue; + } + .fa-trash { + color: #d5232a; + } + } +} + +.validate { + background-color: #168f48; + color: white; +} + +.back-button { + a { + color: unset; // Remove default link color + } + padding: 1rem 1.5rem; + a:hover { + color: #d5232a; + span, a { + color: #d5232a; + } + } +} diff --git a/src/app/components/resources/edit/resource-form.component.ts b/src/app/components/resources/edit/resource-form.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..d8adb34a86852fa6f2edd3d83de0cfc6096410e4 --- /dev/null +++ b/src/app/components/resources/edit/resource-form.component.ts @@ -0,0 +1,109 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, ParamMap, Router } from '@angular/router'; +import { Resource } from 'src/app/models/resource.model'; +import { ResourceService } from 'src/app/services/resource.service'; +import { FormBuilder, FormGroup, Validators, FormArray } from '@angular/forms'; + +@Component({ + selector: 'app-resource-form', + templateUrl: './resource-form.component.html', + styleUrls: ['./resource-form.component.scss'], +}) +export class ResourceFormComponent implements OnInit { + + resource: Resource; + form: FormGroup; + title: string; + + constructor( + private resourceService: ResourceService, + private route: ActivatedRoute, + private router: Router, + private _fb: FormBuilder, + ) { + } + + ngOnInit() { + this.title = this.route.snapshot.data.title; + this.initForm(); + + this.route.paramMap + .filter((paramMap: ParamMap) => (paramMap.get('id') !== null)) + .switchMap((paramMap: ParamMap) => this.resourceService.findById(paramMap.get('id'))) + .subscribe((resource: Resource) => { + + this.resource = resource; + + this.form = this._fb.group( + { + id: [this.resource.id], + name: [resource.name, Validators.required], + type: [resource.type, Validators.required], + queryable: [resource.queryable, Validators.required], + downloadable: [this.resource.downloadable, Validators.required], + description: [resource.description], + outputFormats: [this.resource.outputFormats.join(',')], + }); + + }); + + } + + initForm() { + this.resource = new Resource(); + const arr = new FormArray([]); + this.form = this._fb.group( + { + id: [this.resource.id], + name: [this.resource.name, Validators.required], + type: [this.resource.type, Validators.required], + queryable: [this.resource.queryable, Validators.required], + downloadable: [this.resource.downloadable, Validators.required], + description: [this.resource.description], + outputFormats: [this.resource.outputFormats.join(',')], + }); + } + + onSubmit() { + if (!this.formInvalid) { + this.resource = new Resource(this.form.value); + this.resource.outputFormats = this.form.value.outputFormats.split(','); + this.resourceService.replaceOrCreate(this.resource) + .subscribe( + (resourceCreated) => { + this.router.navigate(['/resources', resourceCreated.id]) + .then(() => { + }); + }, + (err) => { + alert(err.message); + }, + ); + } + } + + // Getters for each property + get name() { + return this.form.controls['name']; + } + + get type() { + return this.form.controls['type']; + } + + get queryable() { + return this.form.controls['queryable']; + } + + get description() { + return this.form.controls['description']; + } + + get outputFormats() { + return this.form.controls['outputFormats']; + } + + get formInvalid() { + return this.form.invalid; + } +} diff --git a/src/app/components/resources/list/resources.component.html b/src/app/components/resources/list/resources.component.html new file mode 100644 index 0000000000000000000000000000000000000000..9606966c5198e8fe8198338de2a52f5ebf0d2bd7 --- /dev/null +++ b/src/app/components/resources/list/resources.component.html @@ -0,0 +1,115 @@ +<ng-container *ngIf="resources"> + <div> + <div class="section"> + <div class="columns is-centered is-marginless"> + <div class="column has-text-centered"> + <h2>{{ totalElement }} ressources trouvées</h2> + </div> + </div> + <div class="add-item"> + <a class="button is-link" [routerLink]="['new']"> + Ajouter + </a> + </div> + <div class="table"> + <div class="header columns is-marginless"> + <div class="column is-1 has-text-centered"> + <span (click)="sortBy('id')" class="is-sortable"> + <span class="column-title" [ngClass]="{'active': sortOptions.value === 'id'}">Id</span> + <span *ngIf="sortOptions.value === 'id'" class="has-text-danger"> + <i class="fas sort-order-icon" [ngClass]="{'fa-arrow-up': sortOptions.order === 'asc', 'fa-arrow-down': sortOptions.order === 'desc'}"></i> + </span> + </span> + </div> + <div class="column is-2 has-text-centered"> + <span (click)="sortBy('name')" class="is-sortable"> + <span class="column-title" [ngClass]="{'active': sortOptions.value === name}">Name</span> + <span *ngIf="sortOptions.value === 'name'" class="has-text-danger"> + <i class="fas sort-order-icon" [ngClass]="{'fa-arrow-up': sortOptions.order === 'asc', 'fa-arrow-down': sortOptions.order === 'desc'}"></i> + </span> + </span> + </div> + <div class="column is-1 has-text-centered"> + <span class="column-title">Type</span> + </div> + <div class="column is-3 has-text-centered"> + <span class="column-title">Description</span> + </div> + <div class="column is-1 has-text-centered"> + <span class="column-title">Requêtable</span> + </div> + <div class="column is-1 has-text-centered"> + <span class="column-title">Téléchargeable</span> + </div> + <div class="column is-2 has-text-centered"> + <span class="column-title">Formats</span> + </div> + <div class="column is-1 has-text-centered"> + <span class="column-title">Actions</span> + </div> + </div> + <div class="data-list"> + <div class="data columns is-multiline is-vcentered is-marginless" + *ngFor="let resource of resources; let i=index; let odd=odd; let even=even;" + [ngClass]="{ odd: odd, even: even }"> + <div class="column is-1 has-text-centered"> + {{ resource.id }} + </div> + <div class="column is-2 has-text-centered"> + {{ resource.name}} + </div> + <div class="column is-1 has-text-centered"> + {{ resource.type}} + </div> + <div class="column is-3 has-text-centered"> + {{ resource.description | slice:0:300}} + </div> + <div class="column is-1 has-text-centered"> + <span class="icon has-text-success" *ngIf="resource.queryable"> + <i class="far fa-check-circle"></i> + </span> + <span class="icon has-text-danger" *ngIf="!resource.queryable"> + <i class="far fa-times-circle"></i> + </span> + </div> + <div class="column is-1 has-text-centered"> + <span class="icon has-text-success" *ngIf="resource.downloadable"> + <i class="far fa-check-circle"></i> + </span> + <span class="icon has-text-danger" *ngIf="!resource.downloadable"> + <i class="far fa-times-circle"></i> + </span> + </div> + <div class="column is-2 has-text-centered"> + {{ resource.outputFormats}} + </div> + <div class="column is-1 has-text-centered actions"> + <div class="columns is-marginless is-centered"> + <span class="icon column is-narrow"> + <a [routerLink]="[resource.id]"><i class="fas fa-eye"></i></a> + </span> + <span class="icon column is-narrow"> + <a [routerLink]="[resource.id, 'edit']"> <i class="fas fa-edit"></i></a> + </span> + <span class="icon has-text-danger column is-narrow" (click)="displayDeletePopup(resource.id)"> + <a> <i class="fas fa-trash"></i></a> + </span> + </div> + + </div> + + </div> + </div> + <div class="columns is-marginless"> + <div class="column"> + <app-paginator *ngIf="paginator.length > 0" [length]="paginator.length" [pageSize]="paginator.limit" + [pageSizeOptions]="paginator.pageSizeOptions" [pageIndex]="paginator.pageIndex" [pagesToShow]="5" + [showFirstLastButtons]="true" (page)="changePagination($event)" (pageSizeChanged)="changePageSize($event)"> + </app-paginator> + </div> + </div> + </div> + + </div> + </div> +</ng-container> diff --git a/src/app/components/resources/list/resources.component.scss b/src/app/components/resources/list/resources.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..aa337b2be447c0ed3974f37cb692ae0ef133d19b --- /dev/null +++ b/src/app/components/resources/list/resources.component.scss @@ -0,0 +1,87 @@ +section { + padding: 20px; +} +.section { + padding-top: 0; +} + +.table { + background-color: white; + border: 1px solid lightgray; +} + +.center { + text-align: center; +} + +img { + max-width: 100px; +} + +.header { + border-bottom: 1px solid lightgray; + background-color: #fafafa; + span { + color: #999; + + } +} + +.is-sortable .column-title { + cursor: pointer; +} + +.table .columns { + border-bottom: 1px solid lightgray +} + +.actions .columns { + border: none; +} + +.actions { + vertical-align: middle; + + .icon.column { + padding: 0; + } + + span { + display: inline-block; + } +} + +.actions .icon { + cursor: pointer; + + i { + color: #4a4a4a; + } + &:hover { + .fa-eye, .fa-edit { + color: blue; + } + .fa-trash { + color: #d5232a; + } + } +} +.icon { + height: unset; +} + +i { + + &.title-icon { + margin-right: 0.75rem; + } + + &.sort-order-icon { + padding-left: 0.75rem; + cursor: pointer; + } +} + +.add-item { + margin-bottom: 20px; +} diff --git a/src/app/components/resources/list/resources.component.ts b/src/app/components/resources/list/resources.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..a8d9357aa537cee3e71e6f1b72186adf159138f8 --- /dev/null +++ b/src/app/components/resources/list/resources.component.ts @@ -0,0 +1,100 @@ +import { Component, OnInit, ViewChild } from '@angular/core'; +import { Resource, ResourceRO } from 'src/app/models/resource.model'; +import { ResourceService } from 'src/app/services/resource.service'; +import { Subscription } from 'rxjs'; +import { PaginatorOptions } from 'src/app/models/paginator-options.model'; + +@Component({ + selector: 'app-resources', + templateUrl: './resources.component.html', + styleUrls: ['./resources.component.scss'], +}) +export class ResourcesComponent implements OnInit { + + resources: Resource[]; + searchChangeSub: Subscription; + + // Paginator options + paginator: PaginatorOptions; + + sortValue: string; + + totalElement: number; + pageSize = 10; + pageSizeOptions = [5, 10, 25, 100]; + filters = { + name: '', + }; + where = {}; + + constructor( + private resourcesService: ResourceService, + ) { + this.paginator = { + pageIndex: this.resourcesService.pageNumber, + length: 0, + limit: this.resourcesService.limit, + pageSizeOptions: [5, 10, 20], + }; + } + + ngOnInit(): void { + this.resourcesService.sortOptions = { + value: 'name', + order: 'asc' + }; + this.search(); + + this.searchChangeSub = this.resourcesService.searchChange$.subscribe( + () => { + this.search(); + }, + ); + } + + private search() { + this.resourcesService.getResources() + .subscribe((items: ResourceRO) => { + this.resources = items.resources; + this.totalElement = items.totalCount; + + this.paginator.limit = this.resourcesService.limit; + this.paginator.pageIndex = this.resourcesService.pageNumber; + this.paginator.length = items.totalCount; + }); + } + + + // When pagination is changed by user, we update datasetList with new pagination options + changePagination(pageIndex) { + this.resourcesService.paginationChanged(this.paginator.limit, pageIndex); + } + + changePageSize(pageSize) { + this.resourcesService.paginationChanged(pageSize, 1); + } + + sortBy(key: string) { + if (this.resourcesService.sortOptions.value === key) { + this.resourcesService.reverseSortOrder(); + } else { + this.resourcesService.sortOptions.value = key; + this.resourcesService.sortOptions.order = 'asc'; + } + this.search(); + } + + get sortOptions() { + return this.resourcesService.sortOptions; + } + + displayDeletePopup(resourceId) { + const pop = confirm('Etes vous sûr de vouloir supprimer cette organisation ?'); + if (pop === true) { + this.resourcesService.delete(resourceId).subscribe(() => { + this.resourcesService.pageNumber = 1; + this.search(); + }); + } + } +} diff --git a/src/app/models/organization.model.ts b/src/app/models/organization.model.ts index ae08a19529d9e4d9eea4250ebc6db54d0ab505f4..1b3a7d2832ea82f2764d0d44ae12c8b44ca23382 100644 --- a/src/app/models/organization.model.ts +++ b/src/app/models/organization.model.ts @@ -2,8 +2,8 @@ export class Organization { id: number; name: string; description: string; - logo: string; - links: ILink[]; + logo?: string; + links?: ILink[]; constructor(organization?: IOrganization) { if (organization) { diff --git a/src/app/models/resource.model.ts b/src/app/models/resource.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..7fb24fa24833f9c6553c65955df1c017b10db4c2 --- /dev/null +++ b/src/app/models/resource.model.ts @@ -0,0 +1,56 @@ +export class Resource { + id: number; + name: string; + type: string; + description?: string; + queryable: number; + downloadable: number; + outputFormats: string[]; + + constructor(resource?: IResource) { + if (resource) { + this.id = resource.id; + this.name = resource.name; + this.type = resource.type; + this.description = resource.description; + this.queryable = resource.queryable; + this.downloadable = resource.downloadable; + this.outputFormats = resource.outputFormats; + } else { + this.name = ''; + this.description = ''; + this.type = ''; + this.queryable = 0; + this.downloadable = 0; + this.outputFormats = []; + } + + } +} + +export class ResourceRO { + resources: Resource[]; + totalCount: number; + + constructor(resources, totalCount) { + this.resources = resources; + this.totalCount = totalCount; + } +} + +export interface IResource { + id: number; + name: string; + type: string; + description: string; + queryable: number; + downloadable: number; + outputFormats: string[]; +} + +interface ILink { + id?: number; + name: string; + url: string; + organizationId: number; +} diff --git a/src/app/services/resource.service.ts b/src/app/services/resource.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..c5045c1774a21ea9da0d93335e392b862926a2af --- /dev/null +++ b/src/app/services/resource.service.ts @@ -0,0 +1,90 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import { Subject } from 'rxjs/Subject'; +import { map } from 'rxjs/operators'; +import { HttpClient } from '@angular/common/http'; +import { Resource, IResource, ResourceRO } from '../models/resource.model'; +import { environment } from 'src/environments/environment'; + +@Injectable() +export class ResourceService { + + limit: number; + pageNumber: number; + sortOptions: { + value: string, + order: string, + }; + + private _searchChangeSubject: Subject<any>; + + constructor( + private _httpClient: HttpClient) { + this._searchChangeSubject = new Subject<any>(); + this.limit = 10; + this.pageNumber = 1; + } + + getResources(options?): Observable<ResourceRO> { + let query = '?'; + query += 'limit=' + (this.limit ? this.limit : 20); + query += '&offset=' + (this.pageNumber ? (this.pageNumber - 1) * this.limit : 0); + query += '&sort_by=' + this.sortOptions.value + '.' + this.sortOptions.order; + + return this._httpClient.get<IResource[]>(environment.resources.url + query, { observe: 'response' }).pipe( + map((response) => { + const totalCount = response.headers.get('Content-Range'); + const resources = []; + response.body.forEach((resource) => { + resources.push(new Resource(resource)); + }); + return new ResourceRO(resources, parseInt(totalCount, 10)); + })); + } + + findById(id): Observable<Resource> { + return this._httpClient.get<IResource>(environment.resources.url + id).pipe( + map((response) => { + return new Resource(response); + } + )); + } + + delete(id) { + return this._httpClient.delete(environment.resources.url + id); + } + + replaceOrCreate(data): Observable<Resource> { + if (data.id) { + return this._httpClient.put<IResource>(environment.resources.url + data.id, data).pipe( + map((response) => { + return new Resource(response); + } + )); + } + return this._httpClient.post<IResource>(environment.resources.url, data).pipe( + map((response) => { + return new Resource(response); + } + )); + } + + /* PAGINATION */ + paginationChanged(limit: number, pageNumber: number) { + this.limit = limit; + this.pageNumber = pageNumber; + this._searchChangeSubject.next(); + } + + reverseSortOrder(): void { + if (this.sortOptions.order === 'asc') { + this.sortOptions.order = 'desc'; + } else { + this.sortOptions.order = 'asc'; + } + } + + get searchChange$(): Observable<string> { + return this._searchChangeSubject.asObservable(); + } +} diff --git a/src/environments/environment.dev.ts b/src/environments/environment.dev.ts index 8daa21d0eeee59bc97995f77cc5919d85068d8bb..c6dcbcb734ab73e6013fb599f1408b534ed0d451 100644 --- a/src/environments/environment.dev.ts +++ b/src/environments/environment.dev.ts @@ -7,4 +7,7 @@ export const environment = { organizations: { url: kongBaseUrl + '/organizations/', }, + resources: { + url: kongBaseUrl + '/resources/', + }, }; diff --git a/src/environments/environment.rec.ts b/src/environments/environment.rec.ts index 67412c195027c0ba928dc5a566cac74f5f720ce0..90736b86bd04d1a7ba7e74f1b8bc5a61784d1e0b 100644 --- a/src/environments/environment.rec.ts +++ b/src/environments/environment.rec.ts @@ -7,4 +7,7 @@ export const environment = { organizations: { url: kongBaseUrl + '/organizations/', }, + resources: { + url: kongBaseUrl + '/resources/', + }, }; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 0614367b00ba8caee00694ffa8dd2e02af97fe58..4752652f5ee5ccf9b5aa76342cd2e808e6b130f0 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -8,5 +8,8 @@ export const environment = { organizations: { url: 'http://localhost:3001/organizations/', }, + resources: { + url: 'http://localhost:3003/resources/', + }, };