From 574e5b728c1f1bebf65b53c57e6c63e6a2aa8bf5 Mon Sep 17 00:00:00 2001 From: FORESTIER Fabien <fabien.forestier@soprasteria.com> Date: Fri, 19 Jul 2019 10:21:44 +0200 Subject: [PATCH] Update paginator, page header style, make menu sticky, add missing required style to some required fields --- src/app/app.component.scss | 11 +- src/app/app.component.ts | 12 +- src/app/app.routing.module.ts | 8 +- .../detail/format-detail.component.html | 45 ++- .../formats/detail/format-detail.component.ts | 2 + .../formats/edit/format-form.component.html | 9 +- .../formats/list/formats.component.html | 128 ++++--- .../formats/list/formats.component.scss | 4 +- .../formats/list/formats.component.ts | 6 + .../image-upload/image-upload.component.html | 3 +- src/app/components/index.ts | 3 + .../detail/organization-detail.component.html | 84 ++--- .../detail/organization-detail.component.ts | 10 +- .../edit/organization-form.component.html | 10 +- .../edit/organization-form.component.ts | 1 + .../list/organizations.component.html | 155 ++++----- .../list/organizations.component.scss | 4 - .../list/organizations.component.ts | 6 + .../page-header/page-header.component.html | 21 ++ .../page-header/page-header.component.scss | 88 +++++ .../page-header/page-header.component.spec.ts | 25 ++ .../page-header/page-header.component.ts | 40 +++ .../paginator/paginator.component.html | 102 +++--- .../paginator/paginator.component.scss | 41 ++- .../paginator/paginator.component.spec.ts | 25 ++ .../paginator/paginator.component.ts | 9 +- .../detail/resource-detail.component.html | 192 +++++------ .../detail/resource-detail.component.ts | 10 +- .../edit/resource-form.component.html | 13 +- .../resources/edit/resource-form.component.ts | 4 +- .../resources/list/resources.component.html | 320 +++++++++--------- .../resources/list/resources.component.scss | 4 +- .../resources/list/resources.component.ts | 8 +- src/app/models/image-upload.model.ts | 1 + src/app/models/page.model.ts | 7 + src/app/services/index.ts | 3 + .../services/navigation-history.service.ts | 27 ++ src/assets/img/left_arrow.svg | 3 + src/styles.scss | 15 + 39 files changed, 857 insertions(+), 602 deletions(-) create mode 100644 src/app/components/page-header/page-header.component.html create mode 100644 src/app/components/page-header/page-header.component.scss create mode 100644 src/app/components/page-header/page-header.component.spec.ts create mode 100644 src/app/components/page-header/page-header.component.ts create mode 100644 src/app/components/paginator/paginator.component.spec.ts create mode 100644 src/app/models/page.model.ts create mode 100644 src/app/services/navigation-history.service.ts create mode 100644 src/assets/img/left_arrow.svg diff --git a/src/app/app.component.scss b/src/app/app.component.scss index 9f10274..629e4b2 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -5,12 +5,12 @@ display: grid; grid-template-columns: 50px auto; grid-template-rows: 60px minmax(calc(100vh - 60px), auto); - overflow: hidden; + // overflow: hidden; } .main-header { grid-row: 1; - grid-column: 1 / -1; + grid-column: 1 / span 2; display: flex; flex-flow: row; @@ -45,11 +45,14 @@ .main-nav { grid-row: 2; - grid-column: 1 / span 1; + grid-column: 1; width: 50px; + height: 100vh; z-index: 200; transition: all .2s linear; background-color: #333745; + position: sticky; + top: 0px; &.is-active { width: 200px; @@ -58,7 +61,7 @@ .main-content { grid-row: 2; - grid-column: 2 / -1; + grid-column: 2; margin-left: 150px; background-color: $grey-background-color; transition: all 200ms cubic-bezier(0.7, 0, 0.3, 1); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 262e49f..994fd9e 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,6 +1,8 @@ import { Component, OnInit } from '@angular/core'; import { UserService } from './user/services'; -import { Router } from '@angular/router'; +import { Router, NavigationEnd } from '@angular/router'; +import { filter } from 'rxjs/operators'; +import { NavigationHistoryService } from './services'; @Component({ selector: 'app-root', @@ -16,10 +18,18 @@ export class AppComponent implements OnInit { constructor( private _userService: UserService, private _router: Router, + private _navigationHistoryService: NavigationHistoryService, ) { } ngOnInit(): void { this.sidebarOpened = true; + + // Activate navigation history + this._router.events.pipe( + filter(e => e instanceof NavigationEnd), + ).subscribe((e) => { + this._navigationHistoryService.add(e['urlAfterRedirects']); + }); } get loggedInUserFullname() { diff --git a/src/app/app.routing.module.ts b/src/app/app.routing.module.ts index c1a9102..f58c4ca 100644 --- a/src/app/app.routing.module.ts +++ b/src/app/app.routing.module.ts @@ -20,7 +20,7 @@ const appRoutes: Routes = [ component: OrganizationsComponent, canActivate: [AuthenticatedGuard], data: { - title: 'Producteur-de-donnees', + title: 'Producteur de donnees', }, }, { @@ -44,7 +44,7 @@ const appRoutes: Routes = [ component: OrganizationDetailComponent, canActivate: [AuthenticatedGuard], data: { - title: 'Producteur de données', + title: 'Detail du producteur de données', }, }, { @@ -76,7 +76,7 @@ const appRoutes: Routes = [ component: ResourceDetailComponent, canActivate: [AuthenticatedGuard], data: { - title: 'Ressource', + title: 'Detail de la ressource', }, }, { @@ -108,7 +108,7 @@ const appRoutes: Routes = [ component: FormatDetailComponent, canActivate: [AuthenticatedGuard], data: { - title: 'Format', + title: 'Detail du format', }, }, ]; diff --git a/src/app/components/formats/detail/format-detail.component.html b/src/app/components/formats/detail/format-detail.component.html index 064569e..4e96e4b 100644 --- a/src/app/components/formats/detail/format-detail.component.html +++ b/src/app/components/formats/detail/format-detail.component.html @@ -1,30 +1,27 @@ -<ng-container *ngIf="format"> +<section class="section page-container" *ngIf="format"> + <app-page-header [pageInfo]="{title: title}"></app-page-header> - <app-back-button [route]="'/formats'" [title]="'Retourner à la liste des formats'"></app-back-button> - - <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"> - {{format.name}} + <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"> + {{format.name}} + </p> + </header> + <div class="card-content"> + <div class="content"> + <p> + <span class="has-text-weight-bold">Id: </span> + <span>{{format.id}}</span> + </p> + <p> + <span class="has-text-weight-bold">Type MapServer: </span> + <span>{{format.mapServerType}}</span> </p> - </header> - <div class="card-content"> - <div class="content"> - <p> - <span class="has-text-weight-bold">Id: </span> - <span>{{format.id}}</span> - </p> - <p> - <span class="has-text-weight-bold">Type MapServer: </span> - <span>{{format.mapServerType}}</span> - </p> - </div> </div> </div> </div> </div> - </section> -</ng-container> \ No newline at end of file + </div> +</section> \ No newline at end of file diff --git a/src/app/components/formats/detail/format-detail.component.ts b/src/app/components/formats/detail/format-detail.component.ts index 52b8bf8..2cff262 100644 --- a/src/app/components/formats/detail/format-detail.component.ts +++ b/src/app/components/formats/detail/format-detail.component.ts @@ -13,6 +13,7 @@ import { Format } from 'src/app/models/format.model'; export class FormatDetailComponent implements OnInit { format: Format; + title: string; constructor( private _route: ActivatedRoute, @@ -21,6 +22,7 @@ export class FormatDetailComponent implements OnInit { } ngOnInit(): void { + this.title = this._route.snapshot.data.title; this._route.paramMap.pipe( switchMap((params: ParamMap) => this._formatService.findById(params.get('id')))) .subscribe((format: Format) => this.format = format); diff --git a/src/app/components/formats/edit/format-form.component.html b/src/app/components/formats/edit/format-form.component.html index dc9588a..b4042a8 100644 --- a/src/app/components/formats/edit/format-form.component.html +++ b/src/app/components/formats/edit/format-form.component.html @@ -1,8 +1,5 @@ -<ng-container *ngIf="format"> - - <app-back-button [route]="'/formats'" [title]="'Retourner à la liste des formats'"></app-back-button> - - <h1>{{ title }}</h1> +<section class="section page-container" *ngIf="format"> + <app-page-header [pageInfo]="{title: title}"></app-page-header> <form [formGroup]="form" (ngSubmit)="onSubmit()" class="columns is-centered is-marginless"> <div class="column is-7"> @@ -38,4 +35,4 @@ </div> </div> </form> -</ng-container> \ No newline at end of file +</section> \ No newline at end of file diff --git a/src/app/components/formats/list/formats.component.html b/src/app/components/formats/list/formats.component.html index 2f14f47..21681fd 100644 --- a/src/app/components/formats/list/formats.component.html +++ b/src/app/components/formats/list/formats.component.html @@ -1,78 +1,68 @@ -<ng-container *ngIf="formats"> - <div> - <div class="section"> - <div class="columns is-centered is-marginless"> - <div class="column has-text-centered"> - <h2>{{ totalElement }} formats trouvés</h2> - </div> - </div> - <div class="add-item-link has-text-right"> - <a class="button button-gl" [routerLink]="['new']"> - Ajouter - </a> +<section class="section page-container" *ngIf="formats"> + <app-page-header [pageInfo]="pageHeaderInfo" [hideBackButton]="true"></app-page-header> + <div class="add-item-link has-text-right"> + <a class="button button-gl" [routerLink]="['new']"> + Ajouter + </a> + </div> + <div class="table entity-list-table"> + <div class="header columns is-marginless"> + <div class="column is-2"> + <span (click)="sortBy('name')" class="is-sortable"> + <span class="sort-icons"> + <span class="icon"> + <i class="fas fa-sort-up" + [ngClass]="{'icon-red': sortOptions.value === 'name' && sortOptions.order === 'desc'}"></i> + </span> + <span class="icon"> + <i class="fas fa-sort-down" + [ngClass]="{'icon-red': sortOptions.value === 'name' && sortOptions.order === 'asc'}"></i> + </span> + </span> + <span class="column-title" [ngClass]="{'active': sortOptions.value === name}">Nom</span> + </span> </div> - <div class="table entity-list-table"> - <div class="header columns is-marginless"> - <div class="column is-2"> - <span (click)="sortBy('name')" class="is-sortable"> - <span class="sort-icons"> - <span class="icon"> - <i class="fas fa-sort-up" - [ngClass]="{'icon-red': sortOptions.value === 'name' && sortOptions.order === 'desc'}"></i> - </span> - <span class="icon"> - <i class="fas fa-sort-down" - [ngClass]="{'icon-red': sortOptions.value === 'name' && sortOptions.order === 'asc'}"></i> - </span> - </span> - <span class="column-title" [ngClass]="{'active': sortOptions.value === name}">Nom</span> + <div class="column is-2"> + <span (click)="sortBy('mapServerType')" class="is-sortable"> + <span class="sort-icons"> + <span class="icon"> + <i class="fas fa-sort-up" + [ngClass]="{'icon-red': sortOptions.value === 'mapServerType' && sortOptions.order === 'desc'}"></i> </span> - </div> - <div class="column is-2"> - <span (click)="sortBy('mapServerType')" class="is-sortable"> - <span class="sort-icons"> - <span class="icon"> - <i class="fas fa-sort-up" - [ngClass]="{'icon-red': sortOptions.value === 'mapServerType' && sortOptions.order === 'desc'}"></i> - </span> - <span class="icon"> - <i class="fas fa-sort-down" - [ngClass]="{'icon-red': sortOptions.value === 'mapServerType' && sortOptions.order === 'asc'}"></i> - </span> - </span> - <span class="column-title" [ngClass]="{'active': sortOptions.value === mapServerType}">Type - MapServer</span> + <span class="icon"> + <i class="fas fa-sort-down" + [ngClass]="{'icon-red': sortOptions.value === 'mapServerType' && sortOptions.order === 'asc'}"></i> </span> - </div> - <div class="column is-offset-7 is-1 has-text-centered"> - <span class="column-title">Actions</span> - </div> + </span> + <span class="column-title" [ngClass]="{'active': sortOptions.value === mapServerType}">Type + MapServer</span> + </span> + </div> + <div class="column is-offset-7 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 format of formats; let i=index; let odd=odd; let even=even;" [ngClass]="{ odd: odd, even: even }"> + <div class="column is-2"> + <span>{{ format.name}}</span> </div> - <div class="data-list"> - <div class="data columns is-multiline is-vcentered is-marginless" - *ngFor="let format of formats; let i=index; let odd=odd; let even=even;" - [ngClass]="{ odd: odd, even: even }"> - <div class="column is-2"> - <span>{{ format.name}}</span> - </div> - <div class="column is-2"> - <span>{{ format.mapServerType}}</span> - </div> - <div class="column is-offset-7 is-1 has-text-centered actions"> - <app-crud-buttons [id]="format.id" (delete)="displayDeletePopup($event)"></app-crud-buttons> - </div> - </div> + <div class="column is-2"> + <span>{{ format.mapServerType}}</span> </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 class="column is-offset-7 is-1 has-text-centered actions"> + <app-crud-buttons [id]="format.id" (delete)="displayDeletePopup($event)"></app-crud-buttons> </div> </div> </div> + <div class="columns is-marginless paginator"> + <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> -</ng-container> \ No newline at end of file +</section> \ No newline at end of file diff --git a/src/app/components/formats/list/formats.component.scss b/src/app/components/formats/list/formats.component.scss index 60e54cc..8b13789 100644 --- a/src/app/components/formats/list/formats.component.scss +++ b/src/app/components/formats/list/formats.component.scss @@ -1,3 +1 @@ -.section { - padding-top: 0; -} + diff --git a/src/app/components/formats/list/formats.component.ts b/src/app/components/formats/list/formats.component.ts index 0efba29..950708a 100644 --- a/src/app/components/formats/list/formats.component.ts +++ b/src/app/components/formats/list/formats.component.ts @@ -3,6 +3,7 @@ import { FormatService } from 'src/app/services/format.service'; import { Subscription } from 'rxjs'; import { PaginatorOptions } from 'src/app/models/paginator-options.model'; import { Format, FormatRO } from 'src/app/models/format.model'; +import { IPageHeaderInfo } from '../../../models/page.model'; @Component({ selector: 'app-formats', @@ -11,6 +12,9 @@ import { Format, FormatRO } from 'src/app/models/format.model'; }) export class FormatsComponent implements OnInit { + pageHeaderInfo: IPageHeaderInfo = { + title: '', + }; formats: Format[]; searchChangeSub: Subscription; @@ -58,6 +62,8 @@ export class FormatsComponent implements OnInit { this.formats = items.formats; this.totalElement = items.totalCount; + this.pageHeaderInfo.title = `${this.totalElement} formats trouvés`; + this.paginator.limit = this.formatsService.limit; this.paginator.pageIndex = this.formatsService.pageNumber; this.paginator.length = items.totalCount; diff --git a/src/app/components/image-upload/image-upload.component.html b/src/app/components/image-upload/image-upload.component.html index 72e3400..acf76a9 100644 --- a/src/app/components/image-upload/image-upload.component.html +++ b/src/app/components/image-upload/image-upload.component.html @@ -1,5 +1,6 @@ <div class="field"> - <label class="label" [for]="fieldParams.inputName">{{ fieldParams.label }}</label> + <label class="label" [ngClass]="{'required': fieldParams.isRequired}" + [for]="fieldParams.inputName">{{ fieldParams.label }}</label> <div class="image-preview-container" *ngIf="fieldParams.existingImageUrl && !removeImageBtnClicked"> <button class="button" (click)="removeImage()"><i class="far fa-times-circle"></i></button> <img [src]="fieldParams.existingImageUrl" alt="" class="image-preview"> diff --git a/src/app/components/index.ts b/src/app/components/index.ts index a2edd10..90f5e96 100644 --- a/src/app/components/index.ts +++ b/src/app/components/index.ts @@ -13,6 +13,7 @@ import { FormatDetailComponent } from './formats/detail/format-detail.component' import { FormatFormComponent } from './formats/edit/format-form.component'; import { ImageUploadComponent } from './image-upload/image-upload.component'; import { NotificationsComponent } from './notifications/notifications.component'; +import { PageHeaderComponent } from './page-header/page-header.component'; export { MenuComponent, @@ -30,6 +31,7 @@ export { FormatFormComponent, ImageUploadComponent, NotificationsComponent, + PageHeaderComponent, }; // tslint:disable-next-line:variable-name @@ -49,4 +51,5 @@ export const AppComponents = [ FormatFormComponent, ImageUploadComponent, NotificationsComponent, + PageHeaderComponent, ]; diff --git a/src/app/components/organizations/detail/organization-detail.component.html b/src/app/components/organizations/detail/organization-detail.component.html index 56d16c9..fcde851 100644 --- a/src/app/components/organizations/detail/organization-detail.component.html +++ b/src/app/components/organizations/detail/organization-detail.component.html @@ -1,53 +1,43 @@ -<ng-container *ngIf="organization"> - - <app-back-button [route]="'/producteur-de-donnees'" [title]="'Retourner à la liste des organisations'"> - </app-back-button> - - <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"> - {{organization.name}} - </p> - </header> - <div class="card-image"> - <figure class="image"> - <img [src]="organization.logo" alt="Logo du producteur de données"> - </figure> - </div> - <div class="card-content"> - - <div class="content"> - <div> - <p>{{organization.description}}</p> - </div> - <br> - <div> - <p><span class="has-text-weight-bold">Id:</span> {{ organization.id}}</p> - </div> - <br> - <div> - <p class="has-text-weight-bold">Nom ElasticSearch de l'organisation:</p> - <p>{{ organization.elasticSearchName}}</p> - </div> - <br> - <div> - <p class="has-text-weight-bold">Liens</p> - <p *ngFor="let link of organization.links"> - <a href="{{ link.url }}" target="_blank">{{link.url}}</a> - </p> - </div> +<section class="section page-container" *ngIf="organization"> + <app-page-header [pageInfo]="{title: title}"></app-page-header> + <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"> + {{organization.name}} + </p> + </header> + <div class="card-image"> + <figure class="image"> + <img [src]="organization.logo" alt="Logo du producteur de données"> + </figure> + </div> + <div class="card-content"> + <div class="content"> + <div> + <p>{{organization.description}}</p> + </div> + <br> + <div> + <p><span class="has-text-weight-bold">Id:</span> {{ organization.id}}</p> + </div> + <br> + <div> + <p class="has-text-weight-bold">Nom ElasticSearch de l'organisation:</p> + <p>{{ organization.elasticSearchName}}</p> + </div> + <br> + <div> + <p class="has-text-weight-bold">Liens</p> + <p *ngFor="let link of organization.links"> + <a href="{{ link.url }}" target="_blank">{{link.url}}</a> + </p> </div> </div> </div> </div> - </div> - - - </section> - -</ng-container> \ No newline at end of file + </div> +</section> \ No newline at end of file diff --git a/src/app/components/organizations/detail/organization-detail.component.ts b/src/app/components/organizations/detail/organization-detail.component.ts index 459164c..b0f291a 100644 --- a/src/app/components/organizations/detail/organization-detail.component.ts +++ b/src/app/components/organizations/detail/organization-detail.component.ts @@ -14,16 +14,18 @@ import { OrganizationService } from 'src/app/services/organization.service'; export class OrganizationDetailComponent implements OnInit { organization: Organization; + title: string; constructor( - private route: ActivatedRoute, - private organizationService: OrganizationService, + private _route: ActivatedRoute, + private _organizationService: OrganizationService, ) { } ngOnInit(): void { - this.route.paramMap.pipe( - switchMap((params: ParamMap) => this.organizationService.findById(params.get('id')))) + this.title = this._route.snapshot.data.title; + this._route.paramMap.pipe( + switchMap((params: ParamMap) => this._organizationService.findById(params.get('id')))) .subscribe((organization: Organization) => this.organization = organization); } } diff --git a/src/app/components/organizations/edit/organization-form.component.html b/src/app/components/organizations/edit/organization-form.component.html index 70d9104..dc8ea2d 100644 --- a/src/app/components/organizations/edit/organization-form.component.html +++ b/src/app/components/organizations/edit/organization-form.component.html @@ -1,9 +1,5 @@ -<ng-container *ngIf="organization"> - - <app-back-button [route]="'/producteur-de-donnees'" [title]="'Retourner à la liste des producteurs de données'"> - </app-back-button> - - <h1>{{ title }}</h1> +<section class="section page-container" *ngIf="organization"> + <app-page-header [pageInfo]="{title: title}"></app-page-header> <form [formGroup]="form" (ngSubmit)="onSubmit()" class="columns is-centered is-marginless"> <div class="column is-7"> @@ -88,4 +84,4 @@ </div> </div> </form> -</ng-container> \ No newline at end of file +</section> \ No newline at end of file diff --git a/src/app/components/organizations/edit/organization-form.component.ts b/src/app/components/organizations/edit/organization-form.component.ts index 65ec6c1..b8a22a5 100644 --- a/src/app/components/organizations/edit/organization-form.component.ts +++ b/src/app/components/organizations/edit/organization-form.component.ts @@ -21,6 +21,7 @@ export class OrganizationFormComponent implements OnInit { inputName: 'logo', label: 'Logo', existingImageUrl: null, + isRequired: true, }; logo: File; title: string; diff --git a/src/app/components/organizations/list/organizations.component.html b/src/app/components/organizations/list/organizations.component.html index bc59588..f30fe6a 100644 --- a/src/app/components/organizations/list/organizations.component.html +++ b/src/app/components/organizations/list/organizations.component.html @@ -1,92 +1,83 @@ -<ng-container *ngIf="organizations"> - <div> - <div class="section"> - <div class="columns is-centered is-marginless"> - <div class="column has-text-centered"> - <h2>{{ totalElement }} producteurs de données trouvés</h2> - </div> +<div class="section page-container" *ngIf="organizations"> + <app-page-header [pageInfo]="pageHeaderInfo" [hideBackButton]="true"></app-page-header> + <div class="add-item-link has-text-right"> + <a class="button button-gl" [routerLink]="['new']"> + Ajouter + </a> + </div> + <div class="table entity-list-table"> + <div class="header columns is-marginless"> + <div class="column is-2"> + <span (click)="sortBy('name')" class="is-sortable"> + <span class="sort-icons"> + <span class="icon"> + <i class="fas fa-sort-up" + [ngClass]="{'icon-red': sortOptions.value === 'name' && sortOptions.order === 'desc'}"></i> + </span> + <span class="icon"> + <i class="fas fa-sort-down" + [ngClass]="{'icon-red': sortOptions.value === 'name' && sortOptions.order === 'asc'}"></i> + </span> + </span> + <span class="column-title" [ngClass]="{'active': sortOptions.value === name}">Nom</span> + </span> </div> - <div class="add-item-link has-text-right"> - <a class="button button-gl" [routerLink]="['new']"> - Ajouter - </a> + <div class="column is-2 has-text-centered"> + <span class="column-title">Logo</span> </div> - <div class="table entity-list-table"> - <div class="header columns is-marginless"> - <div class="column is-2"> - <span (click)="sortBy('name')" class="is-sortable"> - <span class="sort-icons"> - <span class="icon"> - <i class="fas fa-sort-up" - [ngClass]="{'icon-red': sortOptions.value === 'name' && sortOptions.order === 'desc'}"></i> - </span> - <span class="icon"> - <i class="fas fa-sort-down" - [ngClass]="{'icon-red': sortOptions.value === 'name' && sortOptions.order === 'asc'}"></i> - </span> - </span> - <span class="column-title" [ngClass]="{'active': sortOptions.value === name}">Nom</span> + <div class="column is-4"> + <span (click)="sortBy('description')" class="is-sortable"> + <span class="sort-icons"> + <span class="icon"> + <i class="fas fa-sort-up" + [ngClass]="{'icon-red': sortOptions.value === 'description' && sortOptions.order === 'desc'}"></i> </span> - </div> - <div class="column is-2 has-text-centered"> - <span class="column-title">Logo</span> - </div> - <div class="column is-4"> - <span (click)="sortBy('description')" class="is-sortable"> - <span class="sort-icons"> - <span class="icon"> - <i class="fas fa-sort-up" - [ngClass]="{'icon-red': sortOptions.value === 'description' && sortOptions.order === 'desc'}"></i> - </span> - <span class="icon"> - <i class="fas fa-sort-down" - [ngClass]="{'icon-red': sortOptions.value === 'description' && sortOptions.order === 'asc'}"></i> - </span> - </span> - <span class="column-title">Description</span> + <span class="icon"> + <i class="fas fa-sort-down" + [ngClass]="{'icon-red': sortOptions.value === 'description' && sortOptions.order === 'asc'}"></i> </span> - </div> - <div class="column is-3"> - <span class="column-title">Liens</span> - </div> - <div class="column is-1 has-text-centered"> - <span class="column-title">Actions</span> - </div> + </span> + <span class="column-title">Description</span> + </span> + </div> + <div class="column is-3"> + <span class="column-title">Liens</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 organization of organizations; let i=index; let odd=odd; let even=even;" + [ngClass]="{ odd: odd, even: even }"> + <div class="column is-2"> + <span>{{ organization.name}}</span> </div> - <div class="data-list"> - <div class="data columns is-multiline is-vcentered is-marginless" - *ngFor="let organization of organizations; let i=index; let odd=odd; let even=even;" - [ngClass]="{ odd: odd, even: even }"> - <div class="column is-2"> - <span>{{ organization.name}}</span> - </div> - <div class="column is-2 has-text-centered"> - <img src="{{organization.logo}}" alt=""> - </div> - <div class="column is-4"> - <span>{{ organization.description | slice:0:200}}...</span> - </div> - <div class="column is-3"> - <p *ngFor="let link of organization.links"> - <a href="{{ link.url }}" target="_blank">{{link.url}}</a> - </p> - </div> - <div class="column is-1 has-text-centered actions"> - <app-crud-buttons [id]="organization.id" (delete)="displayDeletePopup($event)"></app-crud-buttons> - </div> - - </div> + <div class="column is-2 has-text-centered"> + <img src="{{organization.logo}}" alt=""> + </div> + <div class="column is-4"> + <span>{{ organization.description | slice:0:200}}...</span> + </div> + <div class="column is-3"> + <p *ngFor="let link of organization.links"> + <a href="{{ link.url }}" target="_blank">{{link.url}}</a> + </p> </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 class="column is-1 has-text-centered actions"> + <app-crud-buttons [id]="organization.id" (delete)="displayDeletePopup($event)"></app-crud-buttons> </div> + + </div> + </div> + <div class="columns is-marginless paginator"> + <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> -</ng-container> \ No newline at end of file +</div> \ No newline at end of file diff --git a/src/app/components/organizations/list/organizations.component.scss b/src/app/components/organizations/list/organizations.component.scss index 75967d5..d1ab576 100644 --- a/src/app/components/organizations/list/organizations.component.scss +++ b/src/app/components/organizations/list/organizations.component.scss @@ -1,7 +1,3 @@ -.section { - padding-top: 0; -} - img { max-width: 100px; } diff --git a/src/app/components/organizations/list/organizations.component.ts b/src/app/components/organizations/list/organizations.component.ts index 327fe01..c2c4551 100644 --- a/src/app/components/organizations/list/organizations.component.ts +++ b/src/app/components/organizations/list/organizations.component.ts @@ -3,6 +3,7 @@ import { Organization, OrganizationRO } from 'src/app/models/organization.model' import { OrganizationService } from 'src/app/services/organization.service'; import { Subscription } from 'rxjs'; import { PaginatorOptions } from 'src/app/models/paginator-options.model'; +import { IPageHeaderInfo } from '../../../models/page.model'; @Component({ selector: 'app-organizations', @@ -11,6 +12,9 @@ import { PaginatorOptions } from 'src/app/models/paginator-options.model'; }) export class OrganizationsComponent implements OnInit { + pageHeaderInfo: IPageHeaderInfo = { + title: '', + }; organizations: Organization[]; searchChangeSub: Subscription; @@ -58,6 +62,8 @@ export class OrganizationsComponent implements OnInit { this.organizations = items.organizations; this.totalElement = items.totalCount; + this.pageHeaderInfo.title = `${this.totalElement} producteurs de données trouvés`; + this.paginator.limit = this.organizationsService.limit; this.paginator.pageIndex = this.organizationsService.pageNumber; this.paginator.length = items.totalCount; diff --git a/src/app/components/page-header/page-header.component.html b/src/app/components/page-header/page-header.component.html new file mode 100644 index 0000000..fa2b49d --- /dev/null +++ b/src/app/components/page-header/page-header.component.html @@ -0,0 +1,21 @@ +<div class="page-header"> + <div class="back-button" (click)="goToPreviousPage()" + [ngClass]="{'has-beta-style': pageInfo.hasBetaStyle, 'hidden': hideBackButton}"> + <img class="icon-left-arrow" src="./assets/img/left_arrow.svg" alt="Picto de la flèche retour"> + <span>Retour</span> + </div> + + <div class="page-title" [ngClass]="{'has-surtitle': pageInfo.surtitle}"> + <div class="surtitle-item" *ngIf="pageInfo.surtitle"> + <span>{{ pageInfo.surtitle }}</span> + </div> + <div class="title-item"> + {{ pageInfo.title }} <span class="metadataSubtitle" *ngIf="pageInfo.metadataSubtitle"> - + {{ pageInfo.metadataSubtitle }} </span> + </div> + + <div class="subtitle-item" *ngIf="pageInfo.subtitle"> + <span>{{ pageInfo.subtitle }}</span> + </div> + </div> +</div> \ No newline at end of file diff --git a/src/app/components/page-header/page-header.component.scss b/src/app/components/page-header/page-header.component.scss new file mode 100644 index 0000000..f2646b9 --- /dev/null +++ b/src/app/components/page-header/page-header.component.scss @@ -0,0 +1,88 @@ +@import '../../../scss/variables.scss'; +@import '../../../../node_modules/bulma/sass/utilities/_all.sass'; + +.page-header { + display: flex; + padding-top: 1.875rem; + padding-bottom: 1.875rem; +} + +.back-button { + color: $grey-dark-color; + font-size: 0.875rem; + font-weight: 500; + cursor: pointer; + padding: 1.125rem 1rem 1.125rem 0; + width: 6rem; + white-space: nowrap; + align-items: center; + align-self: flex-start; + flex-shrink: 0; + justify-content: center; + // Hide back button for mobile + display: none; + + &.hidden { + display: none; + } + + @media screen and (min-width: $tablet) { + display: flex; + } + + .icon-left-arrow { + margin-right: 0.5rem; + } + + &:hover { + text-decoration: underline; + } +} + +.page-title { + align-self: center; + padding-left: 1rem; + + border-left: 4px solid $tomato-color; + + &.has-beta-style { + border-left-color: $yellow-dd-color; + } +} + +.page-title.has-surtitle { + display: flex; + flex-direction: column; + justify-content: space-between; + align-self: unset; +} + +.surtitle-item span { + margin-bottom: 0.5rem; + font-size: 0.75rem; + text-transform: uppercase; + color: $grey-dark-color; + line-height: 1; + vertical-align: text-top; +} + +.subtitle-item span { + margin-top: 0.5rem; + font-size: 1rem; + color: $grey-dark-color; + line-height: 1; + vertical-align: text-bottom; +} + +.metadataSubtitle { + color: $grey-dark-color; + font-weight: 300; + font-size: inherit; +} + +.title-item { + font-size: 1.75rem; + font-weight: bold; + line-height: 1.15; + color: $brand-color; +} diff --git a/src/app/components/page-header/page-header.component.spec.ts b/src/app/components/page-header/page-header.component.spec.ts new file mode 100644 index 0000000..21189dd --- /dev/null +++ b/src/app/components/page-header/page-header.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PageHeaderComponent } from './page-header.component'; + +describe('PageHeaderComponent', () => { + let component: PageHeaderComponent; + let fixture: ComponentFixture<PageHeaderComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [PageHeaderComponent], + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PageHeaderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/page-header/page-header.component.ts b/src/app/components/page-header/page-header.component.ts new file mode 100644 index 0000000..0d824ad --- /dev/null +++ b/src/app/components/page-header/page-header.component.ts @@ -0,0 +1,40 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { Router } from '@angular/router'; +import { NavigationHistoryService } from '../../services'; +import { IPageHeaderInfo } from '../../models/page.model'; + +@Component({ + selector: 'app-page-header', + templateUrl: './page-header.component.html', + styleUrls: ['./page-header.component.scss'], +}) +export class PageHeaderComponent implements OnInit { + + constructor( + private _navigationHistoryService: NavigationHistoryService, + private _router: Router, + ) { } + + @Input() pageInfo: IPageHeaderInfo; + @Input() customGoToPreviousPage: any; + @Input() hideBackButton: boolean; + + ngOnInit() { + } + + goToPreviousPage() { + if (this.customGoToPreviousPage) { + this.customGoToPreviousPage(); + } else { + const index = 1; // Start to retrieve the previous element + let url = this._navigationHistoryService.getFromLast(index); + + // If url is null then redirect to home page + if (url == null) { + url = '/'; + } + this._router.navigateByUrl(url); + } + } + +} diff --git a/src/app/components/paginator/paginator.component.html b/src/app/components/paginator/paginator.component.html index 157567c..dd5cef2 100644 --- a/src/app/components/paginator/paginator.component.html +++ b/src/app/components/paginator/paginator.component.html @@ -1,84 +1,64 @@ <div class="columns"> - <div class="column is-narrow has-text-centered"> - <!-- Dropdown list of pageSize number --> - <div class="dropdown" [ngClass]="{'is-active': pageSizeDropdownToggle}" (click)="pageSizeDropdownToggle=!pageSizeDropdownToggle"> - <div class="dropdown-trigger"> - <button class="button is-small" aria-haspopup="true" aria-controls="dropdown-menu"> - <span>{{ pageSize }}</span> - <span class="icon is-small"> - <i class="fas fa-angle-down" aria-hidden="true"></i> - </span> - </button> - </div> - <div class="dropdown-menu" id="dropdown-menu" role="menu"> - <div class="dropdown-content"> - <span role="button" - tabindex="0" - class="dropdown-item" - [ngClass]="{'is-active': nb === pageSize}" - *ngFor="let nb of pageSizeOptions" - (click)="changePageSize(nb)" - (keyup.enter)="changePageSize(nb)"> - {{ nb }} - </span> - </div> - </div> - </div> - </div> <div class="column"> - <div class="pagination is-centered is-small" role="navigation" aria-label="pagination" *ngIf="length > 0"> - <!-- First button --> - <button class="pagination-previous button" *ngIf="pageIndex === 1 || loading; else activeFirstPageLink" disabled> - <i class="fas fa-angle-double-left"></i> - </button> - <ng-template #activeFirstPageLink> - <button class="pagination-previous button" (click)="onPage(1)"> - <i class="fas fa-angle-double-left"></i> - </button> - </ng-template> - + <div class="pagination-dgl is-centered is-small" role="navigation" aria-label="pagination" *ngIf="length > 0"> <!-- Previous button --> - <button class="pagination-previous button" *ngIf="pageIndex === 1 || loading; else activePreviousLink" disabled> - <i class="fas fa-angle-left"></i> + <button class="button previous" *ngIf="pageIndex === 1 || loading; else activePreviousLink" disabled> + <svg xmlns="http://www.w3.org/2000/svg" id="chevron" viewBox="0 0 15 9"> + <path + d="M7.5 7.5c-.1 0-.3-.1-.4-.1l-6-6C1 1.1 1 .8 1.1.6s.5-.2.7 0l5.6 5.6L13 .6c.2-.2.5-.2.7 0s.2.5 0 .7l-6 6c.1.1-.1.2-.2.2z" + class="brandcolor" /> + <path + d="M7.5 7.5c-.1 0-.3-.1-.4-.1l-6-6C1 1.1 1 .8 1.1.6s.5-.2.7 0l5.6 5.6L13 .6c.2-.2.5-.2.7 0s.2.5 0 .7l-6 6c.1.1-.1.2-.2.2z" + class="brandcolor" /> + </svg> </button> <ng-template #activePreviousLink> - <button class="pagination-previous button" (click)="onPrev()"> - <i class="fas fa-angle-left"></i> + <button class="button previous" (click)="onPrev()"> + <svg xmlns="http://www.w3.org/2000/svg" id="chevron" viewBox="0 0 15 9"> + <path + d="M7.5 7.5c-.1 0-.3-.1-.4-.1l-6-6C1 1.1 1 .8 1.1.6s.5-.2.7 0l5.6 5.6L13 .6c.2-.2.5-.2.7 0s.2.5 0 .7l-6 6c.1.1-.1.2-.2.2z" + class="brandcolor" /> + <path + d="M7.5 7.5c-.1 0-.3-.1-.4-.1l-6-6C1 1.1 1 .8 1.1.6s.5-.2.7 0l5.6 5.6L13 .6c.2-.2.5-.2.7 0s.2.5 0 .7l-6 6c.1.1-.1.2-.2.2z" + class="brandcolor" /> + </svg> </button> </ng-template> <!-- List of pages number --> - <ul class="pagination-list"> + <ul> <ng-container *ngFor="let pageNum of getPages(); let i = index"> - <li *ngIf="displayEllipsis(i)"> - <span class="pagination-ellipsis">…</span> - </li> <li> - <button *ngIf="!loading; else pageNumberDisabled" (click)="onPage(pageNum)" class="pagination-link button" [ngClass]="{'is-current': pageNum === pageIndex}">{{ pageNum }}</button> + <button *ngIf="!loading; else pageNumberDisabled" (click)="onPage(pageNum)" class="button" + [ngClass]="{'is-current': pageNum === pageIndex}">{{ pageNum }}</button> <ng-template #pageNumberDisabled> - <button class="pagination-link button" [ngClass]="{'is-current': pageNum === pageIndex}" disabled>{{ pageNum }}</button> + <button class="button" [ngClass]="{'is-current': pageNum === pageIndex}" disabled>{{ pageNum }}</button> </ng-template> </li> </ng-container> </ul> <!-- Next button --> - <button class="pagination-next button" *ngIf="lastPage() || loading; else activeNextLink" disabled> - <i class="fas fa-angle-right"></i> + <button class="button" *ngIf="lastPage() || loading; else activeNextLink" disabled> + <svg xmlns="http://www.w3.org/2000/svg" id="chevron" viewBox="0 0 15 9"> + <path + d="M7.5 7.5c-.1 0-.3-.1-.4-.1l-6-6C1 1.1 1 .8 1.1.6s.5-.2.7 0l5.6 5.6L13 .6c.2-.2.5-.2.7 0s.2.5 0 .7l-6 6c.1.1-.1.2-.2.2z" + class="brandcolor" /> + <path + d="M7.5 7.5c-.1 0-.3-.1-.4-.1l-6-6C1 1.1 1 .8 1.1.6s.5-.2.7 0l5.6 5.6L13 .6c.2-.2.5-.2.7 0s.2.5 0 .7l-6 6c.1.1-.1.2-.2.2z" + class="brandcolor" /> + </svg> </button> <ng-template #activeNextLink> - <button class="pagination-next button" (click)="onNext()"> - <i class="fas fa-angle-right"></i> - </button> - </ng-template> - - <!-- Last button --> - <button class="pagination-next button" *ngIf="lastPage() || loading; else activeLastPageLink" disabled> - <i class="fas fa-angle-double-right"></i> - </button> - <ng-template #activeLastPageLink> - <button class="pagination-next button" (click)="onPage(totalPages())"> - <i class="fas fa-angle-double-right"></i> + <button class="button next" (click)="onNext()"> + <svg xmlns="http://www.w3.org/2000/svg" id="chevron" viewBox="0 0 15 9"> + <path + d="M7.5 7.5c-.1 0-.3-.1-.4-.1l-6-6C1 1.1 1 .8 1.1.6s.5-.2.7 0l5.6 5.6L13 .6c.2-.2.5-.2.7 0s.2.5 0 .7l-6 6c.1.1-.1.2-.2.2z" + class="brandcolor" /> + <path + d="M7.5 7.5c-.1 0-.3-.1-.4-.1l-6-6C1 1.1 1 .8 1.1.6s.5-.2.7 0l5.6 5.6L13 .6c.2-.2.5-.2.7 0s.2.5 0 .7l-6 6c.1.1-.1.2-.2.2z" + class="brandcolor" /> + </svg> </button> </ng-template> </div> diff --git a/src/app/components/paginator/paginator.component.scss b/src/app/components/paginator/paginator.component.scss index 37b33ec..a1becd9 100644 --- a/src/app/components/paginator/paginator.component.scss +++ b/src/app/components/paginator/paginator.component.scss @@ -1,10 +1,49 @@ +@import "./../../../scss/variables.scss"; + .dropdown-menu { min-width: unset; } + .dropdown-content { padding-top: unset; padding-bottom: unset; } + .dropdown-item { padding: 0.3rem 1rem; -} \ No newline at end of file +} + +ul, +li { + display: inline-block; +} + +.pagination-dgl { + text-align: center; + + .button { + border: none; + color: $grey-dark-color; + padding-left: 0.5em; + padding-right: 0.5em; + margin-left: 0.25rem; + + &:hover { + text-decoration: underline; + } + + &.is-current { + color: $tomato-color; + } + } +} + +svg { + width: 13px; + fill: $grey-dark-color; + transform: rotate(-90deg); +} + +.previous svg { + transform: rotate(90deg); +} diff --git a/src/app/components/paginator/paginator.component.spec.ts b/src/app/components/paginator/paginator.component.spec.ts new file mode 100644 index 0000000..b842808 --- /dev/null +++ b/src/app/components/paginator/paginator.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PaginatorComponent } from './paginator.component'; + +describe('PaginatorComponent', () => { + let component: PaginatorComponent; + let fixture: ComponentFixture<PaginatorComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [PaginatorComponent], + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PaginatorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/paginator/paginator.component.ts b/src/app/components/paginator/paginator.component.ts index c0ba5ee..0debb3c 100644 --- a/src/app/components/paginator/paginator.component.ts +++ b/src/app/components/paginator/paginator.component.ts @@ -63,10 +63,11 @@ export class PaginatorComponent implements OnInit { getPages(): number[] { const totalP = Math.ceil(this.length / this.pageSize); // Total number of page const p = this.pageIndex || 1; // Current page index - const pagesToShow = this.pagesToShow || 5; // Total number of pages to be displayed in the paginator + const midPage = Math.round(totalP / 2); + const pagesToShow = 3; // Total number of pages to be displayed in the paginator const pages: number[] = []; // Page number to be displayed pages.push(p); // Push the current page index - let times = pagesToShow - 1; // Number of page to be added to the displayed page + let times = pagesToShow; // Number of page to be added to the displayed page if (p !== 1) { // If current page is different from the first page remove one (first page automatically // added to the array at the end of the function) @@ -110,6 +111,10 @@ export class PaginatorComponent implements OnInit { if (pages.indexOf(totalP) === -1) { pages.push(totalP); } + // Adding half page if not already in the array + if (pages.indexOf(midPage) === -1) { + pages.push(midPage); + } // Reordering the array pages.sort((a, b) => a - b); return pages; diff --git a/src/app/components/resources/detail/resource-detail.component.html b/src/app/components/resources/detail/resource-detail.component.html index 60a5b01..142398b 100644 --- a/src/app/components/resources/detail/resource-detail.component.html +++ b/src/app/components/resources/detail/resource-detail.component.html @@ -1,113 +1,105 @@ -<ng-container *ngIf="resource"> - - <app-back-button [route]="'/resources'" [title]="'Retourner à la liste des ressources'"></app-back-button> - - <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}} +<section class="section page-container" *ngIf="resource"> + <app-page-header [pageInfo]="{title: title}"></app-page-header> + + <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">Id: </span> + <span>{{resource.id}}</span> + </p> + <p> + <span class="has-text-weight-bold">Acronyme: </span> + <span *ngIf="resource.acronym; else emptyAcronymWarning">{{resource.acronym}}</span> + <ng-template #emptyAcronymWarning> + <span class="empty-property">Non renseigné</span> + </ng-template> </p> - </header> - <div class="card-content"> - <div class="content"> - <p> - <span class="has-text-weight-bold">Id: </span> - <span>{{resource.id}}</span> - </p> - <p> - <span class="has-text-weight-bold">Acronyme: </span> - <span *ngIf="resource.acronym; else emptyAcronymWarning">{{resource.acronym}}</span> - <ng-template #emptyAcronymWarning> - <span class="empty-property">Non renseigné</span> - </ng-template> - </p> - - <p> - <span class="has-text-weight-bold">Type: </span> - <span *ngIf="resource.type; else emptyTypeWarning">{{resource.type}}</span> - <ng-template #emptyTypeWarning> - <span class="empty-property">Non renseigné</span> - </ng-template> - </p> - - <div *ngIf="resource.description"> - <span class="has-text-weight-bold">Description: </span> - <span *ngIf="resource.description; else emptyDescriptionWarning">{{resource.description}}</span> - <ng-template #emptyDescriptionWarning> - <span class="empty-property">Non renseigné</span> - </ng-template> - </div> - - <p> - <span class="has-text-weight-bold">Requêtable: </span> - <span class="icon has-text-success" - [ngClass]="{'has-text-success': resource.isQueryable, 'has-text-danger': !resource.isQueryable}"> - <i class="far fa-check-circle" - [ngClass]="{'fa-check-circle': resource.isQueryable, 'fa-times-circle': !resource.isQueryable}"></i> - </span> - </p> - <p> - <span class="has-text-weight-bold">Téléchargeable: </span> - <span class="icon has-text-success" - [ngClass]="{'has-text-success': resource.isDownloadable, 'has-text-danger': !resource.isDownloadable}"> - <i class="far fa-check-circle" - [ngClass]="{'fa-check-circle': resource.isDownloadable, 'fa-times-circle': !resource.isDownloadable}"></i> - </span> - </p> + <p> + <span class="has-text-weight-bold">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> - <span class="has-text-weight-bold">Standardisé: </span> - <span class="icon has-text-success" - [ngClass]="{'has-text-success': resource.isStandard, 'has-text-danger': !resource.isStandard}"> - <i class="far fa-check-circle" - [ngClass]="{'fa-check-circle': resource.isStandard, 'fa-times-circle': !resource.isStandard}"></i> - </span> - </p> + <div *ngIf="resource.description"> + <span class="has-text-weight-bold">Description: </span> + <span *ngIf="resource.description; else emptyDescriptionWarning">{{resource.description}}</span> + <ng-template #emptyDescriptionWarning> + <span class="empty-property">Non renseigné</span> + </ng-template> + </div> - <div *ngIf="resource.parametersUrl"> - <span class="has-text-weight-bold">Parametres URL: </span> - <span *ngIf="resource.parametersUrl; else emptyParameterUrlWarning">{{resource.parametersUrl}}</span> - <ng-template #emptyParameterUrlWarning> - <span class="empty-property">Non renseigné</span> - </ng-template> - </div> + <p> + <span class="has-text-weight-bold">Requêtable: </span> + <span class="icon has-text-success" + [ngClass]="{'has-text-success': resource.isQueryable, 'has-text-danger': !resource.isQueryable}"> + <i class="far fa-check-circle" + [ngClass]="{'fa-check-circle': resource.isQueryable, 'fa-times-circle': !resource.isQueryable}"></i> + </span> + </p> - <div *ngIf="resource.messageWarning"> - <span class="has-text-weight-bold">Message d'alerte: </span> - <span *ngIf="resource.messageWarning; else emptyMessageWarning">{{resource.messageWarning}}</span> - <ng-template #emptyMessageWarning> - <span class="empty-property">Non renseigné</span> - </ng-template> - </div> - <br> + <p> + <span class="has-text-weight-bold">Téléchargeable: </span> + <span class="icon has-text-success" + [ngClass]="{'has-text-success': resource.isDownloadable, 'has-text-danger': !resource.isDownloadable}"> + <i class="far fa-check-circle" + [ngClass]="{'fa-check-circle': resource.isDownloadable, 'fa-times-circle': !resource.isDownloadable}"></i> + </span> + </p> - <div> - <span class="has-text-weight-bold">Formats de sortie: </span> - <ul - *ngIf="resource.resourceFormats && resource.resourceFormats.length > 0; else noResourceFormatTemplate"> - <li *ngFor="let resourceFormat of resource.resourceFormats"> - {{ 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> + <p> + <span class="has-text-weight-bold">Standardisé: </span> + <span class="icon has-text-success" + [ngClass]="{'has-text-success': resource.isStandard, 'has-text-danger': !resource.isStandard}"> + <i class="far fa-check-circle" + [ngClass]="{'fa-check-circle': resource.isStandard, 'fa-times-circle': !resource.isStandard}"></i> + </span> + </p> + <div *ngIf="resource.parametersUrl"> + <span class="has-text-weight-bold">Parametres URL: </span> + <span *ngIf="resource.parametersUrl; else emptyParameterUrlWarning">{{resource.parametersUrl}}</span> + <ng-template #emptyParameterUrlWarning> + <span class="empty-property">Non renseigné</span> + </ng-template> + </div> + <div *ngIf="resource.messageWarning"> + <span class="has-text-weight-bold">Message d'alerte: </span> + <span *ngIf="resource.messageWarning; else emptyMessageWarning">{{resource.messageWarning}}</span> + <ng-template #emptyMessageWarning> + <span class="empty-property">Non renseigné</span> + </ng-template> </div> + <br> + + <div> + <span class="has-text-weight-bold">Formats de sortie: </span> + <ul + *ngIf="resource.resourceFormats && resource.resourceFormats.length > 0; else noResourceFormatTemplate"> + <li *ngFor="let resourceFormat of resource.resourceFormats"> + {{ 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> - - - </section> - -</ng-container> \ No newline at end of file + </div> +</section> \ 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 index 161b88b..d2ab5ad 100644 --- a/src/app/components/resources/detail/resource-detail.component.ts +++ b/src/app/components/resources/detail/resource-detail.component.ts @@ -14,16 +14,18 @@ import { ResourceService } from 'src/app/services/resource.service'; export class ResourceDetailComponent implements OnInit { resource: Resource; + title: string; constructor( - private route: ActivatedRoute, - private resourceService: ResourceService, + private _route: ActivatedRoute, + private _resourceService: ResourceService, ) { } ngOnInit(): void { - this.route.paramMap.pipe( - switchMap((params: ParamMap) => this.resourceService.findById(params.get('id')))) + this.title = this._route.snapshot.data.title; + this._route.paramMap.pipe( + 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 index 9e24f8e..c41e9d4 100644 --- a/src/app/components/resources/edit/resource-form.component.html +++ b/src/app/components/resources/edit/resource-form.component.html @@ -1,8 +1,5 @@ -<ng-container *ngIf="resource"> - - <app-back-button [route]="'/resources'" [title]="'Retourner à la liste des ressources'"></app-back-button> - - <h1>{{ title }}</h1> +<section class="section page-container" *ngIf="resource"> + <app-page-header [pageInfo]="{title: title}"></app-page-header> <form [formGroup]="form" (ngSubmit)="onSubmit()" class="columns is-centered is-marginless"> <div class="column is-7"> @@ -90,14 +87,14 @@ </div> <div class="field"> - <label class="label required" for="parametersUrl">Paramètres URL</label> + <label class="label" for="parametersUrl">Paramètres URL</label> <div class="control"> <input class="input" type="text" formControlName="parametersUrl" id="parametersUrl"> </div> </div> <div class="field"> - <label class="label required" for="messageWarning">Message d'alerte</label> + <label class="label" for="messageWarning">Message d'alerte</label> <div class="control"> <input class="input" type="text" formControlName="messageWarning" id="messageWarning"> </div> @@ -178,4 +175,4 @@ </div> </form> -</ng-container> \ No newline at end of file +</section> \ No newline at end of file diff --git a/src/app/components/resources/edit/resource-form.component.ts b/src/app/components/resources/edit/resource-form.component.ts index b40283e..c379dc1 100644 --- a/src/app/components/resources/edit/resource-form.component.ts +++ b/src/app/components/resources/edit/resource-form.component.ts @@ -52,8 +52,8 @@ export class ResourceFormComponent implements OnInit { this.resource.resourceFormats.forEach((resourceFormat) => { resourceFormats.push(this._fb.group({ formatId: [resourceFormat.format.id, Validators.required], - isProjectable: resourceFormat.isProjectable, - isCuttable: resourceFormat.isCuttable, + isProjectable: [resourceFormat.isProjectable, Validators.required], + isCuttable: [resourceFormat.isCuttable, Validators.required], id: resourceFormat.id, })); }); diff --git a/src/app/components/resources/list/resources.component.html b/src/app/components/resources/list/resources.component.html index 298d7dd..f544a69 100644 --- a/src/app/components/resources/list/resources.component.html +++ b/src/app/components/resources/list/resources.component.html @@ -1,194 +1,186 @@ <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 class="section page-container"> + <app-page-header [pageInfo]="pageHeaderInfo" [hideBackButton]="true"></app-page-header> + <div class="add-item-link has-text-right"> + <a class="button button-gl" [routerLink]="['new']"> + Ajouter + </a> + </div> + <div class="table entity-list-table"> + <div class="header columns is-marginless"> + <div class="column is-2"> + <span (click)="sortBy('name')" class="is-sortable"> + <span class="sort-icons"> + <span class="icon"> + <i class="fas fa-sort-up" + [ngClass]="{'icon-red': sortOptions.value === 'name' && sortOptions.order === 'desc'}"></i> + </span> + <span class="icon"> + <i class="fas fa-sort-down" + [ngClass]="{'icon-red': sortOptions.value === 'name' && sortOptions.order === 'asc'}"></i> + </span> + </span> + <span class="column-title" [ngClass]="{'active': sortOptions.value === name}">Nom</span> + </span> + </div> + <div class="column is-1"> + <span (click)="sortBy('acronym')" class="is-sortable"> + <span class="sort-icons"> + <span class="icon"> + <i class="fas fa-sort-up" + [ngClass]="{'icon-red': sortOptions.value === 'acronym' && sortOptions.order === 'desc'}"></i> + </span> + <span class="icon"> + <i class="fas fa-sort-down" + [ngClass]="{'icon-red': sortOptions.value === 'acronym' && sortOptions.order === 'asc'}"></i> + </span> + </span> + <span class="column-title" [ngClass]="{'active': sortOptions.value === acronym}">Acronyme</span> + </span> + </div> + <div class="column is-1"> + <span (click)="sortBy('type')" class="is-sortable"> + <span class="sort-icons"> + <span class="icon"> + <i class="fas fa-sort-up" + [ngClass]="{'icon-red': sortOptions.value === 'type' && sortOptions.order === 'desc'}"></i> + </span> + <span class="icon"> + <i class="fas fa-sort-down" + [ngClass]="{'icon-red': sortOptions.value === 'type' && sortOptions.order === 'asc'}"></i> + </span> + </span> + <span class="column-title" [ngClass]="{'active': sortOptions.value === type}">Type</span> + </span> + </div> + <div class="column is-4"> + <span (click)="sortBy('description')" class="is-sortable"> + <span class="sort-icons"> + <span class="icon"> + <i class="fas fa-sort-up" + [ngClass]="{'icon-red': sortOptions.value === 'description' && sortOptions.order === 'desc'}"></i> + </span> + <span class="icon"> + <i class="fas fa-sort-down" + [ngClass]="{'icon-red': sortOptions.value === 'description' && sortOptions.order === 'asc'}"></i> + </span> + </span> + <span class="column-title" [ngClass]="{'active': sortOptions.value === description}">Description</span> + </span> + </div> + <div class="column is-1 has-text-centered"> + <span (click)="sortBy('isQueryable')" class="is-sortable"> + <span class="sort-icons"> + <span class="icon"> + <i class="fas fa-sort-up" + [ngClass]="{'icon-red': sortOptions.value === 'isQueryable' && sortOptions.order === 'desc'}"></i> + </span> + <span class="icon"> + <i class="fas fa-sort-down" + [ngClass]="{'icon-red': sortOptions.value === 'isQueryable' && sortOptions.order === 'asc'}"></i> + </span> + </span> + <span class="column-title" [ngClass]="{'active': sortOptions.value === isQueryable}">Requêtable</span> + </span> + </div> + <div class="column is-1 has-text-centered"> + <span (click)="sortBy('isDownloadable')" class="is-sortable"> + <span class="sort-icons"> + <span class="icon"> + <i class="fas fa-sort-up" + [ngClass]="{'icon-red': sortOptions.value === 'isDownloadable' && sortOptions.order === 'desc'}"></i> + </span> + <span class="icon"> + <i class="fas fa-sort-down" + [ngClass]="{'icon-red': sortOptions.value === 'isDownloadable' && sortOptions.order === 'asc'}"></i> + </span> + </span> + <span class="column-title" + [ngClass]="{'active': sortOptions.value === isDownloadable}">Téléchargeable</span> + </span> + </div> + <div class="column is-1 has-text-centered"> + <span (click)="sortBy('isStandard')" class="is-sortable"> + <span class="sort-icons"> + <span class="icon"> + <i class="fas fa-sort-up" + [ngClass]="{'icon-red': sortOptions.value === 'isStandard' && sortOptions.order === 'desc'}"></i> + </span> + <span class="icon"> + <i class="fas fa-sort-down" + [ngClass]="{'icon-red': sortOptions.value === 'isStandard' && sortOptions.order === 'asc'}"></i> + </span> + </span> + <span class="column-title" [ngClass]="{'active': sortOptions.value === isStandard}">Standard</span> + </span> + </div> + <div class="column is-1 has-text-centered"> + <span class="column-title">Actions</span> </div> </div> - <div class="add-item-link has-text-right"> - <a class="button button-gl" [routerLink]="['new']"> - Ajouter - </a> - </div> - <div class="table entity-list-table"> - <div class="header columns is-marginless"> + <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-2"> - <span (click)="sortBy('name')" class="is-sortable"> - <span class="sort-icons"> - <span class="icon"> - <i class="fas fa-sort-up" - [ngClass]="{'icon-red': sortOptions.value === 'name' && sortOptions.order === 'desc'}"></i> - </span> - <span class="icon"> - <i class="fas fa-sort-down" - [ngClass]="{'icon-red': sortOptions.value === 'name' && sortOptions.order === 'asc'}"></i> - </span> - </span> - <span class="column-title" [ngClass]="{'active': sortOptions.value === name}">Nom</span> + <span> + {{ resource.name}} </span> + </div> <div class="column is-1"> - <span (click)="sortBy('acronym')" class="is-sortable"> - <span class="sort-icons"> - <span class="icon"> - <i class="fas fa-sort-up" - [ngClass]="{'icon-red': sortOptions.value === 'acronym' && sortOptions.order === 'desc'}"></i> - </span> - <span class="icon"> - <i class="fas fa-sort-down" - [ngClass]="{'icon-red': sortOptions.value === 'acronym' && sortOptions.order === 'asc'}"></i> - </span> - </span> - <span class="column-title" [ngClass]="{'active': sortOptions.value === acronym}">Acronyme</span> + <span> + {{ resource.acronym}} </span> + </div> <div class="column is-1"> - <span (click)="sortBy('type')" class="is-sortable"> - <span class="sort-icons"> - <span class="icon"> - <i class="fas fa-sort-up" - [ngClass]="{'icon-red': sortOptions.value === 'type' && sortOptions.order === 'desc'}"></i> - </span> - <span class="icon"> - <i class="fas fa-sort-down" - [ngClass]="{'icon-red': sortOptions.value === 'type' && sortOptions.order === 'asc'}"></i> - </span> - </span> - <span class="column-title" [ngClass]="{'active': sortOptions.value === type}">Type</span> + <span> + {{ resource.type}} </span> + </div> <div class="column is-4"> - <span (click)="sortBy('description')" class="is-sortable"> - <span class="sort-icons"> - <span class="icon"> - <i class="fas fa-sort-up" - [ngClass]="{'icon-red': sortOptions.value === 'description' && sortOptions.order === 'desc'}"></i> - </span> - <span class="icon"> - <i class="fas fa-sort-down" - [ngClass]="{'icon-red': sortOptions.value === 'description' && sortOptions.order === 'asc'}"></i> - </span> - </span> - <span class="column-title" [ngClass]="{'active': sortOptions.value === description}">Description</span> + <span> + {{ resource.description | slice:0:300}} </span> </div> <div class="column is-1 has-text-centered"> - <span (click)="sortBy('isQueryable')" class="is-sortable"> - <span class="sort-icons"> - <span class="icon"> - <i class="fas fa-sort-up" - [ngClass]="{'icon-red': sortOptions.value === 'isQueryable' && sortOptions.order === 'desc'}"></i> - </span> - <span class="icon"> - <i class="fas fa-sort-down" - [ngClass]="{'icon-red': sortOptions.value === 'isQueryable' && sortOptions.order === 'asc'}"></i> - </span> - </span> - <span class="column-title" [ngClass]="{'active': sortOptions.value === isQueryable}">Requêtable</span> + <span class="icon has-text-success" *ngIf="resource.isQueryable"> + <i class="far fa-check-circle"></i> + </span> + <span class="icon has-text-danger" *ngIf="!resource.isQueryable"> + <i class="far fa-times-circle"></i> </span> </div> <div class="column is-1 has-text-centered"> - <span (click)="sortBy('isDownloadable')" class="is-sortable"> - <span class="sort-icons"> - <span class="icon"> - <i class="fas fa-sort-up" - [ngClass]="{'icon-red': sortOptions.value === 'isDownloadable' && sortOptions.order === 'desc'}"></i> - </span> - <span class="icon"> - <i class="fas fa-sort-down" - [ngClass]="{'icon-red': sortOptions.value === 'isDownloadable' && sortOptions.order === 'asc'}"></i> - </span> - </span> - <span class="column-title" - [ngClass]="{'active': sortOptions.value === isDownloadable}">Téléchargeable</span> + <span class="icon has-text-success" *ngIf="resource.isDownloadable"> + <i class="far fa-check-circle"></i> + </span> + <span class="icon has-text-danger" *ngIf="!resource.isDownloadable"> + <i class="far fa-times-circle"></i> </span> </div> <div class="column is-1 has-text-centered"> - <span (click)="sortBy('isStandard')" class="is-sortable"> - <span class="sort-icons"> - <span class="icon"> - <i class="fas fa-sort-up" - [ngClass]="{'icon-red': sortOptions.value === 'isStandard' && sortOptions.order === 'desc'}"></i> - </span> - <span class="icon"> - <i class="fas fa-sort-down" - [ngClass]="{'icon-red': sortOptions.value === 'isStandard' && sortOptions.order === 'asc'}"></i> - </span> - </span> - <span class="column-title" [ngClass]="{'active': sortOptions.value === isStandard}">Standard</span> + <span class="icon has-text-success" *ngIf="resource.isStandard"> + <i class="far fa-check-circle"></i> + </span> + <span class="icon has-text-danger" *ngIf="!resource.isStandard"> + <i class="far fa-times-circle"></i> </span> </div> <div class="column is-1 has-text-centered"> - <span class="column-title">Actions</span> + <app-crud-buttons [id]="resource.id" (delete)="displayDeletePopup($event)"></app-crud-buttons> </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-2"> - <span> - {{ resource.name}} - </span> - - </div> - <div class="column is-1"> - <span> - {{ resource.acronym}} - </span> - - </div> - <div class="column is-1"> - <span> - {{ resource.type}} - </span> - - </div> - <div class="column is-4"> - <span> - {{ resource.description | slice:0:300}} - </span> - </div> - <div class="column is-1 has-text-centered"> - <span class="icon has-text-success" *ngIf="resource.isQueryable"> - <i class="far fa-check-circle"></i> - </span> - <span class="icon has-text-danger" *ngIf="!resource.isQueryable"> - <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.isDownloadable"> - <i class="far fa-check-circle"></i> - </span> - <span class="icon has-text-danger" *ngIf="!resource.isDownloadable"> - <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.isStandard"> - <i class="far fa-check-circle"></i> - </span> - <span class="icon has-text-danger" *ngIf="!resource.isStandard"> - <i class="far fa-times-circle"></i> - </span> - </div> - <div class="column is-1 has-text-centered"> - <app-crud-buttons [id]="resource.id" (delete)="displayDeletePopup($event)"></app-crud-buttons> - </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 class="columns is-marginless paginator"> + <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> -</ng-container> \ No newline at end of file + </div> \ No newline at end of file diff --git a/src/app/components/resources/list/resources.component.scss b/src/app/components/resources/list/resources.component.scss index 60e54cc..8b13789 100644 --- a/src/app/components/resources/list/resources.component.scss +++ b/src/app/components/resources/list/resources.component.scss @@ -1,3 +1 @@ -.section { - padding-top: 0; -} + diff --git a/src/app/components/resources/list/resources.component.ts b/src/app/components/resources/list/resources.component.ts index a56ed6d..b19fe3e 100644 --- a/src/app/components/resources/list/resources.component.ts +++ b/src/app/components/resources/list/resources.component.ts @@ -1,8 +1,9 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, OnInit } 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'; +import { IPageHeaderInfo } from '../../../models/page.model'; @Component({ selector: 'app-resources', @@ -11,6 +12,9 @@ import { PaginatorOptions } from 'src/app/models/paginator-options.model'; }) export class ResourcesComponent implements OnInit { + pageHeaderInfo: IPageHeaderInfo = { + title: '', + }; resources: Resource[]; searchChangeSub: Subscription; @@ -58,6 +62,8 @@ export class ResourcesComponent implements OnInit { this.resources = items.resources; this.totalElement = items.totalCount; + this.pageHeaderInfo.title = `${this.totalElement} ressources trouvées`; + this.paginator.limit = this.resourcesService.limit; this.paginator.pageIndex = this.resourcesService.pageNumber; this.paginator.length = items.totalCount; diff --git a/src/app/models/image-upload.model.ts b/src/app/models/image-upload.model.ts index 0c4a768..26160e8 100644 --- a/src/app/models/image-upload.model.ts +++ b/src/app/models/image-upload.model.ts @@ -2,4 +2,5 @@ export interface IImageUploadFieldParams { label: string; inputName: string; existingImageUrl?: string; + isRequired?: boolean; } diff --git a/src/app/models/page.model.ts b/src/app/models/page.model.ts new file mode 100644 index 0000000..94a7507 --- /dev/null +++ b/src/app/models/page.model.ts @@ -0,0 +1,7 @@ +export interface IPageHeaderInfo { + title: string; + metadataSubtitle?: string; + surtitle?: string; + subtitle?: string; + hasBetaStyle?: boolean; +} diff --git a/src/app/services/index.ts b/src/app/services/index.ts index 34d4ee5..22c1f82 100644 --- a/src/app/services/index.ts +++ b/src/app/services/index.ts @@ -3,6 +3,7 @@ import { OrganizationService } from './organization.service'; import { ResourceService } from './resource.service'; import { FormatService } from './format.service'; import { NotificationService } from './notification.service'; +import { NavigationHistoryService } from './navigation-history.service'; export { AppConfigService, @@ -10,6 +11,7 @@ export { ResourceService, FormatService, NotificationService, + NavigationHistoryService, }; // tslint:disable-next-line:variable-name @@ -19,4 +21,5 @@ export const AppServices = [ ResourceService, FormatService, NotificationService, + NavigationHistoryService, ]; diff --git a/src/app/services/navigation-history.service.ts b/src/app/services/navigation-history.service.ts new file mode 100644 index 0000000..608c4a5 --- /dev/null +++ b/src/app/services/navigation-history.service.ts @@ -0,0 +1,27 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export class NavigationHistoryService { + history: string[] = []; + maxHistoryLength = 20; // Avoid to store too many url limite back history to 20 + + constructor( + ) { } + + add(url: string) { + // If max size reach remove the oldest url + if (this.history.length >= this.maxHistoryLength) { + this.history.shift(); + } + this.history.push(url); + } + + getFromLast(index: number): string { + const position = this.history.length - 1 - index; + let res = null; + if (position >= 0) { + res = this.history[position]; + } + return res; + } +} diff --git a/src/assets/img/left_arrow.svg b/src/assets/img/left_arrow.svg new file mode 100644 index 0000000..ecd6f77 --- /dev/null +++ b/src/assets/img/left_arrow.svg @@ -0,0 +1,3 @@ +<svg width="6" height="10" viewBox="0 0 6 10" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M5 1L1 5L5 9" stroke="#818080" stroke-linecap="round" stroke-linejoin="round"/> +</svg> diff --git a/src/styles.scss b/src/styles.scss index ff7533c..0982233 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -137,6 +137,17 @@ textarea.ng-invalid:not(form).ng-touched { } } +.page-container { + min-height: calc(100% - 1rem); + max-width: 100%; + background-color: white; + padding-top: 0; + + @media screen and (min-width: $tablet) { + margin: 1rem 1rem 0 1rem; + } +} + // Style for tables .add-item-link { margin-bottom: 1.25rem; @@ -188,4 +199,8 @@ textarea.ng-invalid:not(form).ng-touched { .is-sortable .column-title { cursor: pointer; } + + .paginator { + border-top: 1px solid $grey-super-light-color; + } } -- GitLab