From f05c475af6896dc9ce252056186ba41bf2055535 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Agneray?= <francois.agneray@lam.fr> Date: Fri, 1 Apr 2022 11:51:05 +0200 Subject: [PATCH] Create containers for dataset images --- .../dataset/dataset-card.component.html | 4 + .../dataset/dataset-form.component.html | 18 ----- .../dataset/dataset-form.component.ts | 10 --- .../components/image/image-form.component.ts | 7 +- .../image/image-table.component.html | 60 +-------------- .../components/image/image-table.component.ts | 38 +--------- .../containers/edit-dataset.component.html | 10 --- .../containers/edit-dataset.component.ts | 36 +-------- .../containers/edit-image.component.html | 47 ++++++++++++ .../containers/edit-image.component.ts | 76 +++++++++++++++++++ .../containers/image-list.component.html | 38 ++++++++++ .../containers/image-list.component.ts | 51 +++++++++++++ .../containers/new-image.component.html | 46 +++++++++++ .../dataset/containers/new-image.component.ts | 65 ++++++++++++++++ .../dataset/dataset-routing.module.ts | 11 ++- .../app/metamodel/effects/image.effects.ts | 21 ++++- .../app/metamodel/selectors/image.selector.ts | 6 ++ 17 files changed, 375 insertions(+), 169 deletions(-) create mode 100644 client/src/app/admin/instance/dataset/containers/edit-image.component.html create mode 100644 client/src/app/admin/instance/dataset/containers/edit-image.component.ts create mode 100644 client/src/app/admin/instance/dataset/containers/image-list.component.html create mode 100644 client/src/app/admin/instance/dataset/containers/image-list.component.ts create mode 100644 client/src/app/admin/instance/dataset/containers/new-image.component.html create mode 100644 client/src/app/admin/instance/dataset/containers/new-image.component.ts diff --git a/client/src/app/admin/instance/dataset/components/dataset/dataset-card.component.html b/client/src/app/admin/instance/dataset/components/dataset/dataset-card.component.html index 7ea2e12a..0c757a81 100644 --- a/client/src/app/admin/instance/dataset/components/dataset/dataset-card.component.html +++ b/client/src/app/admin/instance/dataset/components/dataset/dataset-card.component.html @@ -17,6 +17,10 @@ <span class="fas fa-cog"></span> </a> + <a routerLink="/admin/instance/configure-instance/{{ instance.name }}/dataset/image-list/{{dataset.name}}" class="btn btn-outline-primary" title="Configure images"> + <span class="fas fa-image"></span> + </a> + <a title="Edit this dataset" routerLink="/admin/instance/configure-instance/{{ instance.name }}/dataset/edit-dataset/{{dataset.name}}" class="btn btn-outline-primary"> <span class="fas fa-edit"></span> </a> diff --git a/client/src/app/admin/instance/dataset/components/dataset/dataset-form.component.html b/client/src/app/admin/instance/dataset/components/dataset/dataset-form.component.html index 0200ca1d..94c24e99 100644 --- a/client/src/app/admin/instance/dataset/components/dataset/dataset-form.component.html +++ b/client/src/app/admin/instance/dataset/components/dataset/dataset-form.component.html @@ -102,24 +102,6 @@ <input class="custom-control-input" type="checkbox" id="cone_search_plot_enabled" name="cone_search_plot_enabled" formControlName="cone_search_plot_enabled"> <label class="custom-control-label" for="cone_search_plot_enabled">Plot enabled</label> </div> - <app-image-table - [instanceDataPath]="instance.data_path" - [datasetDataPath]="form.controls.data_path.value" - [files]="files" - [filesIsLoading]="filesIsLoading" - [filesIsLoaded]="filesIsLoaded" - [imageList]="imageList" - [imageListIsLoading]="imageListIsLoading" - [imageListIsLoaded]="imageListIsLoaded" - [fitsImageLimits]="fitsImageLimits" - [fitsImageLimitsIsLoading]="fitsImageLimitsIsLoading" - [fitsImageLimitsIsLoaded]="fitsImageLimitsIsLoaded" - (loadRootDirectory)="loadRootDirectory.emit($event)" - (retrieveFitsImageLimits)="retrieveFitsImageLimits.emit($event)" - (addNewImage)="addNewImage.emit($event)" - (editImage)="editImage.emit($event)" - (deleteImage)="deleteImage.emit($event)"> - </app-image-table> </accordion-group> <accordion-group heading="Download" [isOpen]="true"> <div class="custom-control custom-switch"> diff --git a/client/src/app/admin/instance/dataset/components/dataset/dataset-form.component.ts b/client/src/app/admin/instance/dataset/components/dataset/dataset-form.component.ts index fd5949c5..ea13faa1 100644 --- a/client/src/app/admin/instance/dataset/components/dataset/dataset-form.component.ts +++ b/client/src/app/admin/instance/dataset/components/dataset/dataset-form.component.ts @@ -30,18 +30,8 @@ export class DatasetFormComponent implements OnInit, OnChanges { @Input() filesIsLoading: boolean; @Input() filesIsLoaded: boolean; @Input() attributeList: Attribute[]; - @Input() imageList: Image[]; - @Input() imageListIsLoading: boolean; - @Input() imageListIsLoaded: boolean; - @Input() fitsImageLimits: FitsImageLimits; - @Input() fitsImageLimitsIsLoading: boolean; - @Input() fitsImageLimitsIsLoaded: boolean; @Output() changeSurvey: EventEmitter<number> = new EventEmitter(); @Output() loadRootDirectory: EventEmitter<string> = new EventEmitter(); - @Output() retrieveFitsImageLimits: EventEmitter<string> = new EventEmitter(); - @Output() addNewImage: EventEmitter<Image> = new EventEmitter(); - @Output() editImage: EventEmitter<Image> = new EventEmitter(); - @Output() deleteImage: EventEmitter<Image> = new EventEmitter(); @Output() onSubmit: EventEmitter<Dataset> = new EventEmitter(); public isNewDataset = true; diff --git a/client/src/app/admin/instance/dataset/components/image/image-form.component.ts b/client/src/app/admin/instance/dataset/components/image/image-form.component.ts index 955277af..1ad3258b 100644 --- a/client/src/app/admin/instance/dataset/components/image/image-form.component.ts +++ b/client/src/app/admin/instance/dataset/components/image/image-form.component.ts @@ -10,7 +10,7 @@ import { Component, Input, Output, OnInit, OnChanges, EventEmitter, SimpleChanges } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; -import { Image } from 'src/app/metamodel/models'; +import { Image, Dataset, Instance } from 'src/app/metamodel/models'; import { FileInfo, FitsImageLimits } from 'src/app/admin/store/models'; @Component({ @@ -19,7 +19,8 @@ import { FileInfo, FitsImageLimits } from 'src/app/admin/store/models'; }) export class ImageFormComponent implements OnInit, OnChanges { @Input() image: Image; - @Input() datasetDataPath: string; + @Input() instance: Instance; + @Input() dataset: Dataset; @Input() files: FileInfo[]; @Input() filesIsLoading: boolean; @Input() filesIsLoaded: boolean; @@ -55,7 +56,7 @@ export class ImageFormComponent implements OnInit, OnChanges { } onChangeFileSelect(path: string) { - this.loadRootDirectory.emit(`${this.datasetDataPath}${path}`); + this.loadRootDirectory.emit(`${this.instance.data_path}${this.dataset.data_path}${path}`); } onFileSelect(fileInfo: FileInfo) { diff --git a/client/src/app/admin/instance/dataset/components/image/image-table.component.html b/client/src/app/admin/instance/dataset/components/image/image-table.component.html index 3440ea61..a5256f23 100644 --- a/client/src/app/admin/instance/dataset/components/image/image-table.component.html +++ b/client/src/app/admin/instance/dataset/components/image/image-table.component.html @@ -1,6 +1,3 @@ -<button (click)="openModal(templateNewImage)" class="btn btn-outline-primary mt-3" type="button"> - <i class="far fa-image"></i> Add new image -</button> <div class="mt-2 table-responsive"> <table class="table"> <thead> @@ -26,7 +23,9 @@ <td class="align-middle">{{ image.pmin }}</td> <td class="align-middle">{{ image.pmax }}</td> <td class="align-middle"> - <a title="Edit this image" (click)="openModal(templateEditImage, image)" class="btn btn-outline-primary"> + <a title="Edit this image" + routerLink="/admin/instance/configure-instance/{{ instance.name }}/dataset/image-list/{{ dataset.name }}/edit-image/{{ image.id }}" + class="btn btn-outline-primary"> <span class="fas fa-edit"></span> </a> </td> @@ -41,56 +40,3 @@ </tbody> </table> </div> - -<ng-template #templateNewImage> - <div class="modal-header"> - <h4 class="modal-title pull-left"><strong>Add a new image</strong></h4> - </div> - <div class="modal-body"> - <app-image-form - [datasetDataPath]="datasetDataPath" - [files]="files" - [filesIsLoading]="filesIsLoading" - [filesIsLoaded]="filesIsLoaded" - [fitsImageLimits]="fitsImageLimits" - [fitsImageLimitsIsLoading]="fitsImageLimitsIsLoading" - [fitsImageLimitsIsLoaded]="fitsImageLimitsIsLoaded" - (loadRootDirectory)="onChangeDataPath($event)" - (retrieveFitsImageLimits)="retrieveFitsImageLimits.emit($event)" - (onSubmit)="addNewImage.emit($event)" - #formAddDatasetFamily> - <button [disabled]="!formAddDatasetFamily.form.valid || formAddDatasetFamily.form.pristine" (click)="modalRef.hide()" type="submit" class="btn btn-primary"> - <span class="fa fa-database"></span> Add new image - </button> - - <button (click)="modalRef.hide()" type="button" class="btn btn-danger">Cancel</button> - </app-image-form> - </div> -</ng-template> - -<ng-template #templateEditImage> - <div class="modal-header"> - <h4 class="modal-title pull-left"><strong>Edit image</strong></h4> - </div> - <div class="modal-body"> - <app-image-form - [image]="imageForEdit" - [datasetDataPath]="datasetDataPath" - [files]="files" - [filesIsLoading]="filesIsLoading" - [filesIsLoaded]="filesIsLoaded" - [fitsImageLimits]="fitsImageLimits" - [fitsImageLimitsIsLoading]="fitsImageLimitsIsLoading" - [fitsImageLimitsIsLoaded]="fitsImageLimitsIsLoaded" - (loadRootDirectory)="onChangeDataPath($event)" - (retrieveFitsImageLimits)="retrieveFitsImageLimits.emit($event)" - (onSubmit)="editImage.emit($event)" - #formAddDatasetFamily> - <button [disabled]="!formAddDatasetFamily.form.valid || formAddDatasetFamily.form.pristine" (click)="modalRef.hide()" type="submit" class="btn btn-primary"> - <span class="fa fa-database"></span> Edit image - </button> - - <button (click)="modalRef.hide()" type="button" class="btn btn-danger">Cancel</button> - </app-image-form> - </div> -</ng-template> \ No newline at end of file diff --git a/client/src/app/admin/instance/dataset/components/image/image-table.component.ts b/client/src/app/admin/instance/dataset/components/image/image-table.component.ts index fd75a9d9..669b4306 100644 --- a/client/src/app/admin/instance/dataset/components/image/image-table.component.ts +++ b/client/src/app/admin/instance/dataset/components/image/image-table.component.ts @@ -7,13 +7,9 @@ * file that was distributed with this source code. */ -import { Component, Input, Output, ChangeDetectionStrategy, EventEmitter, TemplateRef } from '@angular/core'; +import { Component, Input, Output, ChangeDetectionStrategy, EventEmitter } from '@angular/core'; -import { BsModalService } from 'ngx-bootstrap/modal'; -import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service'; - -import { Image } from 'src/app/metamodel/models'; -import { FileInfo, FitsImageLimits } from 'src/app/admin/store/models'; +import { Dataset, Image, Instance } from 'src/app/metamodel/models'; @Component({ selector: 'app-image-table', @@ -21,34 +17,8 @@ import { FileInfo, FitsImageLimits } from 'src/app/admin/store/models'; changeDetection: ChangeDetectionStrategy.OnPush }) export class ImageTableComponent { - @Input() instanceDataPath: string; - @Input() datasetDataPath: string; - @Input() files: FileInfo[]; - @Input() filesIsLoading: boolean; - @Input() filesIsLoaded: boolean; + @Input() instance: Instance; + @Input() dataset: Dataset; @Input() imageList: Image[]; - @Input() imageListIsLoading: boolean; - @Input() imageListIsLoaded: boolean; - @Input() fitsImageLimits: FitsImageLimits; - @Input() fitsImageLimitsIsLoading: boolean; - @Input() fitsImageLimitsIsLoaded: boolean; - @Output() loadRootDirectory: EventEmitter<string> = new EventEmitter(); - @Output() retrieveFitsImageLimits: EventEmitter<string> = new EventEmitter(); - @Output() addNewImage: EventEmitter<Image> = new EventEmitter(); - @Output() editImage: EventEmitter<Image> = new EventEmitter(); @Output() deleteImage: EventEmitter<Image> = new EventEmitter(); - - modalRef: BsModalRef; - imageForEdit: Image; - - constructor(private modalService: BsModalService) { } - - openModal(template: TemplateRef<any>, image: Image = null) { - this.imageForEdit = image; - this.modalRef = this.modalService.show(template); - } - - onChangeDataPath(path: string) { - this.loadRootDirectory.emit(`${this.instanceDataPath}${path}`); - } } diff --git a/client/src/app/admin/instance/dataset/containers/edit-dataset.component.html b/client/src/app/admin/instance/dataset/containers/edit-dataset.component.html index abdb60b5..a1ab6612 100644 --- a/client/src/app/admin/instance/dataset/containers/edit-dataset.component.html +++ b/client/src/app/admin/instance/dataset/containers/edit-dataset.component.html @@ -37,18 +37,8 @@ [filesIsLoading]="filesIsLoading | async" [filesIsLoaded]="filesIsLoaded | async" [attributeList]="attributeList | async" - [imageList]="imageList | async" - [imageListIsLoading]="imageListIsLoading | async" - [imageListIsLoaded]="imageListIsLoaded | async" - [fitsImageLimits]="fitsImageLimits | async" - [fitsImageLimitsIsLoading]="fitsImageLimitsIsLoading | async" - [fitsImageLimitsIsLoaded]="fitsImageLimitsIsLoaded | async" (changeSurvey)="loadTableList($event)" (loadRootDirectory)="loadRootDirectory($event)" - (retrieveFitsImageLimits)="retrieveFitsImageLimits($event)" - (addNewImage)="addNewImage($event)" - (editImage)="editImage($event)" - (deleteImage)="deleteImage($event)" (onSubmit)="editDataset($event)" #formDataset> <button [disabled]="!formDataset.form.valid || formDataset.form.pristine" type="submit" class="btn btn-primary"> diff --git a/client/src/app/admin/instance/dataset/containers/edit-dataset.component.ts b/client/src/app/admin/instance/dataset/containers/edit-dataset.component.ts index a323f77f..ef598be4 100644 --- a/client/src/app/admin/instance/dataset/containers/edit-dataset.component.ts +++ b/client/src/app/admin/instance/dataset/containers/edit-dataset.component.ts @@ -8,13 +8,12 @@ */ import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; import { Observable } from 'rxjs'; import { Store } from '@ngrx/store'; import { Instance, Survey, DatasetFamily, Dataset, Attribute, Image } from 'src/app/metamodel/models'; -import { FileInfo, FitsImageLimits } from 'src/app/admin/store/models'; +import { FileInfo } from 'src/app/admin/store/models'; import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector'; import * as datasetActions from 'src/app/metamodel/actions/dataset.actions'; import * as attributeSelector from 'src/app/metamodel/selectors/attribute.selector'; @@ -27,9 +26,6 @@ import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector import * as adminFileExplorerActions from 'src/app/admin/store/actions/admin-file-explorer.actions'; import * as adminFileExplorerSelector from 'src/app/admin/store/selectors/admin-file-explorer.selector'; import * as imageActions from 'src/app/metamodel/actions/image.actions'; -import * as imageSelector from 'src/app/metamodel/selectors/image.selector'; -import * as fitsImageActions from 'src/app/admin/store/actions/fits-image.actions'; -import * as fitsImageSelector from 'src/app/admin/store/selectors/fits-image.selector'; @Component({ selector: 'app-edit-dataset', @@ -56,14 +52,8 @@ export class EditDatasetComponent implements OnInit { public files: Observable<FileInfo[]>; public filesIsLoading: Observable<boolean>; public filesIsLoaded: Observable<boolean>; - public imageList: Observable<Image[]>; - public imageListIsLoading: Observable<boolean>; - public imageListIsLoaded: Observable<boolean>; - public fitsImageLimits: Observable<FitsImageLimits>; - public fitsImageLimitsIsLoading: Observable<boolean>; - public fitsImageLimitsIsLoaded: Observable<boolean>; - constructor(private store: Store<{ }>, private route: ActivatedRoute) { + constructor(private store: Store<{ }>) { this.instance = store.select(instanceSelector.selectInstanceByRouteName); this.datasetSelected = store.select(datasetSelector.selectDatasetNameByRoute); this.datasetList = store.select(datasetSelector.selectAllDatasets); @@ -84,12 +74,6 @@ export class EditDatasetComponent implements OnInit { this.files = store.select(adminFileExplorerSelector.selectFiles); this.filesIsLoading = store.select(adminFileExplorerSelector.selectFilesIsLoading); this.filesIsLoaded = store.select(adminFileExplorerSelector.selectFilesIsLoaded); - this.imageList = store.select(imageSelector.selectAllImages); - this.imageListIsLoading = store.select(imageSelector.selectImageListIsLoading); - this.imageListIsLoaded = store.select(imageSelector.selectImageListIsLoaded); - this.fitsImageLimits = store.select(fitsImageSelector.selectFitsImageLimits); - this.fitsImageLimitsIsLoading = store.select(fitsImageSelector.selectFitsImageLimitsIsLoading); - this.fitsImageLimitsIsLoaded = store.select(fitsImageSelector.selectFitsImageLimitsIsLoaded); } ngOnInit() { @@ -105,22 +89,6 @@ export class EditDatasetComponent implements OnInit { this.store.dispatch(adminFileExplorerActions.loadFiles({ path })); } - addNewImage(image: Image) { - this.store.dispatch(imageActions.addImage({ image })); - } - - editImage(image: Image) { - this.store.dispatch(imageActions.editImage({ image })); - } - - deleteImage(image: Image) { - this.store.dispatch(imageActions.deleteImage({ image })); - } - - retrieveFitsImageLimits(filePath: string) { - this.store.dispatch(fitsImageActions.retrieveFitsImageLimits({ filePath })); - } - editDataset(dataset: Dataset) { this.store.dispatch(datasetActions.editDataset({ dataset })); } diff --git a/client/src/app/admin/instance/dataset/containers/edit-image.component.html b/client/src/app/admin/instance/dataset/containers/edit-image.component.html new file mode 100644 index 00000000..177f0ddc --- /dev/null +++ b/client/src/app/admin/instance/dataset/containers/edit-image.component.html @@ -0,0 +1,47 @@ +<app-spinner *ngIf="(datasetListIsLoading | async) || (imageListIsLoading | async)"></app-spinner> + +<div *ngIf="(datasetListIsLoaded | async) && (imageListIsLoaded | async)" class="container-fluid"> + <nav aria-label="breadcrumb"> + <ol class="breadcrumb"> + <li class="breadcrumb-item"><a routerLink="/admin/instance/instance-list">Instances</a></li> + <li class="breadcrumb-item"> + <a routerLink="/admin/instance/configure-instance/{{ (instance | async).name }}/dataset/dataset-list"> + Configure instance {{ (instance | async).label }} + </a> + </li> + <li class="breadcrumb-item"> + <a routerLink="/admin/instance/configure-instance/{{ (instance | async).name }}/dataset/image-list/{{ (dataset | async).name }}"> + {{ (dataset | async).label }} image list + </a> + </li> + <li class="breadcrumb-item active" aria-current="page">Edit image</li> + </ol> + </nav> +</div> + +<div *ngIf="(datasetListIsLoaded | async) && (imageListIsLoaded | async)" class="container"> + <div class="row"> + <div class="col-12"> + <app-image-form + [image]="image | async" + [instance]="instance | async" + [dataset]="dataset | async" + [files]="files | async" + [filesIsLoading]="filesIsLoading | async" + [filesIsLoaded]="filesIsLoaded | async" + [fitsImageLimits]="fitsImageLimits | async" + [fitsImageLimitsIsLoading]="fitsImageLimitsIsLoading | async" + [fitsImageLimitsIsLoaded]="fitsImageLimitsIsLoaded | async" + (loadRootDirectory)="loadRootDirectory($event)" + (retrieveFitsImageLimits)="retrieveFitsImageLimits($event)" + (onSubmit)="editImage($event)" + #formEditImage> + <button [disabled]="!formEditImage.form.valid || formEditImage.form.pristine" type="submit" class="btn btn-primary"> + <span class="fa fa-database"></span> Edit image + </button> + + <button routerLink="/admin/instance/configure-instance/{{ (instance | async).name }}/dataset/image-list/{{ (dataset | async).name }}" type="button" class="btn btn-danger">Cancel</button> + </app-image-form> + </div> + </div> +</div> diff --git a/client/src/app/admin/instance/dataset/containers/edit-image.component.ts b/client/src/app/admin/instance/dataset/containers/edit-image.component.ts new file mode 100644 index 00000000..b9b2f033 --- /dev/null +++ b/client/src/app/admin/instance/dataset/containers/edit-image.component.ts @@ -0,0 +1,76 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { Component } from '@angular/core'; + +import { Observable } from 'rxjs'; +import { Store } from '@ngrx/store'; + +import { Instance, Dataset, Image } from 'src/app/metamodel/models'; +import { FileInfo, FitsImageLimits } from 'src/app/admin/store/models'; +import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector'; +import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector'; +import * as adminFileExplorerActions from 'src/app/admin/store/actions/admin-file-explorer.actions'; +import * as adminFileExplorerSelector from 'src/app/admin/store/selectors/admin-file-explorer.selector'; +import * as imageActions from 'src/app/metamodel/actions/image.actions'; +import * as imageSelector from 'src/app/metamodel/selectors/image.selector'; +import * as fitsImageActions from 'src/app/admin/store/actions/fits-image.actions'; +import * as fitsImageSelector from 'src/app/admin/store/selectors/fits-image.selector'; + +@Component({ + selector: 'app-edit-image', + templateUrl: 'edit-image.component.html' +}) +export class EditImageComponent { + public instance: Observable<Instance>; + public dataset: Observable<Dataset>; + public datasetListIsLoading: Observable<boolean>; + public datasetListIsLoaded: Observable<boolean>; + public files: Observable<FileInfo[]>; + public filesIsLoading: Observable<boolean>; + public filesIsLoaded: Observable<boolean>; + public fitsImageLimits: Observable<FitsImageLimits>; + public fitsImageLimitsIsLoading: Observable<boolean>; + public fitsImageLimitsIsLoaded: Observable<boolean>; + public image: Observable<Image>; + public imageListIsLoading: Observable<boolean>; + public imageListIsLoaded: Observable<boolean>; + + constructor(private store: Store<{ }>) { + this.instance = store.select(instanceSelector.selectInstanceByRouteName); + this.dataset = store.select(datasetSelector.selectDatasetByRouteName); + this.datasetListIsLoading = store.select(datasetSelector.selectDatasetListIsLoading); + this.datasetListIsLoaded = store.select(datasetSelector.selectDatasetListIsLoaded); + this.files = store.select(adminFileExplorerSelector.selectFiles); + this.filesIsLoading = store.select(adminFileExplorerSelector.selectFilesIsLoading); + this.filesIsLoaded = store.select(adminFileExplorerSelector.selectFilesIsLoaded); + this.fitsImageLimits = store.select(fitsImageSelector.selectFitsImageLimits); + this.fitsImageLimitsIsLoading = store.select(fitsImageSelector.selectFitsImageLimitsIsLoading); + this.fitsImageLimitsIsLoaded = store.select(fitsImageSelector.selectFitsImageLimitsIsLoaded); + this.image = store.select(imageSelector.selectImageByRouteId); + this.imageListIsLoading = store.select(imageSelector.selectImageListIsLoading); + this.imageListIsLoaded = store.select(imageSelector.selectImageListIsLoaded); + } + + ngOnInit() { + this.store.dispatch(imageActions.loadImageList()); + } + + loadRootDirectory(path: string) { + this.store.dispatch(adminFileExplorerActions.loadFiles({ path })); + } + + retrieveFitsImageLimits(filePath: string) { + this.store.dispatch(fitsImageActions.retrieveFitsImageLimits({ filePath })); + } + + editImage(image: Image) { + this.store.dispatch(imageActions.editImage({ image })); + } +} \ No newline at end of file diff --git a/client/src/app/admin/instance/dataset/containers/image-list.component.html b/client/src/app/admin/instance/dataset/containers/image-list.component.html new file mode 100644 index 00000000..8826de3f --- /dev/null +++ b/client/src/app/admin/instance/dataset/containers/image-list.component.html @@ -0,0 +1,38 @@ +<div class="container-fluid"> + <nav aria-label="breadcrumb"> + <ol class="breadcrumb"> + <li class="breadcrumb-item"><a routerLink="/admin/instance/instance-list">Instances</a></li> + <li class="breadcrumb-item"> + <a routerLink="/admin/instance/configure-instance/{{ (instance | async).name }}/dataset/dataset-list"> + Configure instance {{ (instance | async).label }} + </a> + </li> + <li class="breadcrumb-item active" aria-current="page">{{ (dataset | async).label }} image list</li> + </ol> + </nav> + + <app-spinner *ngIf="imageListIsLoading | async"></app-spinner> + + <ng-container *ngIf="imageListIsLoaded | async"> + <div class="row"> + <div class="col-12"> + <button title="Add a new image" + class="btn btn-outline-success float-right" + routerLink="/admin/instance/configure-instance/{{ (instance | async).name }}/dataset/image-list/{{ (dataset | async).name }}/new-image"> + <span class="fas fa-plus"></span> New image + </button> + </div> + </div> + + <div class="row mt-1"> + <div class="col-12"> + <app-image-table + [instance]="instance | async" + [dataset]="dataset | async" + [imageList]="imageList | async" + (deleteImage)="deleteImage($event)"> + </app-image-table> + </div> + </div> + </ng-container> +</div> diff --git a/client/src/app/admin/instance/dataset/containers/image-list.component.ts b/client/src/app/admin/instance/dataset/containers/image-list.component.ts new file mode 100644 index 00000000..e3b12da9 --- /dev/null +++ b/client/src/app/admin/instance/dataset/containers/image-list.component.ts @@ -0,0 +1,51 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { Component, OnInit } from '@angular/core'; + +import { Observable } from 'rxjs'; +import { Store } from '@ngrx/store'; + +import { Image, Instance, Dataset } from 'src/app/metamodel/models'; +import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector'; +import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector'; +import * as imageActions from 'src/app/metamodel/actions/image.actions'; +import * as imageSelector from 'src/app/metamodel/selectors/image.selector'; + +@Component({ + selector: 'app-image-list', + templateUrl: 'image-list.component.html' +}) +export class ImageListComponent implements OnInit { + public instance: Observable<Instance>; + public dataset: Observable<Dataset>; + public datasetListIsLoading: Observable<boolean>; + public datasetListIsLoaded: Observable<boolean>; + public imageList: Observable<Image[]>; + public imageListIsLoading: Observable<boolean>; + public imageListIsLoaded: Observable<boolean>; + + constructor(private store: Store<{ }>) { + this.instance = store.select(instanceSelector.selectInstanceByRouteName); + this.dataset = store.select(datasetSelector.selectDatasetByRouteName); + this.datasetListIsLoading = store.select(datasetSelector.selectDatasetListIsLoading); + this.datasetListIsLoaded = store.select(datasetSelector.selectDatasetListIsLoaded); + this.imageList = store.select(imageSelector.selectAllImages); + this.imageListIsLoading = store.select(imageSelector.selectImageListIsLoading); + this.imageListIsLoaded = store.select(imageSelector.selectImageListIsLoaded); + } + + ngOnInit() { + this.store.dispatch(imageActions.loadImageList()); + } + + deleteImage(image: Image) { + this.store.dispatch(imageActions.deleteImage({ image })); + } +} \ No newline at end of file diff --git a/client/src/app/admin/instance/dataset/containers/new-image.component.html b/client/src/app/admin/instance/dataset/containers/new-image.component.html new file mode 100644 index 00000000..8560f4ab --- /dev/null +++ b/client/src/app/admin/instance/dataset/containers/new-image.component.html @@ -0,0 +1,46 @@ +<app-spinner *ngIf="datasetListIsLoading | async"></app-spinner> + +<div *ngIf="datasetListIsLoaded | async" class="container-fluid"> + <nav aria-label="breadcrumb"> + <ol class="breadcrumb"> + <li class="breadcrumb-item"><a routerLink="/admin/instance/instance-list">Instances</a></li> + <li class="breadcrumb-item"> + <a routerLink="/admin/instance/configure-instance/{{ (instance | async).name }}/dataset/dataset-list"> + Configure instance {{ (instance | async).label }} + </a> + </li> + <li class="breadcrumb-item"> + <a routerLink="/admin/instance/configure-instance/{{ (instance | async).name }}/dataset/image-list/{{ (dataset | async).name }}"> + {{ (dataset | async).label }} image list + </a> + </li> + <li class="breadcrumb-item active" aria-current="page">Add a new image</li> + </ol> + </nav> +</div> + +<div *ngIf="datasetListIsLoaded | async" class="container"> + <div class="row"> + <div class="col-12"> + <app-image-form + [instance]="instance | async" + [dataset]="dataset | async" + [files]="files | async" + [filesIsLoading]="filesIsLoading | async" + [filesIsLoaded]="filesIsLoaded | async" + [fitsImageLimits]="fitsImageLimits | async" + [fitsImageLimitsIsLoading]="fitsImageLimitsIsLoading | async" + [fitsImageLimitsIsLoaded]="fitsImageLimitsIsLoaded | async" + (loadRootDirectory)="loadRootDirectory($event)" + (retrieveFitsImageLimits)="retrieveFitsImageLimits($event)" + (onSubmit)="addNewImage($event)" + #formAddImage> + <button [disabled]="!formAddImage.form.valid || formAddImage.form.pristine" type="submit" class="btn btn-primary"> + <span class="fa fa-database"></span> Add new image + </button> + + <button routerLink="/admin/instance/configure-instance/{{ (instance | async).name }}/dataset/image-list/{{ (dataset | async).name }}" type="button" class="btn btn-danger">Cancel</button> + </app-image-form> + </div> + </div> +</div> diff --git a/client/src/app/admin/instance/dataset/containers/new-image.component.ts b/client/src/app/admin/instance/dataset/containers/new-image.component.ts new file mode 100644 index 00000000..5dd243e6 --- /dev/null +++ b/client/src/app/admin/instance/dataset/containers/new-image.component.ts @@ -0,0 +1,65 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { Component } from '@angular/core'; + +import { Observable } from 'rxjs'; +import { Store } from '@ngrx/store'; + +import { Instance, Dataset, Image } from 'src/app/metamodel/models'; +import { FileInfo, FitsImageLimits } from 'src/app/admin/store/models'; +import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector'; +import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector'; +import * as adminFileExplorerActions from 'src/app/admin/store/actions/admin-file-explorer.actions'; +import * as adminFileExplorerSelector from 'src/app/admin/store/selectors/admin-file-explorer.selector'; +import * as imageActions from 'src/app/metamodel/actions/image.actions'; +import * as fitsImageActions from 'src/app/admin/store/actions/fits-image.actions'; +import * as fitsImageSelector from 'src/app/admin/store/selectors/fits-image.selector'; + +@Component({ + selector: 'app-new-image', + templateUrl: 'new-image.component.html' +}) +export class NewImageComponent { + public instance: Observable<Instance>; + public dataset: Observable<Dataset>; + public datasetListIsLoading: Observable<boolean>; + public datasetListIsLoaded: Observable<boolean>; + public files: Observable<FileInfo[]>; + public filesIsLoading: Observable<boolean>; + public filesIsLoaded: Observable<boolean>; + public fitsImageLimits: Observable<FitsImageLimits>; + public fitsImageLimitsIsLoading: Observable<boolean>; + public fitsImageLimitsIsLoaded: Observable<boolean>; + + constructor(private store: Store<{ }>) { + this.instance = store.select(instanceSelector.selectInstanceByRouteName); + this.dataset = store.select(datasetSelector.selectDatasetByRouteName); + this.datasetListIsLoading = store.select(datasetSelector.selectDatasetListIsLoading); + this.datasetListIsLoaded = store.select(datasetSelector.selectDatasetListIsLoaded); + this.files = store.select(adminFileExplorerSelector.selectFiles); + this.filesIsLoading = store.select(adminFileExplorerSelector.selectFilesIsLoading); + this.filesIsLoaded = store.select(adminFileExplorerSelector.selectFilesIsLoaded); + this.fitsImageLimits = store.select(fitsImageSelector.selectFitsImageLimits); + this.fitsImageLimitsIsLoading = store.select(fitsImageSelector.selectFitsImageLimitsIsLoading); + this.fitsImageLimitsIsLoaded = store.select(fitsImageSelector.selectFitsImageLimitsIsLoaded); + } + + loadRootDirectory(path: string) { + this.store.dispatch(adminFileExplorerActions.loadFiles({ path })); + } + + retrieveFitsImageLimits(filePath: string) { + this.store.dispatch(fitsImageActions.retrieveFitsImageLimits({ filePath })); + } + + addNewImage(image: Image) { + this.store.dispatch(imageActions.addImage({ image })); + } +} \ No newline at end of file diff --git a/client/src/app/admin/instance/dataset/dataset-routing.module.ts b/client/src/app/admin/instance/dataset/dataset-routing.module.ts index 5779ddc7..31d8edf4 100644 --- a/client/src/app/admin/instance/dataset/dataset-routing.module.ts +++ b/client/src/app/admin/instance/dataset/dataset-routing.module.ts @@ -14,12 +14,18 @@ import { DatasetListComponent } from './containers/dataset-list.component'; import { NewDatasetComponent } from './containers/new-dataset.component'; import { EditDatasetComponent } from './containers/edit-dataset.component'; import { AttributeListComponent } from './containers/attribute-list.component'; +import { ImageListComponent } from './containers/image-list.component'; +import { NewImageComponent } from './containers/new-image.component'; +import { EditImageComponent } from './containers/edit-image.component'; const routes: Routes = [ { path: 'dataset-list', component: DatasetListComponent }, { path: 'new-dataset', component: NewDatasetComponent }, { path: 'edit-dataset/:dname', component: EditDatasetComponent }, { path: 'configure-dataset/:dname', component: AttributeListComponent }, + { path: 'image-list/:dname', component: ImageListComponent }, + { path: 'image-list/:dname/new-image', component: NewImageComponent }, + { path: 'image-list/:dname/edit-image/:id', component: EditImageComponent } ]; /** @@ -36,5 +42,8 @@ export const routedComponents = [ DatasetListComponent, NewDatasetComponent, EditDatasetComponent, - AttributeListComponent + AttributeListComponent, + ImageListComponent, + NewImageComponent, + EditImageComponent ]; diff --git a/client/src/app/metamodel/effects/image.effects.ts b/client/src/app/metamodel/effects/image.effects.ts index 59dce9ad..dcfc1d5c 100644 --- a/client/src/app/metamodel/effects/image.effects.ts +++ b/client/src/app/metamodel/effects/image.effects.ts @@ -8,6 +8,7 @@ */ import { Injectable } from '@angular/core'; +import { Router } from '@angular/router'; import { Actions, createEffect, ofType, concatLatestFrom } from '@ngrx/effects'; import { Store } from '@ngrx/store'; @@ -18,6 +19,7 @@ import { ToastrService } from 'ngx-toastr'; import * as imageActions from '../actions/image.actions'; import { ImageService } from '../services/image.service'; import * as datasetSelector from '../selectors/dataset.selector'; +import * as instanceSelector from '../selectors/instance.selector'; /** * @class @@ -64,7 +66,14 @@ export class ImageEffects { addImageSuccess$ = createEffect(() => this.actions$.pipe( ofType(imageActions.addImageSuccess), - tap(() => this.toastr.success('Image successfully added', 'The new image was added into the database')) + concatLatestFrom(() => [ + this.store.select(instanceSelector.selectInstanceNameByRoute), + this.store.select(datasetSelector.selectDatasetNameByRoute) + ]), + tap(([, instanceName, datasetName]) => { + this.router.navigateByUrl(`/admin/instance/configure-instance/${instanceName}/dataset/image-list/${datasetName}`); + this.toastr.success('Image successfully added', 'The new image was added into the database'); + }) ), { dispatch: false } ); @@ -99,7 +108,14 @@ export class ImageEffects { editImageSuccess$ = createEffect(() => this.actions$.pipe( ofType(imageActions.editImageSuccess), - tap(() => this.toastr.success('Image successfully edited', 'The existing image has been edited into the database')) + concatLatestFrom(() => [ + this.store.select(instanceSelector.selectInstanceNameByRoute), + this.store.select(datasetSelector.selectDatasetNameByRoute) + ]), + tap(([, instanceName, datasetName]) => { + this.router.navigateByUrl(`/admin/instance/configure-instance/${instanceName}/dataset/image-list/${datasetName}`); + this.toastr.success('Image successfully edited', 'The existing image has been edited into the database'); + }) ), { dispatch: false } ); @@ -151,6 +167,7 @@ export class ImageEffects { constructor( private actions$: Actions, private imageService: ImageService, + private router: Router, private toastr: ToastrService, private store: Store<{ }> ) {} diff --git a/client/src/app/metamodel/selectors/image.selector.ts b/client/src/app/metamodel/selectors/image.selector.ts index 5902eb3f..ce5e4842 100644 --- a/client/src/app/metamodel/selectors/image.selector.ts +++ b/client/src/app/metamodel/selectors/image.selector.ts @@ -46,3 +46,9 @@ export const selectImageListIsLoaded = createSelector( selectImageState, fromImage.selectImageListIsLoaded ); + +export const selectImageByRouteId = createSelector( + selectImageEntities, + reducer.selectRouterState, + (entities, router) => entities[router.state.params.id] +); \ No newline at end of file -- GitLab