diff --git a/client/package.json b/client/package.json index 502facc13f89b61e78ce9545518d4e64232c56f7..7e7cad96734364427fdcc7fe3022f1e64f022190 100644 --- a/client/package.json +++ b/client/package.json @@ -29,6 +29,7 @@ "keycloak-angular": "^8.2.0", "keycloak-js": "^14.0.0", "ngx-bootstrap": "^7.0.0-rc.1", + "ngx-json-viewer": "^3.0.2", "ngx-toastr": "^14.0.0", "rxjs": "~6.6.0", "tslib": "^2.1.0", diff --git a/client/src/app/instance/search/components/result/datatable-tab.component.html b/client/src/app/instance/search/components/result/datatable-tab.component.html new file mode 100644 index 0000000000000000000000000000000000000000..670acae1dd47d1c6dc836cbd4f78e0cec4592d37 --- /dev/null +++ b/client/src/app/instance/search/components/result/datatable-tab.component.html @@ -0,0 +1,25 @@ +<accordion *ngIf="getDataset().config.datatable.datatable_enabled" [isAnimated]="true"> + <accordion-group #ag [isOpen]="getDataset().config.datatable.datatable_opened" [panelClass]="'custom-accordion'" class="my-2"> + <button class="btn btn-link btn-block clearfix" accordion-heading> + <span class="pull-left float-left"> + Display result details + + <span *ngIf="ag.isOpen"><span class="fas fa-chevron-up"></span></span> + <span *ngIf="!ag.isOpen"><span class="fas fa-chevron-down"></span></span> + </span> + </button> + <app-datatable + [dataset]="getDataset()" + [attributeList]="attributeList" + [outputList]="outputList" + [dataLength]="dataLength" + [data]="data" + [dataIsLoading]="dataIsLoading" + [dataIsLoaded]="dataIsLoaded" + [selectedData]="selectedData" + (retrieveData)="retrieveData.emit($event)" + (addSelectedData)="addSelectedData.emit($event)" + (deleteSelectedData)="deleteSelectedData.emit($event)"> + </app-datatable> + </accordion-group> +</accordion> diff --git a/client/src/app/instance/search/components/result/datatable-tab.component.ts b/client/src/app/instance/search/components/result/datatable-tab.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..0b7b2258095c4ff700fc940781e0ed6a4dd5d6af --- /dev/null +++ b/client/src/app/instance/search/components/result/datatable-tab.component.ts @@ -0,0 +1,46 @@ +/** + * 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 { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; + +import { Attribute, Dataset } from 'src/app/metamodel/models'; +import { Pagination } from 'src/app/instance/store/models'; + +@Component({ + selector: 'app-datatable-tab', + templateUrl: 'datatable-tab.component.html', + changeDetection: ChangeDetectionStrategy.OnPush +}) +/** + * @class + * @classdesc Search result datatable tab component. + */ +export class DatatableTabComponent { + @Input() datasetSelected: string; + @Input() datasetList: Dataset[]; + @Input() attributeList: Attribute[]; + @Input() outputList: number[]; + @Input() dataLength: number; + @Input() data: any[]; + @Input() dataIsLoading: boolean; + @Input() dataIsLoaded: boolean; + @Input() selectedData: any[]; + @Output() retrieveData: EventEmitter<Pagination> = new EventEmitter(); + @Output() addSelectedData: EventEmitter<number | string> = new EventEmitter(); + @Output() deleteSelectedData: EventEmitter<number | string> = new EventEmitter(); + + /** + * Returns selected dataset for the search. + * + * @return Dataset + */ + getDataset(): Dataset { + return this.datasetList.find(dataset => dataset.name === this.datasetSelected); + } +} diff --git a/client/src/app/instance/search/components/result/index.ts b/client/src/app/instance/search/components/result/index.ts index 68174bc2cf9b0578ae6fab36b416ceefcad29e0b..f710426a95579957903094bd0ac64f1402585f5c 100644 --- a/client/src/app/instance/search/components/result/index.ts +++ b/client/src/app/instance/search/components/result/index.ts @@ -1,9 +1,11 @@ +import { DatatableTabComponent } from './datatable-tab.component'; import { DownloadComponent } from './download.component'; import { ReminderComponent } from './reminder.component'; import { SampComponent } from './samp.component'; import { UrlDisplayComponent } from './url-display.component'; export const resultComponents = [ + DatatableTabComponent, DownloadComponent, ReminderComponent, SampComponent, diff --git a/client/src/app/instance/search/containers/abstract-search.component.ts b/client/src/app/instance/search/containers/abstract-search.component.ts index a1a3340b41cd69182b9672b39c1e12e7a712f5ae..a6ebdbbebc3bb3175648b19ddadfb4adc037c880 100644 --- a/client/src/app/instance/search/containers/abstract-search.component.ts +++ b/client/src/app/instance/search/containers/abstract-search.component.ts @@ -73,7 +73,7 @@ export abstract class AbstractSearchComponent implements OnInit, OnDestroy { Promise.resolve(null).then(() => this.store.dispatch(searchActions.initSearch())); this.attributeListIsLoadedSubscription = this.attributeListIsLoaded.subscribe(attributeListIsLoaded => { if (attributeListIsLoaded) { - this.store.dispatch(searchActions.loadDefaultFormParameters()); + Promise.resolve(null).then(() => this.store.dispatch(searchActions.loadDefaultFormParameters())); } }); } diff --git a/client/src/app/instance/search/containers/result.component.html b/client/src/app/instance/search/containers/result.component.html index 3bb295f6980d632cdddbc9668e8406c485c3628b..9eacc2ffbff8b44a625d444390f47af89e481e08 100644 --- a/client/src/app/instance/search/containers/result.component.html +++ b/client/src/app/instance/search/containers/result.component.html @@ -60,19 +60,21 @@ [dataLength]="dataLength | async" [isConeSearchAdded]="isConeSearchAdded | async" [coneSearch]="coneSearch | async"> - </app-cone-search-plot-tab> + </app-cone-search-plot-tab> --> <app-datatable-tab - [datasetName]="datasetName | async" + [datasetSelected]="datasetSelected | async" [datasetList]="datasetList | async" [attributeList]="attributeList | async" [outputList]="outputList | async" - [searchData]="searchData | async" [dataLength]="dataLength | async" + [data]="data | async" + [dataIsLoading]="dataIsLoading | async" + [dataIsLoaded]="dataIsLoaded | async" [selectedData]="selectedData | async" - (getSearchData)="getSearchData($event)" + (retrieveData)="retrieveData($event)" (addSelectedData)="addSearchData($event)" (deleteSelectedData)="deleteSearchData($event)"> - </app-datatable-tab> --> + </app-datatable-tab> </ng-container> </div> </div> diff --git a/client/src/app/instance/search/containers/result.component.ts b/client/src/app/instance/search/containers/result.component.ts index 85bd6dc469e0bdfc309e439b331c83dcc7397028..1e1c3359b8c7a5fafe764ade7c1c49eef4107a20 100644 --- a/client/src/app/instance/search/containers/result.component.ts +++ b/client/src/app/instance/search/containers/result.component.ts @@ -34,6 +34,10 @@ export class ResultComponent extends AbstractSearchComponent { public dataLength: Observable<number>; public dataLengthIsLoading: Observable<boolean>; public dataLengthIsLoaded: Observable<boolean>; + public data: Observable<any>; + public dataIsLoading: Observable<boolean>; + public dataIsLoaded: Observable<boolean>; + public selectedData: Observable<any>; public sampRegistered: Observable<boolean>; private pristineSubscription: Subscription; @@ -43,6 +47,10 @@ export class ResultComponent extends AbstractSearchComponent { this.dataLength = this.store.select(searchSelector.selectDataLength); this.dataLengthIsLoading = this.store.select(searchSelector.selectDataLengthIsLoading); this.dataLengthIsLoaded = this.store.select(searchSelector.selectDataLengthIsLoaded); + this.data = this.store.select(searchSelector.selectData); + this.dataIsLoading = this.store.select(searchSelector.selectDataIsLoading); + this.dataIsLoaded = this.store.select(searchSelector.selectDataIsLoaded); + this.selectedData = this.store.select(searchSelector.selectSelectedData); this.sampRegistered = this.store.select(sampSelector.selectRegistered); } @@ -71,19 +79,12 @@ export class ResultComponent extends AbstractSearchComponent { this.store.dispatch(sampActions.broadcastVotable({ url })); } - /** - * Dispatches action to retrieve result number. - */ - getDataLength(): void { - // this.store.dispatch(searchActions.retrieveDataLength()); - } - /** * Dispatches action to retrieve data with the given pagination. * * @param {Pagination} pagination - The pagination parameters. */ - getSearchData(pagination: Pagination): void { + retrieveData(pagination: Pagination): void { this.store.dispatch(searchActions.retrieveData({ pagination })); } diff --git a/client/src/app/instance/search/search.module.ts b/client/src/app/instance/search/search.module.ts index 8ae63a5dd82a8356a1d805a4617ed67664b2837a..63eef0ff7d627926da0f1dd73535176b9bd1a303 100644 --- a/client/src/app/instance/search/search.module.ts +++ b/client/src/app/instance/search/search.module.ts @@ -10,14 +10,14 @@ import { NgModule } from '@angular/core'; import { SharedModule } from 'src/app/shared/shared.module'; -// import { SharedSearchModule } from '../shared-search/shared-search.module'; +import { SharedSearchModule } from '../shared-search/shared-search.module'; import { SearchRoutingModule, routedComponents } from './search-routing.module'; import { dummiesComponents } from './components'; @NgModule({ imports: [ SharedModule, - // SharedSearchModule, + SharedSearchModule, SearchRoutingModule ], declarations: [ diff --git a/client/src/app/instance/shared-search/components/datatable/datatable.component.html b/client/src/app/instance/shared-search/components/datatable/datatable.component.html index fb1fdb310fa27a9c63da7df497862dc178ec2d16..8a373adc94235177078fdbe92c629b1bb642024b 100644 --- a/client/src/app/instance/shared-search/components/datatable/datatable.component.html +++ b/client/src/app/instance/shared-search/components/datatable/datatable.component.html @@ -1,8 +1,10 @@ -<div class="table-responsive"> +<app-spinner *ngIf="(dataIsLoading)"></app-spinner> + +<div *ngIf="(dataIsLoaded)" class="table-responsive"> <table class="table table-bordered table-hover"> <thead> <tr> - <th *ngIf="dataset.config.datatable.selectable_row">#</th> + <th *ngIf="dataset.config.datatable.datatable_selectable_rows">#</th> <th *ngFor="let attribute of getOutputList()" scope="col" class="clickable" (click)="sort(attribute.id)"> {{ attribute.label }} <span *ngIf="attribute.id === sortedCol" class="pl-2"> @@ -26,7 +28,7 @@ </thead> <tbody> <tr *ngFor="let datum of data"> - <td *ngIf="dataset.config.datatable.selectable_row" class="data-selected" + <td *ngIf="dataset.config.datatable.datatable_selectable_rows" class="data-selected" (click)="toggleSelection(datum)"> <button class="btn btn-block text-left p-0 m-0"> <span *ngIf="!isSelected(datum)"> @@ -43,35 +45,35 @@ <app-detail-renderer [value]="datum[attribute.label]" [datasetName]="dataset.name" - [config]="attribute.renderer_config"> + [config]="getRendererConfig(attribute)"> </app-detail-renderer> </div> <div *ngSwitchCase="'link'"> <app-link-renderer [value]="datum[attribute.label]" [datasetName]="dataset.name" - [config]="attribute.renderer_config"> + [config]="getRendererConfig(attribute)"> </app-link-renderer> </div> <div *ngSwitchCase="'download'"> <app-download-renderer [value]="datum[attribute.label]" [datasetName]="dataset.name" - [config]="attribute.renderer_config"> + [config]="getRendererConfig(attribute)"> </app-download-renderer> </div> <div *ngSwitchCase="'image'"> <app-image-renderer [value]="datum[attribute.label]" [datasetName]="dataset.name" - [config]="attribute.renderer_config"> + [config]="getRendererConfig(attribute)"> </app-image-renderer> </div> <div *ngSwitchCase="'json'"> <app-json-renderer [value]="datum[attribute.label]" [attributeLabel]="attribute.label" - [config]="attribute.renderer_config"> + [config]="getRendererConfig(attribute)"> </app-json-renderer> </div> <div *ngSwitchDefault> diff --git a/client/src/app/instance/shared-search/components/datatable/datatable.component.ts b/client/src/app/instance/shared-search/components/datatable/datatable.component.ts index 8cfef40a18a8060684c6610869f87129075c2a59..56d115ee220a55a674fc8b3a6343871b3c6c8178 100644 --- a/client/src/app/instance/shared-search/components/datatable/datatable.component.ts +++ b/client/src/app/instance/shared-search/components/datatable/datatable.component.ts @@ -9,7 +9,7 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { Attribute, Dataset } from 'src/app/metamodel/models'; +import { Attribute, Dataset, DetailRendererConfig, DownloadRendererConfig, ImageRendererConfig, LinkRendererConfig, RendererConfig } from 'src/app/metamodel/models'; import { Pagination, PaginationOrder } from 'src/app/instance/store/models'; @@ -25,36 +25,56 @@ import { Pagination, PaginationOrder } from 'src/app/instance/store/models'; * @implements OnInit */ export class DatatableComponent implements OnInit { - @Input() datasetSelected: string; - @Input() datasetList: Dataset[]; + @Input() dataset: Dataset; @Input() attributeList: Attribute[]; @Input() outputList: number[]; - @Input() data: any[]; @Input() dataLength: number; + @Input() data: any[]; + @Input() dataIsLoading: boolean; + @Input() dataIsLoaded: boolean; @Input() selectedData: any[] = []; - @Output() getData: EventEmitter<Pagination> = new EventEmitter(); + @Output() retrieveData: EventEmitter<Pagination> = new EventEmitter(); @Output() addSelectedData: EventEmitter<number | string> = new EventEmitter(); @Output() deleteSelectedData: EventEmitter<number | string> = new EventEmitter(); - nbItems = 10; - page = 1; - sortedCol: number = null; - sortedOrder: PaginationOrder = PaginationOrder.a; + + public page = 1; + public nbItems = 10; + public sortedCol: number = null; + public sortedOrder: PaginationOrder = PaginationOrder.a; ngOnInit() { this.sortedCol = this.attributeList.find(a => a.order_by).id; + Promise.resolve(null).then(() => this.retrieveData.emit({ + dname: this.dataset.name, + page: this.page, + nbItems: this.nbItems, + sortedCol: this.sortedCol, + order: this.sortedOrder + })); } - getDataset() { - return this.datasetList.find(dataset => dataset.name === this.datasetSelected); - } - - /** - * Checks if there is no data selected. - * - * @return boolean - */ - noSelectedData(): boolean { - return this.selectedData.length < 1; + getRendererConfig(attribute: Attribute) { + let config = null; + switch(attribute.renderer) { + case 'detail': + config = attribute.renderer_config as DetailRendererConfig; + break; + case 'link': + config = attribute.renderer_config as LinkRendererConfig; + break; + case 'download': + config = attribute.renderer_config as DownloadRendererConfig; + break; + case 'image': + config = attribute.renderer_config as ImageRendererConfig; + break; + case 'json': + config = attribute.renderer_config as RendererConfig; + break; + default: + config = null; + } + return config; } /** @@ -111,13 +131,13 @@ export class DatatableComponent implements OnInit { changePage(nb: number): void { this.page = nb; const pagination: Pagination = { - dname: this.getDataset().name, + dname: this.dataset.name, page: this.page, nbItems: this.nbItems, sortedCol: this.sortedCol, order: this.sortedOrder }; - this.getData.emit(pagination); + this.retrieveData.emit(pagination); } /** diff --git a/client/src/app/instance/shared-search/components/datatable/renderer/image-renderer.component.ts b/client/src/app/instance/shared-search/components/datatable/renderer/image-renderer.component.ts index dac787886b77845e7eb19988f20eb93da1c1aead..75521e7d2816346299a40bebc41cee587f5a0e40 100644 --- a/client/src/app/instance/shared-search/components/datatable/renderer/image-renderer.component.ts +++ b/client/src/app/instance/shared-search/components/datatable/renderer/image-renderer.component.ts @@ -12,7 +12,7 @@ import { Component, Input, ChangeDetectionStrategy, TemplateRef } from '@angular import { BsModalService } from 'ngx-bootstrap/modal'; import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service'; -import { ImageRendererConfig } from 'src/app/metamodel/models/renderers/image-renderer-config.model'; +import { ImageRendererConfig } from 'src/app/metamodel/models/renderers'; import { environment } from 'src/environments/environment'; @Component({ diff --git a/client/src/app/instance/shared-search/components/index.ts b/client/src/app/instance/shared-search/components/index.ts index 1bd2ebbdd5b479facf234dd6ba38ab4ef88f589e..f3ee95d0784280eae6250d149041229fd9e5127f 100644 --- a/client/src/app/instance/shared-search/components/index.ts +++ b/client/src/app/instance/shared-search/components/index.ts @@ -1,7 +1,7 @@ -import { coneSearchComponents } from './cone-search'; +// import { coneSearchComponents } from './cone-search'; import { datatableComponents } from './datatable'; export const sharedComponents = [ - coneSearchComponents, + // coneSearchComponents, datatableComponents ]; diff --git a/client/src/app/instance/shared-search/shared-search.module.ts b/client/src/app/instance/shared-search/shared-search.module.ts index e43fcc5efcbd7fe6f678950d8ca9d370f2cbd89c..8d66fd662e112bf97b1832d2c6bfd218ffd5451e 100644 --- a/client/src/app/instance/shared-search/shared-search.module.ts +++ b/client/src/app/instance/shared-search/shared-search.module.ts @@ -8,6 +8,7 @@ */ import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; import { SharedModule } from 'src/app/shared/shared.module'; import { sharedComponents } from './components'; @@ -15,7 +16,8 @@ import { sharedPipes } from './pipes'; @NgModule({ imports: [ - SharedModule + SharedModule, + RouterModule ], declarations: [ sharedComponents, diff --git a/client/src/app/instance/store/reducers/search.reducer.ts b/client/src/app/instance/store/reducers/search.reducer.ts index 662214361d9848f049ea6237adbe1cbc12dd54e1..ee7d006a215d73bd0c44ac1a75b98bc4233f2f06 100644 --- a/client/src/app/instance/store/reducers/search.reducer.ts +++ b/client/src/app/instance/store/reducers/search.reducer.ts @@ -22,10 +22,12 @@ export interface State { coneSearchAdded: boolean; criteriaList: Criterion[]; outputList: number[]; - searchData: any[]; dataLengthIsLoading: boolean; dataLengthIsLoaded: boolean; dataLength: number; + data: any[], + dataIsLoading: boolean, + dataIsLoaded: boolean, selectedData: any[]; } @@ -39,10 +41,12 @@ export const initialState: State = { coneSearchAdded: false, criteriaList: [], outputList: [], - searchData: [], dataLengthIsLoading: false, dataLengthIsLoaded: false, dataLength: null, + data: [], + dataIsLoading: false, + dataIsLoaded: false, selectedData: [] }; @@ -115,6 +119,21 @@ export const searchReducer = createReducer( ...state, dataLengthIsLoading: false })), + on(searchActions.retrieveData, state => ({ + ...state, + dataIsLoading: true, + dataIsLoaded: false + })), + on(searchActions.retrieveDataSuccess, (state, { data }) => ({ + ...state, + data, + dataIsLoading: false, + dataIsLoaded: true + })), + on(searchActions.retrieveDataFail, state => ({ + ...state, + dataIsLoading: false + })), on(searchActions.destroyResults, state => ({ ...state, searchData: [], @@ -135,8 +154,10 @@ export const selectResultStepChecked = (state: State) => state.resultStepChecked export const selectIsConeSearchAdded = (state: State) => state.coneSearchAdded; export const selectCriteriaList = (state: State) => state.criteriaList; export const selectOutputList = (state: State) => state.outputList; -export const selectSearchData = (state: State) => state.searchData; export const selectDataLengthIsLoading = (state: State) => state.dataLengthIsLoading; export const selectDataLengthIsLoaded = (state: State) => state.dataLengthIsLoaded; export const selectDataLength = (state: State) => state.dataLength; +export const selectData = (state: State) => state.data; +export const selectDataIsLoading = (state: State) => state.dataIsLoading; +export const selectDataIsLoaded = (state: State) => state.dataIsLoaded; export const selectSelectedData = (state: State) => state.selectedData; diff --git a/client/src/app/instance/store/selectors/search.selector.ts b/client/src/app/instance/store/selectors/search.selector.ts index 57c9c1ba203f8b55a00d07d254b5adc7ebc54025..ee70032ca896242b28fe17f59bd61982c7159f74 100644 --- a/client/src/app/instance/store/selectors/search.selector.ts +++ b/client/src/app/instance/store/selectors/search.selector.ts @@ -63,11 +63,6 @@ export const selectOutputList = createSelector( fromSearch.selectOutputList ); -export const selectSearchData = createSelector( - selectInstanceState, - fromSearch.selectSearchData -); - export const selectDataLengthIsLoading = createSelector( selectInstanceState, fromSearch.selectDataLengthIsLoading @@ -83,6 +78,21 @@ export const selectDataLength = createSelector( fromSearch.selectDataLength ); +export const selectDataIsLoading = createSelector( + selectInstanceState, + fromSearch.selectDataIsLoading +); + +export const selectDataIsLoaded = createSelector( + selectInstanceState, + fromSearch.selectDataIsLoaded +); + +export const selectData = createSelector( + selectInstanceState, + fromSearch.selectData +); + export const selectSelectedData = createSelector( selectInstanceState, fromSearch.selectSelectedData diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index b9c2adcca2576927a0172d6cc21ef29446b151a6..b402511e14ee743e933a76b564ed0d8110bf17d4 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts @@ -23,6 +23,7 @@ import { BsDatepickerModule } from 'ngx-bootstrap/datepicker'; import { TabsModule } from 'ngx-bootstrap/tabs'; import { PaginationModule } from 'ngx-bootstrap/pagination'; import { NgSelectModule } from '@ng-select/ng-select'; +import { NgxJsonViewerModule } from 'ngx-json-viewer'; import { sharedComponents } from './components'; import { sharedPipes } from './pipes'; @@ -47,7 +48,8 @@ import { sharedPipes } from './pipes'; BsDatepickerModule.forRoot(), TabsModule.forRoot(), PaginationModule.forRoot(), - NgSelectModule + NgSelectModule, + NgxJsonViewerModule ], exports: [ CommonModule, @@ -64,6 +66,7 @@ import { sharedPipes } from './pipes'; TabsModule, PaginationModule, NgSelectModule, + NgxJsonViewerModule, sharedComponents, sharedPipes ] diff --git a/client/src/styles.scss b/client/src/styles.scss index 89e2847317aee8ea63bab7e9eed39a5efd9577d3..93c9c212bf75cf6478a33cb0053f85a4eeb36a8b 100644 --- a/client/src/styles.scss +++ b/client/src/styles.scss @@ -27,6 +27,7 @@ @import "~bootstrap/scss/popover"; @import "~bootstrap/scss/tooltip"; @import "~bootstrap/scss/progress"; +@import "~bootstrap/scss/pagination"; @import "~bootstrap/scss/utilities"; /* Import ngx-toastr bootstrap 4 alert styled design */ diff --git a/client/tsconfig.json b/client/tsconfig.json index 12fb7bd5716788a2329c07c6149895a726e40e93..824b803cca255aed75c72380255ffcc15fe1c85b 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -25,6 +25,7 @@ "enableI18nLegacyMessageIdFormat": false, "strictInjectionParameters": true, "strictInputAccessModifiers": true, - "strictTemplates": true + "strictTemplates": true, + "strictDomEventTypes": false } } diff --git a/client/yarn.lock b/client/yarn.lock index 922a5191405b94b0e056cf1e444f9ffab445deaa..2a005f9358ac87f05bedd31cb41ab6f7bf727db2 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -4908,7 +4908,6 @@ minipass-fetch@^1.3.0, minipass-fetch@^1.3.2: resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.3.3.tgz#34c7cea038c817a8658461bf35174551dce17a0a" integrity sha512-akCrLDWfbdAWkMLBxJEeWTdNsjML+dt5YgOI4gJ53vuO0vrmYQkUPxa6j6V65s9CcePIr2SSWqjT2EcrNseryQ== dependencies: - encoding "^0.1.12" minipass "^3.1.0" minipass-sized "^1.0.3" minizlib "^2.0.0" @@ -5070,6 +5069,13 @@ ngx-bootstrap@^7.0.0-rc.1: dependencies: tslib "^2.0.0" +ngx-json-viewer@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/ngx-json-viewer/-/ngx-json-viewer-3.0.2.tgz#91e72fe41f80756181aa0d36b4bfaeac5df5b1b1" + integrity sha512-XBj0DgUDIBOeJuAczlFQIIMCaELJGoEbvjBWIXHIh2QebiB5lY6itslRkbE5TAgFn1bYK+2ToxqwspLgP4DDJg== + dependencies: + tslib "^2.0.0" + ngx-toastr@^14.0.0: version "14.0.0" resolved "https://registry.yarnpkg.com/ngx-toastr/-/ngx-toastr-14.0.0.tgz#20e4737ef330b892a453768cd98b980558aeb286"