mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
Merge remote-tracking branch 'refs/remotes/github/main' into task/main/DURACOM-263
This commit is contained in:
@@ -7,8 +7,10 @@
|
|||||||
} }}
|
} }}
|
||||||
</h1>
|
</h1>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<ds-vocabulary-treeview [vocabularyOptions]=vocabularyOptions
|
<ds-vocabulary-treeview [description]="description"
|
||||||
|
[vocabularyOptions]=vocabularyOptions
|
||||||
[multiSelect]="true"
|
[multiSelect]="true"
|
||||||
|
[showAdd]="false"
|
||||||
(select)="onSelect($event)"
|
(select)="onSelect($event)"
|
||||||
(deselect)="onDeselect($event)">
|
(deselect)="onDeselect($event)">
|
||||||
</ds-vocabulary-treeview>
|
</ds-vocabulary-treeview>
|
||||||
|
@@ -14,7 +14,10 @@ import {
|
|||||||
Params,
|
Params,
|
||||||
RouterLink,
|
RouterLink,
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import {
|
||||||
|
TranslateModule,
|
||||||
|
TranslateService,
|
||||||
|
} from '@ngx-translate/core';
|
||||||
import {
|
import {
|
||||||
BehaviorSubject,
|
BehaviorSubject,
|
||||||
Observable,
|
Observable,
|
||||||
@@ -124,6 +127,11 @@ export class BrowseByTaxonomyComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
*/
|
*/
|
||||||
browseDefinition$: Observable<BrowseDefinition>;
|
browseDefinition$: Observable<BrowseDefinition>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Browse description
|
||||||
|
*/
|
||||||
|
description: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscriptions to track
|
* Subscriptions to track
|
||||||
*/
|
*/
|
||||||
@@ -131,6 +139,7 @@ export class BrowseByTaxonomyComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
protected route: ActivatedRoute,
|
protected route: ActivatedRoute,
|
||||||
|
protected translate: TranslateService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,9 +150,11 @@ export class BrowseByTaxonomyComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
this.subs.push(this.browseDefinition$.subscribe((browseDefinition: HierarchicalBrowseDefinition) => {
|
this.subs.push(this.browseDefinition$.subscribe((browseDefinition: HierarchicalBrowseDefinition) => {
|
||||||
|
this.selectedItems = [];
|
||||||
this.facetType = browseDefinition.facetType;
|
this.facetType = browseDefinition.facetType;
|
||||||
this.vocabularyName = browseDefinition.vocabulary;
|
this.vocabularyName = browseDefinition.vocabulary;
|
||||||
this.vocabularyOptions = { name: this.vocabularyName, closed: true };
|
this.vocabularyOptions = { name: this.vocabularyName, closed: true };
|
||||||
|
this.description = this.translate.instant(`browse.metadata.${this.vocabularyName}.tree.descrption`);
|
||||||
}));
|
}));
|
||||||
this.subs.push(this.scope$.subscribe(() => {
|
this.subs.push(this.scope$.subscribe(() => {
|
||||||
this.updateQueryParams();
|
this.updateQueryParams();
|
||||||
|
@@ -293,7 +293,7 @@ export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent imple
|
|||||||
const modalRef: NgbModalRef = this.modalService.open(VocabularyTreeviewModalComponent, { size: 'lg', windowClass: 'treeview' });
|
const modalRef: NgbModalRef = this.modalService.open(VocabularyTreeviewModalComponent, { size: 'lg', windowClass: 'treeview' });
|
||||||
modalRef.componentInstance.vocabularyOptions = this.model.vocabularyOptions;
|
modalRef.componentInstance.vocabularyOptions = this.model.vocabularyOptions;
|
||||||
modalRef.componentInstance.preloadLevel = preloadLevel;
|
modalRef.componentInstance.preloadLevel = preloadLevel;
|
||||||
modalRef.componentInstance.selectedItems = this.currentValue ? [this.currentValue.value] : [];
|
modalRef.componentInstance.selectedItems = this.currentValue ? [this.currentValue] : [];
|
||||||
modalRef.result.then((result: VocabularyEntryDetail) => {
|
modalRef.result.then((result: VocabularyEntryDetail) => {
|
||||||
if (result) {
|
if (result) {
|
||||||
this.currentValue = result;
|
this.currentValue = result;
|
||||||
|
@@ -7,9 +7,11 @@
|
|||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="p-3">
|
<div class="p-3">
|
||||||
<ds-vocabulary-treeview [vocabularyOptions]="vocabularyOptions"
|
<ds-vocabulary-treeview [vocabularyOptions]="vocabularyOptions"
|
||||||
|
[description]="description"
|
||||||
[preloadLevel]="preloadLevel"
|
[preloadLevel]="preloadLevel"
|
||||||
[selectedItems]="selectedItems"
|
[selectedItems]="selectedItems"
|
||||||
[multiSelect]="multiSelect"
|
[multiSelect]="multiSelect"
|
||||||
|
[showAdd]="showAdd"
|
||||||
(select)="onSelect($event)">
|
(select)="onSelect($event)">
|
||||||
</ds-vocabulary-treeview>
|
</ds-vocabulary-treeview>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -5,6 +5,7 @@ import {
|
|||||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { VocabularyOptions } from '../../../core/submission/vocabularies/models/vocabulary-options.model';
|
||||||
import { VocabularyTreeviewComponent } from '../vocabulary-treeview/vocabulary-treeview.component';
|
import { VocabularyTreeviewComponent } from '../vocabulary-treeview/vocabulary-treeview.component';
|
||||||
import { VocabularyTreeviewModalComponent } from './vocabulary-treeview-modal.component';
|
import { VocabularyTreeviewModalComponent } from './vocabulary-treeview-modal.component';
|
||||||
|
|
||||||
@@ -13,6 +14,7 @@ describe('VocabularyTreeviewModalComponent', () => {
|
|||||||
let fixture: ComponentFixture<VocabularyTreeviewModalComponent>;
|
let fixture: ComponentFixture<VocabularyTreeviewModalComponent>;
|
||||||
|
|
||||||
const modalStub = jasmine.createSpyObj('modalStub', ['close']);
|
const modalStub = jasmine.createSpyObj('modalStub', ['close']);
|
||||||
|
const vocabularyOptions = new VocabularyOptions('vocabularyTest', false);
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
@@ -32,10 +34,16 @@ describe('VocabularyTreeviewModalComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(VocabularyTreeviewModalComponent);
|
fixture = TestBed.createComponent(VocabularyTreeviewModalComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
component.vocabularyOptions = vocabularyOptions;
|
||||||
|
spyOn(component as any, 'setDescription').and.callThrough();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
expect(component).toBeTruthy();
|
expect(component).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should init descrption message', () => {
|
||||||
|
expect((component as any).setDescription).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -2,10 +2,14 @@ import {
|
|||||||
Component,
|
Component,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
Input,
|
Input,
|
||||||
|
OnInit,
|
||||||
Output,
|
Output,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import {
|
||||||
|
TranslateModule,
|
||||||
|
TranslateService,
|
||||||
|
} from '@ngx-translate/core';
|
||||||
|
|
||||||
import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
|
import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
|
||||||
import { VocabularyOptions } from '../../../core/submission/vocabularies/models/vocabulary-options.model';
|
import { VocabularyOptions } from '../../../core/submission/vocabularies/models/vocabulary-options.model';
|
||||||
@@ -24,7 +28,7 @@ import { VocabularyTreeviewComponent } from '../vocabulary-treeview/vocabulary-t
|
|||||||
/**
|
/**
|
||||||
* Component that contains a modal to display a VocabularyTreeviewComponent
|
* Component that contains a modal to display a VocabularyTreeviewComponent
|
||||||
*/
|
*/
|
||||||
export class VocabularyTreeviewModalComponent {
|
export class VocabularyTreeviewModalComponent implements OnInit {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link VocabularyOptions} object
|
* The {@link VocabularyOptions} object
|
||||||
@@ -39,13 +43,23 @@ export class VocabularyTreeviewModalComponent {
|
|||||||
/**
|
/**
|
||||||
* The vocabulary entries already selected, if any
|
* The vocabulary entries already selected, if any
|
||||||
*/
|
*/
|
||||||
@Input() selectedItems: string[] = [];
|
@Input() selectedItems: VocabularyEntryDetail[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to allow selecting multiple values with checkboxes
|
* Whether to allow selecting multiple values with checkboxes
|
||||||
*/
|
*/
|
||||||
@Input() multiSelect = false;
|
@Input() multiSelect = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if to show the add button or not
|
||||||
|
*/
|
||||||
|
@Input() showAdd = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contain a descriptive message for this vocabulary retrieved from i18n files
|
||||||
|
*/
|
||||||
|
description: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event fired when a vocabulary entry is selected.
|
* An event fired when a vocabulary entry is selected.
|
||||||
* Event's payload equals to {@link VocabularyEntryDetail} selected.
|
* Event's payload equals to {@link VocabularyEntryDetail} selected.
|
||||||
@@ -56,11 +70,17 @@ export class VocabularyTreeviewModalComponent {
|
|||||||
* Initialize instance variables
|
* Initialize instance variables
|
||||||
*
|
*
|
||||||
* @param {NgbActiveModal} activeModal
|
* @param {NgbActiveModal} activeModal
|
||||||
|
* @param {TranslateService} translate
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
public activeModal: NgbActiveModal,
|
public activeModal: NgbActiveModal,
|
||||||
|
protected translate: TranslateService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.setDescription();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method called on entry select
|
* Method called on entry select
|
||||||
*/
|
*/
|
||||||
@@ -68,4 +88,13 @@ export class VocabularyTreeviewModalComponent {
|
|||||||
this.select.emit(item);
|
this.select.emit(item);
|
||||||
this.activeModal.close(item);
|
this.activeModal.close(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the description message related to the given vocabulary
|
||||||
|
*/
|
||||||
|
private setDescription() {
|
||||||
|
const descriptionLabel = 'vocabulary-treeview.tree.description.' + this.vocabularyOptions.name;
|
||||||
|
this.description = this.translate.instant(descriptionLabel);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<ds-alert [content]="'vocabulary-treeview.info' | translate" [type]="AlertType.Info"></ds-alert>
|
<ds-alert *ngIf="description" [content]="description" [type]="AlertType.Info"></ds-alert>
|
||||||
<div class="treeview-header row mb-1">
|
<div class="treeview-header row mb-1">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
<button class="btn btn-outline-secondary" type="button" (click)="reset()">
|
<button class="btn btn-outline-secondary" type="button" (click)="reset()">
|
||||||
{{'vocabulary-treeview.search.form.reset' | translate}}
|
{{'vocabulary-treeview.search.form.reset' | translate}}
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-primary" type="button" (click)="add()" [disabled]="this.vocabularyOptions.closed">
|
<button *ngIf="showAdd && this.vocabularyOptions.closed" class="btn btn-outline-primary" type="button" (click)="add()">
|
||||||
{{'vocabulary-treeview.search.form.add' | translate}}
|
{{'vocabulary-treeview.search.form.add' | translate}}
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-primary" type="button" (click)="add()" [disabled]="this.vocabularyOptions.closed">
|
<button class="btn btn-outline-primary" type="button" (click)="add()" [disabled]="this.vocabularyOptions.closed">
|
||||||
|
@@ -13,14 +13,9 @@ import {
|
|||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { StoreModule } from '@ngrx/store';
|
|
||||||
import { provideMockStore } from '@ngrx/store/testing';
|
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
|
|
||||||
import { storeModuleConfig } from '../../../app.reducer';
|
|
||||||
import { authReducer } from '../../../core/auth/auth.reducer';
|
|
||||||
import { AuthTokenInfo } from '../../../core/auth/models/auth-token-info.model';
|
|
||||||
import { PageInfo } from '../../../core/shared/page-info.model';
|
import { PageInfo } from '../../../core/shared/page-info.model';
|
||||||
import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
|
import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
|
||||||
import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
|
import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
|
||||||
@@ -40,7 +35,6 @@ describe('VocabularyTreeviewComponent test suite', () => {
|
|||||||
let comp: VocabularyTreeviewComponent;
|
let comp: VocabularyTreeviewComponent;
|
||||||
let compAsAny: any;
|
let compAsAny: any;
|
||||||
let fixture: ComponentFixture<VocabularyTreeviewComponent>;
|
let fixture: ComponentFixture<VocabularyTreeviewComponent>;
|
||||||
let initialState;
|
|
||||||
let de;
|
let de;
|
||||||
|
|
||||||
const item = new VocabularyEntryDetail();
|
const item = new VocabularyEntryDetail();
|
||||||
@@ -71,25 +65,10 @@ describe('VocabularyTreeviewComponent test suite', () => {
|
|||||||
clearSearchTopRequests: jasmine.createSpy('clearSearchTopRequests'),
|
clearSearchTopRequests: jasmine.createSpy('clearSearchTopRequests'),
|
||||||
});
|
});
|
||||||
|
|
||||||
initialState = {
|
|
||||||
core: {
|
|
||||||
auth: {
|
|
||||||
authenticated: true,
|
|
||||||
loaded: true,
|
|
||||||
blocking: false,
|
|
||||||
loading: false,
|
|
||||||
authToken: new AuthTokenInfo('test_token'),
|
|
||||||
userId: 'testid',
|
|
||||||
authMethods: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(waitForAsync(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
CdkTreeModule,
|
CdkTreeModule,
|
||||||
StoreModule.forRoot({ auth: authReducer }, storeModuleConfig),
|
|
||||||
TranslateModule.forRoot(),
|
TranslateModule.forRoot(),
|
||||||
VocabularyTreeviewComponent,
|
VocabularyTreeviewComponent,
|
||||||
TestComponent,
|
TestComponent,
|
||||||
@@ -99,7 +78,6 @@ describe('VocabularyTreeviewComponent test suite', () => {
|
|||||||
{ provide: VocabularyTreeviewService, useValue: vocabularyTreeviewServiceStub },
|
{ provide: VocabularyTreeviewService, useValue: vocabularyTreeviewServiceStub },
|
||||||
{ provide: VocabularyService, useValue: vocabularyServiceStub },
|
{ provide: VocabularyService, useValue: vocabularyServiceStub },
|
||||||
{ provide: NgbActiveModal, useValue: modalStub },
|
{ provide: NgbActiveModal, useValue: modalStub },
|
||||||
provideMockStore({ initialState }),
|
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
VocabularyTreeviewComponent,
|
VocabularyTreeviewComponent,
|
||||||
],
|
],
|
||||||
@@ -155,10 +133,10 @@ describe('VocabularyTreeviewComponent test suite', () => {
|
|||||||
currentValue.otherInformation = {
|
currentValue.otherInformation = {
|
||||||
id: 'entryID',
|
id: 'entryID',
|
||||||
};
|
};
|
||||||
comp.selectedItems = [currentValue.value];
|
comp.selectedItems = [currentValue];
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(comp.dataSource.data).toEqual([]);
|
expect(comp.dataSource.data).toEqual([]);
|
||||||
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['testValue'], null);
|
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['entryID'], 'entryID');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should should init component properly with init value as VocabularyEntry', () => {
|
it('should should init component properly with init value as VocabularyEntry', () => {
|
||||||
@@ -167,10 +145,20 @@ describe('VocabularyTreeviewComponent test suite', () => {
|
|||||||
currentValue.otherInformation = {
|
currentValue.otherInformation = {
|
||||||
id: 'entryID',
|
id: 'entryID',
|
||||||
};
|
};
|
||||||
comp.selectedItems = [currentValue.value];
|
comp.selectedItems = [currentValue];
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(comp.dataSource.data).toEqual([]);
|
expect(comp.dataSource.data).toEqual([]);
|
||||||
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['testValue'], null);
|
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['entryID'], 'entryID');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should should init component properly with init value as VocabularyEntryDetail', () => {
|
||||||
|
const currentValue = new VocabularyEntryDetail();
|
||||||
|
currentValue.value = 'testValue';
|
||||||
|
currentValue.id = 'entryID';
|
||||||
|
comp.selectedItems = [currentValue];
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(comp.dataSource.data).toEqual([]);
|
||||||
|
expect(vocabularyTreeviewServiceStub.initialize).toHaveBeenCalledWith(comp.vocabularyOptions, new PageInfo(), ['entryID'], 'entryID');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call loadMore function', () => {
|
it('should call loadMore function', () => {
|
||||||
|
@@ -18,23 +18,16 @@ import {
|
|||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { Store } from '@ngrx/store';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import {
|
|
||||||
TranslateModule,
|
|
||||||
TranslateService,
|
|
||||||
} from '@ngx-translate/core';
|
|
||||||
import {
|
import {
|
||||||
Observable,
|
Observable,
|
||||||
Subscription,
|
Subscription,
|
||||||
} from 'rxjs';
|
} from 'rxjs';
|
||||||
|
|
||||||
import { CoreState } from '../../../core/core-state.model';
|
|
||||||
import { getFirstSucceededRemoteDataPayload } from '../../../core/shared/operators';
|
|
||||||
import { PageInfo } from '../../../core/shared/page-info.model';
|
import { PageInfo } from '../../../core/shared/page-info.model';
|
||||||
import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
|
import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
|
||||||
import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
|
import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
|
||||||
import { VocabularyOptions } from '../../../core/submission/vocabularies/models/vocabulary-options.model';
|
import { VocabularyOptions } from '../../../core/submission/vocabularies/models/vocabulary-options.model';
|
||||||
import { VocabularyService } from '../../../core/submission/vocabularies/vocabulary.service';
|
|
||||||
import { AlertComponent } from '../../alert/alert.component';
|
import { AlertComponent } from '../../alert/alert.component';
|
||||||
import { AlertType } from '../../alert/alert-type';
|
import { AlertType } from '../../alert/alert-type';
|
||||||
import {
|
import {
|
||||||
@@ -43,6 +36,7 @@ import {
|
|||||||
isNotEmpty,
|
isNotEmpty,
|
||||||
} from '../../empty.util';
|
} from '../../empty.util';
|
||||||
import { ThemedLoadingComponent } from '../../loading/themed-loading.component';
|
import { ThemedLoadingComponent } from '../../loading/themed-loading.component';
|
||||||
|
import { FormFieldMetadataValueObject } from '../builder/models/form-field-metadata-value.model';
|
||||||
import { VocabularyTreeFlatDataSource } from './vocabulary-tree-flat-data-source';
|
import { VocabularyTreeFlatDataSource } from './vocabulary-tree-flat-data-source';
|
||||||
import { VocabularyTreeFlattener } from './vocabulary-tree-flattener';
|
import { VocabularyTreeFlattener } from './vocabulary-tree-flattener';
|
||||||
import { VocabularyTreeviewService } from './vocabulary-treeview.service';
|
import { VocabularyTreeviewService } from './vocabulary-treeview.service';
|
||||||
@@ -53,6 +47,8 @@ import {
|
|||||||
TreeviewNode,
|
TreeviewNode,
|
||||||
} from './vocabulary-treeview-node.model';
|
} from './vocabulary-treeview-node.model';
|
||||||
|
|
||||||
|
export type VocabularyTreeItemType = FormFieldMetadataValueObject | VocabularyEntry | VocabularyEntryDetail;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that shows a hierarchical vocabulary in a tree view
|
* Component that shows a hierarchical vocabulary in a tree view
|
||||||
*/
|
*/
|
||||||
@@ -85,15 +81,25 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
|
|||||||
@Input() preloadLevel = 2;
|
@Input() preloadLevel = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The vocabulary entries already selected, if any
|
* Contain a descriptive message for the tree
|
||||||
*/
|
*/
|
||||||
@Input() selectedItems: string[] = [];
|
@Input() description = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to allow selecting multiple values with checkboxes
|
* Whether to allow selecting multiple values with checkboxes
|
||||||
*/
|
*/
|
||||||
@Input() multiSelect = false;
|
@Input() multiSelect = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if to show the add button or not
|
||||||
|
*/
|
||||||
|
@Input() showAdd = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The vocabulary entries already selected, if any
|
||||||
|
*/
|
||||||
|
@Input() selectedItems: VocabularyTreeItemType[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A map containing the current node showed by the tree
|
* A map containing the current node showed by the tree
|
||||||
*/
|
*/
|
||||||
@@ -131,20 +137,15 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An event fired when a vocabulary entry is selected.
|
* An event fired when a vocabulary entry is selected.
|
||||||
* Event's payload equals to {@link VocabularyEntryDetail} selected.
|
* Event's payload equals to {@link VocabularyTreeItemType} selected.
|
||||||
*/
|
*/
|
||||||
@Output() select: EventEmitter<VocabularyEntryDetail> = new EventEmitter<VocabularyEntryDetail>(null);
|
@Output() select: EventEmitter<VocabularyTreeItemType> = new EventEmitter<VocabularyTreeItemType>(null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event fired when a vocabulary entry is deselected.
|
* An event fired when a vocabulary entry is deselected.
|
||||||
* Event's payload equals to {@link VocabularyEntryDetail} deselected.
|
* Event's payload equals to {@link VocabularyTreeItemType} deselected.
|
||||||
*/
|
*/
|
||||||
@Output() deselect: EventEmitter<VocabularyEntryDetail> = new EventEmitter<VocabularyEntryDetail>(null);
|
@Output() deselect: EventEmitter<VocabularyTreeItemType> = new EventEmitter<VocabularyTreeItemType>(null);
|
||||||
|
|
||||||
/**
|
|
||||||
* A boolean representing if user is authenticated
|
|
||||||
*/
|
|
||||||
private isAuthenticated: Observable<boolean>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array to track all subscriptions and unsubscribe them onDestroy
|
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||||
@@ -157,15 +158,9 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
|
|||||||
* Initialize instance variables
|
* Initialize instance variables
|
||||||
*
|
*
|
||||||
* @param {VocabularyTreeviewService} vocabularyTreeviewService
|
* @param {VocabularyTreeviewService} vocabularyTreeviewService
|
||||||
* @param {vocabularyService} vocabularyService
|
|
||||||
* @param {Store<CoreState>} store
|
|
||||||
* @param {TranslateService} translate
|
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
private vocabularyTreeviewService: VocabularyTreeviewService,
|
private vocabularyTreeviewService: VocabularyTreeviewService,
|
||||||
private vocabularyService: VocabularyService,
|
|
||||||
private store: Store<CoreState>,
|
|
||||||
private translate: TranslateService,
|
|
||||||
) {
|
) {
|
||||||
this.treeFlattener = new VocabularyTreeFlattener(this.transformer, this.getLevel,
|
this.treeFlattener = new VocabularyTreeFlattener(this.transformer, this.getLevel,
|
||||||
this.isExpandable, this.getChildren);
|
this.isExpandable, this.getChildren);
|
||||||
@@ -187,7 +182,8 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
|
|||||||
* @param level The node level information
|
* @param level The node level information
|
||||||
*/
|
*/
|
||||||
transformer = (node: TreeviewNode, level: number) => {
|
transformer = (node: TreeviewNode, level: number) => {
|
||||||
const existingNode = this.nodeMap.get(node.item.id);
|
const entryId = this.getEntryId(node.item);
|
||||||
|
const existingNode = this.nodeMap.get(entryId);
|
||||||
|
|
||||||
if (existingNode && existingNode.item.id !== LOAD_MORE && existingNode.item.id !== LOAD_MORE_ROOT) {
|
if (existingNode && existingNode.item.id !== LOAD_MORE && existingNode.item.id !== LOAD_MORE_ROOT) {
|
||||||
return existingNode;
|
return existingNode;
|
||||||
@@ -204,7 +200,7 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
|
|||||||
node.isInInitValueHierarchy,
|
node.isInInitValueHierarchy,
|
||||||
node.isSelected,
|
node.isSelected,
|
||||||
);
|
);
|
||||||
this.nodeMap.set(node.item.id, newNode);
|
this.nodeMap.set(entryId, newNode);
|
||||||
|
|
||||||
if ((((level + 1) < this.preloadLevel) && newNode.childrenLoaded)
|
if ((((level + 1) < this.preloadLevel) && newNode.childrenLoaded)
|
||||||
|| (newNode.isSearchNode && newNode.childrenLoaded)
|
|| (newNode.isSearchNode && newNode.childrenLoaded)
|
||||||
@@ -259,7 +255,8 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
|
|||||||
|
|
||||||
this.loading = this.vocabularyTreeviewService.isLoading();
|
this.loading = this.vocabularyTreeviewService.isLoading();
|
||||||
|
|
||||||
this.vocabularyTreeviewService.initialize(this.vocabularyOptions, new PageInfo(), this.selectedItems, null);
|
const entryId: string = (this.selectedItems?.length > 0) ? this.getEntryId(this.selectedItems[0]) : null;
|
||||||
|
this.vocabularyTreeviewService.initialize(this.vocabularyOptions, new PageInfo(), this.getSelectedEntryIds(), entryId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -267,7 +264,7 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
|
|||||||
* @param item The VocabularyEntryDetail for which to load more nodes
|
* @param item The VocabularyEntryDetail for which to load more nodes
|
||||||
*/
|
*/
|
||||||
loadMore(item: VocabularyEntryDetail) {
|
loadMore(item: VocabularyEntryDetail) {
|
||||||
this.vocabularyTreeviewService.loadMore(item, this.selectedItems);
|
this.vocabularyTreeviewService.loadMore(item, this.getSelectedEntryIds());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -275,7 +272,7 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
|
|||||||
* @param node The TreeviewFlatNode for which to load more nodes
|
* @param node The TreeviewFlatNode for which to load more nodes
|
||||||
*/
|
*/
|
||||||
loadMoreRoot(node: TreeviewFlatNode) {
|
loadMoreRoot(node: TreeviewFlatNode) {
|
||||||
this.vocabularyTreeviewService.loadMoreRoot(node, this.selectedItems);
|
this.vocabularyTreeviewService.loadMoreRoot(node, this.getSelectedEntryIds());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -283,18 +280,18 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
|
|||||||
* @param node The TreeviewFlatNode for which to load children nodes
|
* @param node The TreeviewFlatNode for which to load children nodes
|
||||||
*/
|
*/
|
||||||
loadChildren(node: TreeviewFlatNode) {
|
loadChildren(node: TreeviewFlatNode) {
|
||||||
this.vocabularyTreeviewService.loadMore(node.item, this.selectedItems, true);
|
this.vocabularyTreeviewService.loadMore(node.item, this.getSelectedEntryIds(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method called on entry select/deselect
|
* Method called on entry select/deselect
|
||||||
*/
|
*/
|
||||||
onSelect(item: VocabularyEntryDetail) {
|
onSelect(item: VocabularyEntryDetail) {
|
||||||
if (!this.selectedItems.includes(item.id)) {
|
if (!this.getSelectedEntryIds().includes(this.getEntryId(item))) {
|
||||||
this.selectedItems.push(item.id);
|
this.selectedItems.push(item);
|
||||||
this.select.emit(item);
|
this.select.emit(item);
|
||||||
} else {
|
} else {
|
||||||
this.selectedItems = this.selectedItems.filter((detail: string) => { return detail !== item.id; });
|
this.selectedItems = this.selectedItems.filter((detail: VocabularyTreeItemType) => this.getEntryId(detail) !== this.getEntryId(item));
|
||||||
this.deselect.emit(item);
|
this.deselect.emit(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -308,7 +305,7 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
|
|||||||
this.storedNodeMap = this.nodeMap;
|
this.storedNodeMap = this.nodeMap;
|
||||||
}
|
}
|
||||||
this.nodeMap = new Map<string, TreeviewFlatNode>();
|
this.nodeMap = new Map<string, TreeviewFlatNode>();
|
||||||
this.vocabularyTreeviewService.searchByQuery(this.searchText, this.selectedItems);
|
this.vocabularyTreeviewService.searchByQuery(this.searchText, this.getSelectedEntryIds());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,12 +322,8 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
|
|||||||
reset() {
|
reset() {
|
||||||
this.searchText = '';
|
this.searchText = '';
|
||||||
for (const item of this.selectedItems) {
|
for (const item of this.selectedItems) {
|
||||||
this.subs.push(this.vocabularyService.findEntryDetailById(item, this.vocabularyOptions.name, true, true, false).pipe(
|
this.deselect.emit(item);
|
||||||
getFirstSucceededRemoteDataPayload(),
|
this.nodeMap.get(this.getEntryId(item)).isSelected = false;
|
||||||
).subscribe((detail: VocabularyEntryDetail) => {
|
|
||||||
this.deselect.emit(detail);
|
|
||||||
}));
|
|
||||||
this.nodeMap.get(item).isSelected = false;
|
|
||||||
}
|
}
|
||||||
this.selectedItems = [];
|
this.selectedItems = [];
|
||||||
|
|
||||||
@@ -361,14 +354,27 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an id for a given {@link VocabularyEntry}
|
* Return an id for a given {@link VocabularyTreeItemType}
|
||||||
*/
|
*/
|
||||||
private getEntryId(entry: VocabularyEntry): string {
|
private getEntryId(entry: VocabularyTreeItemType): string {
|
||||||
return entry.authority || entry.otherInformation.id || undefined;
|
return entry?.authority || entry?.otherInformation?.id || (entry as any)?.id || undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an ids for all selected entries
|
||||||
|
*/
|
||||||
|
private getSelectedEntryIds(): string[] {
|
||||||
|
return this.selectedItems
|
||||||
|
.map((entry: VocabularyTreeItemType) => this.getEntryId(entry))
|
||||||
|
.filter((value) => isNotEmpty(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges): void {
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
this.reset();
|
if (!changes.vocabularyOptions.isFirstChange() && changes.vocabularyOptions.currentValue !== changes.vocabularyOptions.previousValue) {
|
||||||
this.vocabularyTreeviewService.initialize(this.vocabularyOptions, new PageInfo(), this.selectedItems, null);
|
this.selectedItems = [];
|
||||||
|
this.searchText = '';
|
||||||
|
this.vocabularyTreeviewService.cleanTree();
|
||||||
|
this.vocabularyTreeviewService.initialize(this.vocabularyOptions, new PageInfo(), this.getSelectedEntryIds(), null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -260,7 +260,7 @@ export class VocabularyTreeviewService {
|
|||||||
const hasChildren = entry.hasOtherInformation() && (entry.otherInformation as any)!.hasChildren === 'true';
|
const hasChildren = entry.hasOtherInformation() && (entry.otherInformation as any)!.hasChildren === 'true';
|
||||||
const pageInfo: PageInfo = this.pageInfo;
|
const pageInfo: PageInfo = this.pageInfo;
|
||||||
const isInInitValueHierarchy = this.initValueHierarchy.includes(entryId);
|
const isInInitValueHierarchy = this.initValueHierarchy.includes(entryId);
|
||||||
const isSelected: boolean = selectedItems.some(() => selectedItems.includes(entry.id));
|
const isSelected: boolean = selectedItems.some(() => selectedItems.includes(entryId));
|
||||||
const result = new TreeviewNode(
|
const result = new TreeviewNode(
|
||||||
entry,
|
entry,
|
||||||
hasChildren,
|
hasChildren,
|
||||||
|
@@ -126,6 +126,7 @@ export class SearchHierarchyFilterComponent extends SearchFacetFilterComponent i
|
|||||||
name: this.getVocabularyEntry(),
|
name: this.getVocabularyEntry(),
|
||||||
closed: true,
|
closed: true,
|
||||||
};
|
};
|
||||||
|
modalRef.componentInstance.showAdd = false;
|
||||||
this.subs.push(from(modalRef.result).pipe(
|
this.subs.push(from(modalRef.result).pipe(
|
||||||
switchMap((detail: VocabularyEntryDetail) => this.searchConfigService.selectNewAppliedFilterParams(this.filterConfig.name, detail.value, 'equals')),
|
switchMap((detail: VocabularyEntryDetail) => this.searchConfigService.selectNewAppliedFilterParams(this.filterConfig.name, detail.value, 'equals')),
|
||||||
take(1),
|
take(1),
|
||||||
|
@@ -1034,8 +1034,12 @@
|
|||||||
|
|
||||||
"browse.metadata.srsc.breadcrumbs": "Browse by Subject Category",
|
"browse.metadata.srsc.breadcrumbs": "Browse by Subject Category",
|
||||||
|
|
||||||
|
"browse.metadata.srsc.tree.descrption": "Select a subject to add as search filter",
|
||||||
|
|
||||||
"browse.metadata.nsi.breadcrumbs": "Browse by Norwegian Science Index",
|
"browse.metadata.nsi.breadcrumbs": "Browse by Norwegian Science Index",
|
||||||
|
|
||||||
|
"browse.metadata.nsi.tree.descrption": "Select an index to add as search filter",
|
||||||
|
|
||||||
"browse.metadata.title.breadcrumbs": "Browse by Title",
|
"browse.metadata.title.breadcrumbs": "Browse by Title",
|
||||||
|
|
||||||
"pagination.next.button": "Next",
|
"pagination.next.button": "Next",
|
||||||
|
Reference in New Issue
Block a user