From c896a08c04389372e42d246691d1cea7640707bd Mon Sep 17 00:00:00 2001 From: FORESTIER Fabien <fabien.forestier@soprasteria.com> Date: Mon, 22 Jul 2019 17:22:45 +0200 Subject: [PATCH] WIP - changelog list --- src/app/app.routing.module.ts | 9 ++ .../changelog/list/changelog.component.html | 68 ++++++++++++ .../changelog/list/changelog.component.scss | 0 .../changelog/list/changelog.component.ts | 105 ++++++++++++++++++ src/app/components/index.ts | 3 + src/app/components/menu/menu.component.html | 7 ++ .../list/organizations.component.html | 4 +- .../list/organizations.component.ts | 3 +- src/app/models/changelog.model.ts | 39 +++++++ src/app/services/app-config.service.ts | 3 + src/app/services/changelog.service.ts | 98 ++++++++++++++++ src/app/services/index.ts | 3 + 12 files changed, 339 insertions(+), 3 deletions(-) create mode 100644 src/app/components/changelog/list/changelog.component.html create mode 100644 src/app/components/changelog/list/changelog.component.scss create mode 100644 src/app/components/changelog/list/changelog.component.ts create mode 100644 src/app/models/changelog.model.ts create mode 100644 src/app/services/changelog.service.ts diff --git a/src/app/app.routing.module.ts b/src/app/app.routing.module.ts index f58c4ca..4071bf8 100644 --- a/src/app/app.routing.module.ts +++ b/src/app/app.routing.module.ts @@ -8,6 +8,7 @@ import { ResourceFormComponent } from './components/resources/edit/resource-form import { ResourceDetailComponent } from './components/resources/detail/resource-detail.component'; import { FormatsComponent, FormatDetailComponent, FormatFormComponent } from './components'; import { AuthenticatedGuard } from './user/guards/authenticated.guard'; +import { ChangelogComponent } from './components/changelog/list/changelog.component'; const appRoutes: Routes = [ { @@ -111,6 +112,14 @@ const appRoutes: Routes = [ title: 'Detail du format', }, }, + { + path: 'changelog', + component: ChangelogComponent, + canActivate: [AuthenticatedGuard], + data: { + title: 'Changelog', + }, + }, ]; @NgModule({ diff --git a/src/app/components/changelog/list/changelog.component.html b/src/app/components/changelog/list/changelog.component.html new file mode 100644 index 0000000..703b91a --- /dev/null +++ b/src/app/components/changelog/list/changelog.component.html @@ -0,0 +1,68 @@ +<section class="section page-container" *ngIf="changelogs"> + <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('version')" class="is-sortable"> + <span class="sort-icons"> + <span class="icon"> + <i class="fas fa-sort-up" + [ngClass]="{'icon-red': sortOptions.value === 'version' && sortOptions.order === 'desc'}"></i> + </span> + <span class="icon"> + <i class="fas fa-sort-down" + [ngClass]="{'icon-red': sortOptions.value === 'version' && sortOptions.order === 'asc'}"></i> + </span> + </span> + <span class="column-title" [ngClass]="{'active': sortOptions.value === version}">Version</span> + </span> + </div> + <div class="column is-2"> + <span (click)="sortBy('language')" class="is-sortable"> + <span class="sort-icons"> + <span class="icon"> + <i class="fas fa-sort-up" + [ngClass]="{'icon-red': sortOptions.value === 'language' && sortOptions.order === 'desc'}"></i> + </span> + <span class="icon"> + <i class="fas fa-sort-down" + [ngClass]="{'icon-red': sortOptions.value === 'language' && sortOptions.order === 'asc'}"></i> + </span> + </span> + <span class="column-title" [ngClass]="{'active': sortOptions.value === language}">Langue</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 changelog of changelogs; let i=index; let odd=odd; let even=even;" + [ngClass]="{ odd: odd, even: even }"> + <div class="column is-2"> + <span>{{ changelog.version }}</span> + </div> + <div class="column is-2"> + <span>{{ changelog.language }}</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> + <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)"> + </app-paginator> + </div> + </div> + </div> +</section> \ No newline at end of file diff --git a/src/app/components/changelog/list/changelog.component.scss b/src/app/components/changelog/list/changelog.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/components/changelog/list/changelog.component.ts b/src/app/components/changelog/list/changelog.component.ts new file mode 100644 index 0000000..1641067 --- /dev/null +++ b/src/app/components/changelog/list/changelog.component.ts @@ -0,0 +1,105 @@ +import { Component, OnInit } from '@angular/core'; +import { PaginatorOptions } from 'src/app/models/paginator-options.model'; +import { IPageHeaderInfo } from '../../../models/page.model'; +import { Subscription } from 'rxjs'; +import { ChangelogService } from '../../../services'; +import { ChangelogRO, Changelog } from '../../../models/changelog.model'; + +@Component({ + selector: 'app-changelog', + templateUrl: './changelog.component.html', + styleUrls: ['./changelog.component.scss'], +}) +export class ChangelogComponent implements OnInit { + + pageHeaderInfo: IPageHeaderInfo = { + title: '', + }; + changelogs: Changelog[]; + searchChangeSub: Subscription; + + // Paginator options + paginator: PaginatorOptions; + pageSize = 10; + pageSizeOptions = [5, 10, 25, 100]; + + sortValue: string; + + totalElement: number; + filters = { + name: '', + }; + where = {}; + + constructor( + private changelogService: ChangelogService, + ) { + this.paginator = { + pageIndex: this.changelogService.pageNumber, + length: 0, + limit: this.changelogService.limit, + pageSizeOptions: [5, 10, 20], + }; + } + + ngOnInit(): void { + this.changelogService.sortOptions = { + value: 'name', + order: 'asc', + }; + this.search(); + + this.searchChangeSub = this.changelogService.searchChange$.subscribe( + () => { + this.search(); + }, + ); + } + + private search() { + this.changelogService.getChangelogs() + .subscribe((items: ChangelogRO) => { + this.changelogs = items.changelogs; + this.totalElement = items.totalCount; + + this.pageHeaderInfo.title = `${this.totalElement} formats trouvés`; + + this.paginator.limit = this.changelogService.limit; + this.paginator.pageIndex = this.changelogService.pageNumber; + this.paginator.length = items.totalCount; + }); + } + + // When pagination is changed by user, we update datasetList with new pagination options + changePagination(pageIndex) { + this.changelogService.paginationChanged(this.paginator.limit, pageIndex); + } + + changePageSize(pageSize) { + this.changelogService.paginationChanged(pageSize, 1); + } + + sortBy(key: string) { + if (this.changelogService.sortOptions.value === key) { + this.changelogService.reverseSortOrder(); + } else { + this.changelogService.sortOptions.value = key; + this.changelogService.sortOptions.order = 'asc'; + } + this.search(); + } + + get sortOptions() { + return this.changelogService.sortOptions; + } + + displayDeletePopup(formatId) { + const pop = confirm('Etes vous sûr de vouloir supprimer ce format ?'); + if (pop) { + // this.changelogService.delete(formatId).subscribe(() => { + // this.changelogService.pageNumber = 1; + // this.search(); + // }); + } + } +} diff --git a/src/app/components/index.ts b/src/app/components/index.ts index 90f5e96..c58b8ca 100644 --- a/src/app/components/index.ts +++ b/src/app/components/index.ts @@ -14,6 +14,7 @@ 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'; +import { ChangelogComponent } from './changelog/list/changelog.component'; export { MenuComponent, @@ -32,6 +33,7 @@ export { ImageUploadComponent, NotificationsComponent, PageHeaderComponent, + ChangelogComponent, }; // tslint:disable-next-line:variable-name @@ -52,4 +54,5 @@ export const AppComponents = [ ImageUploadComponent, NotificationsComponent, PageHeaderComponent, + ChangelogComponent, ]; diff --git a/src/app/components/menu/menu.component.html b/src/app/components/menu/menu.component.html index f0b4848..0d5bd17 100644 --- a/src/app/components/menu/menu.component.html +++ b/src/app/components/menu/menu.component.html @@ -27,5 +27,12 @@ <span class="label-menu">Formats</span> </a> </li> + <li><a [routerLink]="['/', 'changelog']" routerLinkActive="active-link"> + <span class="icon"> + <i class="fas fa-clipboard-list"></i> + </span> + <span class="label-menu">Changelog</span> + </a> + </li> </ul> </aside> \ No newline at end of file diff --git a/src/app/components/organizations/list/organizations.component.html b/src/app/components/organizations/list/organizations.component.html index f30fe6a..bfae60a 100644 --- a/src/app/components/organizations/list/organizations.component.html +++ b/src/app/components/organizations/list/organizations.component.html @@ -1,11 +1,11 @@ -<div class="section page-container" *ngIf="organizations"> +<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="table entity-list-table" *ngIf="organizations"> <div class="header columns is-marginless"> <div class="column is-2"> <span (click)="sortBy('name')" class="is-sortable"> diff --git a/src/app/components/organizations/list/organizations.component.ts b/src/app/components/organizations/list/organizations.component.ts index c2c4551..c092bc5 100644 --- a/src/app/components/organizations/list/organizations.component.ts +++ b/src/app/components/organizations/list/organizations.component.ts @@ -62,7 +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.pageHeaderInfo.title = items.totalCount ? + `${this.totalElement} producteurs de données trouvés` : '0 producteur de données trouvé'; this.paginator.limit = this.organizationsService.limit; this.paginator.pageIndex = this.organizationsService.pageNumber; diff --git a/src/app/models/changelog.model.ts b/src/app/models/changelog.model.ts new file mode 100644 index 0000000..940be35 --- /dev/null +++ b/src/app/models/changelog.model.ts @@ -0,0 +1,39 @@ +export class ChangelogRO { + changelogs: Changelog[]; + totalCount: number; + + constructor(changelogs, totalCount) { + this.changelogs = changelogs; + this.totalCount = totalCount; + } +} + +export class Changelog { + version: string; + createDate: string; // bon type ? + updateDate: string; + language: string; + majorImprovements: string[]; + minorImprovements: string[]; + bugfixes: string[]; + + constructor(changelog?: IChangelog) { + this.version = changelog && changelog.version ? changelog.version : null; + this.createDate = changelog && changelog.createDate ? changelog.createDate : null; + this.updateDate = changelog && changelog.updateDate ? changelog.updateDate : null; + this.language = changelog && changelog.language ? changelog.language : null; + this.majorImprovements = changelog && changelog.majorImprovements ? changelog.majorImprovements : []; + this.minorImprovements = changelog && changelog.minorImprovements ? changelog.minorImprovements : []; + this.bugfixes = changelog && changelog.bugfixes ? changelog.bugfixes : []; + } +} + +export interface IChangelog { + version: string; + createDate: string; // bon type ? + updateDate: string; + language: string; + majorImprovements: string[]; + minorImprovements: string[]; + bugfixes: string[]; +} diff --git a/src/app/services/app-config.service.ts b/src/app/services/app-config.service.ts index c8fb343..ccd0f66 100644 --- a/src/app/services/app-config.service.ts +++ b/src/app/services/app-config.service.ts @@ -16,6 +16,9 @@ export class AppConfig { middlewareLegacyAuth: { url: string; }; + changelog: { + url: string; + }; } export let APP_CONFIG: AppConfig; diff --git a/src/app/services/changelog.service.ts b/src/app/services/changelog.service.ts new file mode 100644 index 0000000..5dfc620 --- /dev/null +++ b/src/app/services/changelog.service.ts @@ -0,0 +1,98 @@ +import { Injectable } from '@angular/core'; +import { Observable, Subject } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { HttpClient } from '@angular/common/http'; +import { APP_CONFIG } from './app-config.service'; +import { ChangelogRO, IChangelog, Changelog } from '../models/changelog.model'; + +@Injectable() +export class ChangelogService { + + changelogServiceUrl: string; + limit: number; + pageNumber: number; + sortOptions: { + value: string, + order: string, + }; + + private _searchChangeSubject: Subject<any>; + + constructor( + private _httpClient: HttpClient) { + this.changelogServiceUrl = `${APP_CONFIG.changelog.url}changelog`; + this._searchChangeSubject = new Subject<any>(); + this.limit = 10; + this.pageNumber = 1; + } + + getChangelogs(): Observable<ChangelogRO> { + 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<IChangelog[]>(this.changelogServiceUrl + query, { observe: 'response' }).pipe( + map((response) => { + const totalCount = response.headers.get('Content-Range'); + const changelogs = []; + console.log(response.body); + response.body.forEach((changelog) => { + changelogs.push(new Changelog(changelog)); + }); + return new ChangelogRO(changelogs, parseInt(totalCount, 10)); + })); + } + + // getAllFormats(): Observable<Format[]> { + // return this._httpClient.get<IFormat[]>(this.changelogServiceUrl).pipe( + // map(body => body.map(format => new Format(format))), + // ); + // } + + // findById(id): Observable<Format> { + // return this._httpClient.get<IFormat>(this.changelogServiceUrl + id).pipe( + // map((response) => { + // return new Format(response); + // }), + // ); + // } + + // delete(id) { + // return this._httpClient.delete(this.changelogServiceUrl + id, { withCredentials: true }); + // } + + // replaceOrCreate(data): Observable<Format> { + // if (data.id) { + // return this._httpClient.put<IFormat>(this.changelogServiceUrl + data.id, data, { withCredentials: true }).pipe( + // map((response) => { + // return new Format(response); + // }), + // ); + // } + // return this._httpClient.post<IFormat>(this.changelogServiceUrl, data, { withCredentials: true }).pipe( + // map((response) => { + // return new Format(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/app/services/index.ts b/src/app/services/index.ts index 22c1f82..d9eaec2 100644 --- a/src/app/services/index.ts +++ b/src/app/services/index.ts @@ -4,6 +4,7 @@ import { ResourceService } from './resource.service'; import { FormatService } from './format.service'; import { NotificationService } from './notification.service'; import { NavigationHistoryService } from './navigation-history.service'; +import { ChangelogService } from './changelog.service'; export { AppConfigService, @@ -12,6 +13,7 @@ export { FormatService, NotificationService, NavigationHistoryService, + ChangelogService, }; // tslint:disable-next-line:variable-name @@ -22,4 +24,5 @@ export const AppServices = [ FormatService, NotificationService, NavigationHistoryService, + ChangelogService, ]; -- GitLab