diff --git a/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts
index d2f3de2dc3..7aa81116de 100644
--- a/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts
+++ b/src/app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.ts
@@ -13,6 +13,6 @@ import { facetLoad, SearchFacetFilterComponent } from '../search-facet-filter/se
/**
* Component that represents a hierarchy facet for a specific filter configuration
*/
-@renderFacetFor(FilterType.hierarchy)
+// @renderFacetFor(FilterType.hierarchy)
export class SearchHierarchyFilterComponent extends SearchFacetFilterComponent implements OnInit {
}
diff --git a/src/themes/okr/app/shared/okr-vocabulary-treeview/okr-vocabulary-treeview.component.ts b/src/themes/okr/app/shared/okr-vocabulary-treeview/okr-vocabulary-treeview.component.ts
index f340cdfccf..f33f7d89e9 100644
--- a/src/themes/okr/app/shared/okr-vocabulary-treeview/okr-vocabulary-treeview.component.ts
+++ b/src/themes/okr/app/shared/okr-vocabulary-treeview/okr-vocabulary-treeview.component.ts
@@ -1,10 +1,11 @@
import { Component } from '@angular/core';
import { VocabularyTreeviewComponent } from '../../../../../app/shared/vocabulary-treeview/vocabulary-treeview.component';
-import { filter, find, startWith } from 'rxjs/operators';
+import { filter, startWith } from 'rxjs/operators';
import { PageInfo } from '../../../../../app/core/shared/page-info.model';
/**
- * Component that show a hierarchical vocabulary in a tree view
+ * Component that show a hierarchical vocabulary in a tree view.
+ * Worldbank customization which omits the authentication check.
*/
@Component({
selector: 'ds-okr-vocabulary-treeview',
@@ -32,16 +33,8 @@ export class OkrVocabularyTreeviewComponent extends VocabularyTreeviewComponent
startWith('')
);
- // set isAuthenticated
- this.isAuthenticated = this.store.pipe(select(isAuthenticated));
-
this.loading = this.vocabularyTreeviewService.isLoading();
- this.isAuthenticated.pipe(
- find((isAuth) => isAuth)
- ).subscribe(() => {
- const entryId: string = (this.selectedItem) ? this.getEntryId(this.selectedItem) : null;
- this.vocabularyTreeviewService.initialize(this.vocabularyOptions, new PageInfo(), entryId);
- });
+ this.vocabularyTreeviewService.initialize(this.vocabularyOptions, new PageInfo(), null);
}
}
diff --git a/src/themes/okr/app/shared/search/search-filters/search-filter/okr-search-hierarchy-filter/okr-search-hierarchy-filter.component.html b/src/themes/okr/app/shared/search/search-filters/search-filter/okr-search-hierarchy-filter/okr-search-hierarchy-filter.component.html
new file mode 100644
index 0000000000..e62006538b
--- /dev/null
+++ b/src/themes/okr/app/shared/search/search-filters/search-filter/okr-search-hierarchy-filter/okr-search-hierarchy-filter.component.html
@@ -0,0 +1,7 @@
+
+
+
+ {{'search.filters.filter.show-tree' | translate: {name: filterConfig.name} }}
+
diff --git a/src/themes/okr/app/shared/search/search-filters/search-filter/okr-search-hierarchy-filter/okr-search-hierarchy-filter.component.scss b/src/themes/okr/app/shared/search/search-filters/search-filter/okr-search-hierarchy-filter/okr-search-hierarchy-filter.component.scss
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/themes/okr/app/shared/search/search-filters/search-filter/okr-search-hierarchy-filter/okr-search-hierarchy-filter.component.spec.ts b/src/themes/okr/app/shared/search/search-filters/search-filter/okr-search-hierarchy-filter/okr-search-hierarchy-filter.component.spec.ts
new file mode 100644
index 0000000000..ce4caa23eb
--- /dev/null
+++ b/src/themes/okr/app/shared/search/search-filters/search-filter/okr-search-hierarchy-filter/okr-search-hierarchy-filter.component.spec.ts
@@ -0,0 +1,156 @@
+import { OkrSearchHierarchyFilterComponent } from './okr-search-hierarchy-filter.component';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { DebugElement, EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core';
+import { By } from '@angular/platform-browser';
+import { VocabularyService } from '../../../../../../../../app/core/submission/vocabularies/vocabulary.service';
+import { of as observableOf } from 'rxjs';
+import { RemoteData } from '../../../../../../../../app/core/data/remote-data';
+import { RequestEntryState } from '../../../../../../../../app/core/data/request.reducer';
+import { TranslateModule } from '@ngx-translate/core';
+import { RouterStub } from '../../../../../../../../app/shared/testing/router.stub';
+import { buildPaginatedList } from '../../../../../../../../app/core/data/paginated-list.model';
+import { PageInfo } from '../../../../../../../../app/core/shared/page-info.model';
+import { CommonModule } from '@angular/common';
+import { SearchService } from '../../../../../../../../app/core/shared/search/search.service';
+import {
+ FILTER_CONFIG,
+ IN_PLACE_SEARCH,
+ SearchFilterService
+} from '../../../../../../../../app/core/shared/search/search-filter.service';
+import { RemoteDataBuildService } from '../../../../../../../../app/core/cache/builders/remote-data-build.service';
+import { Router } from '@angular/router';
+import { NgbModal, NgbModule } from '@ng-bootstrap/ng-bootstrap';
+import { SEARCH_CONFIG_SERVICE } from '../../../../../../../../app/my-dspace-page/my-dspace-page.component';
+import { SearchConfigurationServiceStub } from '../../../../../../../../app/shared/testing/search-configuration-service.stub';
+import { VocabularyEntryDetail } from '../../../../../../../../app/core/submission/vocabularies/models/vocabulary-entry-detail.model';
+import { FacetValue } from '../../../../../../../../app/shared/search/facet-value.model';
+import { SearchFilterConfig } from '../../../../../../../../app/shared/search/search-filter-config.model';
+
+describe('OkrSearchHierarchyFilterComponent', () => {
+
+ let fixture: ComponentFixture;
+ let showVocabularyTreeLink: DebugElement;
+
+ const testSearchLink = 'test-search';
+ const testSearchFilter = 'test-search-filter';
+ const okrVocabularyTreeViewComponent = {
+ select: new EventEmitter(),
+ };
+
+ const searchService = {
+ getSearchLink: () => testSearchLink,
+ getFacetValuesFor: () => observableOf([]),
+ };
+ const searchFilterService = {
+ getPage: () => observableOf(0),
+ };
+ const router = new RouterStub();
+ const ngbModal = jasmine.createSpyObj('modal', {
+ open: {
+ componentInstance: okrVocabularyTreeViewComponent,
+ }
+ });
+ const vocabularyService = {
+ searchTopEntries: () => undefined,
+ };
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ CommonModule,
+ NgbModule,
+ TranslateModule.forRoot(),
+ ],
+ declarations: [
+ OkrSearchHierarchyFilterComponent,
+ ],
+ providers: [
+ { provide: SearchService, useValue: searchService },
+ { provide: SearchFilterService, useValue: searchFilterService },
+ { provide: RemoteDataBuildService, useValue: {} },
+ { provide: Router, useValue: router },
+ { provide: NgbModal, useValue: ngbModal },
+ { provide: VocabularyService, useValue: vocabularyService },
+ { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() },
+ { provide: IN_PLACE_SEARCH, useValue: false },
+ { provide: FILTER_CONFIG, useValue: Object.assign(new SearchFilterConfig(), { name: testSearchFilter }) },
+ ],
+ schemas: [NO_ERRORS_SCHEMA],
+ }).compileComponents();
+ });
+
+ function init() {
+ fixture = TestBed.createComponent(OkrSearchHierarchyFilterComponent);
+ fixture.detectChanges();
+ showVocabularyTreeLink = fixture.debugElement.query(By.css('div#show-test-search-filter-tree'));
+ }
+
+ describe('if the vocabulary doesn\'t exist', () => {
+
+ beforeEach(() => {
+ spyOn(vocabularyService, 'searchTopEntries').and.returnValue(observableOf(new RemoteData(
+ undefined, 0, 0, RequestEntryState.Error, undefined, undefined, 404
+ )));
+ init();
+ });
+
+ it('should not show the vocabulary tree link', () => {
+ expect(showVocabularyTreeLink).toBeNull();
+ });
+ });
+
+ describe('if the vocabulary exists', () => {
+
+ beforeEach(() => {
+ spyOn(vocabularyService, 'searchTopEntries').and.returnValue(observableOf(new RemoteData(
+ undefined, 0, 0, RequestEntryState.Success, undefined, buildPaginatedList(new PageInfo(), []), 200
+ )));
+ init();
+ });
+
+ it('should show the vocabulary tree link', () => {
+ expect(showVocabularyTreeLink).toBeTruthy();
+ });
+
+ describe('when clicking the vocabulary tree link', () => {
+
+ beforeEach(async () => {
+ showVocabularyTreeLink.nativeElement.click();
+ });
+
+ it('should open the vocabulary tree modal', () => {
+ expect(ngbModal.open).toHaveBeenCalled();
+ });
+
+ describe('when selecting a value from the vocabulary tree', () => {
+
+ const alreadySelectedValues = [
+ 'already-selected-value-1',
+ 'already-selected-value-2',
+ ];
+ const newSelectedValue = 'new-selected-value';
+
+ beforeEach(() => {
+ fixture.componentInstance.selectedValues$ = observableOf(
+ alreadySelectedValues.map(value => Object.assign(new FacetValue(), { value }))
+ );
+ okrVocabularyTreeViewComponent.select.emit(Object.assign(new VocabularyEntryDetail(), {
+ value: newSelectedValue,
+ }));
+ });
+
+ it('should add a new search filter to the existing search filters', () => {
+ expect(router.navigate).toHaveBeenCalledWith([testSearchLink], {
+ queryParams: {
+ [`f.${testSearchFilter}`]: [
+ ...alreadySelectedValues,
+ newSelectedValue,
+ ].map((value => `${value},equals`)),
+ },
+ queryParamsHandling: 'merge',
+ });
+ });
+ });
+ });
+ });
+});
diff --git a/src/themes/okr/app/shared/search/search-filters/search-filter/okr-search-hierarchy-filter/okr-search-hierarchy-filter.component.ts b/src/themes/okr/app/shared/search/search-filters/search-filter/okr-search-hierarchy-filter/okr-search-hierarchy-filter.component.ts
new file mode 100644
index 0000000000..c637f576eb
--- /dev/null
+++ b/src/themes/okr/app/shared/search/search-filters/search-filter/okr-search-hierarchy-filter/okr-search-hierarchy-filter.component.ts
@@ -0,0 +1,106 @@
+import { Component, Inject } from '@angular/core';
+import { renderFacetFor } from 'src/app/shared/search/search-filters/search-filter/search-filter-type-decorator';
+import { FilterType } from '../../../../../../../../app/shared/search/filter-type.model';
+import { facetLoad } from '../../../../../../../../app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component';
+import { SearchHierarchyFilterComponent } from '../../../../../../../../app/shared/search/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { OkrVocabularyTreeviewComponent } from '../../../../okr-vocabulary-treeview/okr-vocabulary-treeview.component';
+import { VocabularyEntryDetail } from '../../../../../../../../app/core/submission/vocabularies/models/vocabulary-entry-detail.model';
+import { SearchService } from '../../../../../../../../app/core/shared/search/search.service';
+import {
+ FILTER_CONFIG,
+ IN_PLACE_SEARCH,
+ SearchFilterService
+} from '../../../../../../../../app/core/shared/search/search-filter.service';
+import { Router } from '@angular/router';
+import { RemoteDataBuildService } from '../../../../../../../../app/core/cache/builders/remote-data-build.service';
+import { SEARCH_CONFIG_SERVICE } from '../../../../../../../../app/my-dspace-page/my-dspace-page.component';
+import { SearchConfigurationService } from '../../../../../../../../app/core/shared/search/search-configuration.service';
+import { SearchFilterConfig } from '../../../../../../../../app/shared/search/search-filter-config.model';
+import { FacetValue } from '../../../../../../../../app/shared/search/facet-value.model';
+import { getFacetValueForType } from '../../../../../../../../app/shared/search/search.utils';
+import { filter, map, take } from 'rxjs/operators';
+import { VocabularyService } from '../../../../../../../../app/core/submission/vocabularies/vocabulary.service';
+import { Observable } from 'rxjs';
+import { PageInfo } from '../../../../../../../../app/core/shared/page-info.model';
+
+/**
+ * Component that represents a hierarchy facet for a specific filter configuration.
+ * Worldbank customization which features a link at the bottom to open a vocabulary popup,
+ */
+@Component({
+ selector: 'ds-okr-search-hierarchy-filter',
+ styleUrls: ['./okr-search-hierarchy-filter.component.scss'],
+ templateUrl: './okr-search-hierarchy-filter.component.html',
+ animations: [facetLoad]
+})
+@renderFacetFor(FilterType.hierarchy)
+export class OkrSearchHierarchyFilterComponent extends SearchHierarchyFilterComponent {
+
+ constructor(protected searchService: SearchService,
+ protected filterService: SearchFilterService,
+ protected rdbs: RemoteDataBuildService,
+ protected router: Router,
+ protected modalService: NgbModal,
+ protected vocabularyService: VocabularyService,
+ @Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService,
+ @Inject(IN_PLACE_SEARCH) public inPlaceSearch: boolean,
+ @Inject(FILTER_CONFIG) public filterConfig: SearchFilterConfig,
+ ) {
+ super(
+ searchService,
+ filterService,
+ rdbs,
+ router,
+ searchConfigService,
+ inPlaceSearch,
+ filterConfig,
+ );
+ }
+
+ vocabularyExists$: Observable;
+
+ ngOnInit() {
+ super.ngOnInit();
+ this.vocabularyExists$ = this.vocabularyService.searchTopEntries(
+ this.filterConfig.name, new PageInfo(), true, false,
+ ).pipe(
+ filter(rd => rd.hasCompleted),
+ take(1),
+ map(rd => {
+ return rd.hasSucceeded;
+ }),
+ );
+ }
+
+ /**
+ * Open the vocabulary tree modal popup.
+ * When an entry is selected, add the filter query to the search options.
+ */
+ showVocabularyTree() {
+ const modalRef: NgbModalRef = this.modalService.open(OkrVocabularyTreeviewComponent, {
+ size: 'lg',
+ windowClass: 'treeview'
+ });
+ modalRef.componentInstance.vocabularyOptions = {
+ name: this.filterConfig.name,
+ closed: true
+ };
+ modalRef.componentInstance.select.subscribe((detail: VocabularyEntryDetail) => {
+ this.selectedValues$
+ .pipe(take(1))
+ .subscribe((selectedValues) => {
+ this.router.navigate(
+ [this.searchService.getSearchLink()],
+ {
+ queryParams: {
+ [this.filterConfig.paramName]: [...selectedValues, {value: detail.value}]
+ .map((facetValue: FacetValue) => getFacetValueForType(facetValue, this.filterConfig)),
+ },
+ queryParamsHandling: 'merge',
+ },
+ );
+ });
+ });
+ }
+}
diff --git a/src/themes/okr/entry-components.ts b/src/themes/okr/entry-components.ts
new file mode 100644
index 0000000000..bfc93ad216
--- /dev/null
+++ b/src/themes/okr/entry-components.ts
@@ -0,0 +1,63 @@
+import { PublicationComponent } from './app/item-page/simple/item-types/publication/publication.component';
+import { ItemSearchResultListElementComponent } from './app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component';
+import { PersonSearchResultListElementComponent } from './app/entity-groups/research-entities/item-list-elements/search-result-list-elements/person/person-search-result-list-element.component';
+import { JournalSearchResultListElementComponent } from './app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component';
+import { JournalIssueSearchResultListElementComponent } from './app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component';
+import { JournalVolumeSearchResultListElementComponent } from './app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component';
+import { CitationsSectionComponent } from './app/item-page/field-components/citation/citations-section.component';
+import { CcIconsComponent } from './app/item-page/field-components/cc-icons/cc-icons.component';
+import { AltmetricDonutComponent } from './app/item-page/field-components/citation/altmetric-donut/altmetric-donut.component';
+import { ItemPageWbDateFieldComponent } from './app/item-page/field-components/specific-field/wb-date/item-page-wb-date-field.component';
+import { ItemPageWbGenericWithFallbackComponent } from './app/item-page/field-components/specific-field/wb-generic-with-fallback/item-page-wb-generic-with-fallback.component';
+import { ItemPageWbExternalContentComponent } from './app/item-page/field-components/specific-field/wb-external-content/item-page-wb-external-content.component';
+import { UntypedItemComponent } from './app/item-page/simple/item-types/untyped-item/untyped-item.component';
+import { JournalComponent } from './app/entity-groups/journal-entities/item-pages/journal/journal.component';
+import { JournalIssueComponent } from './app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component';
+import { JournalVolumeComponent } from './app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component';
+import { JournalVolumeGridElementComponent } from './app/entity-groups/journal-entities/item-grid-elements/journal-volume/journal-volume-grid-element.component';
+import { JournalVolumeSearchResultGridElementComponent } from './app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component';
+import { JournalIssueSearchResultGridElementComponent } from './app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component';
+import { JournalIssueGridElementComponent } from './app/entity-groups/journal-entities/item-grid-elements/journal-issue/journal-issue-grid-element.component';
+import { JournalVolumeSidebarSearchListElementComponent } from './app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal-volume/journal-volume-sidebar-search-list-element.component';
+import { JournalIssueSidebarSearchListElementComponent } from './app/entity-groups/journal-entities/item-list-elements/sidebar-search-list-elements/journal-issue/journal-issue-sidebar-search-list-element.component';
+import { JournalIssueListElementComponent } from './app/entity-groups/journal-entities/item-list-elements/journal-issue/journal-issue-list-element.component';
+import { JournalVolumeListElementComponent } from './app/entity-groups/journal-entities/item-list-elements/journal-volume/journal-volume-list-element.component';
+import { FeaturedPublicationsListElementComponent } from './app/featured-publications/featured-publications-list-element/featured-publications-list-element.component';
+import { ClaimedTaskActionsMarkDuplicateComponent } from './app/shared/mydspace-actions/claimed-task/mark-duplicate/claimed-task-actions-mark-duplicate.component';
+import { ClaimedTaskActionsReportProblemComponent } from './app/shared/mydspace-actions/claimed-task/report-problem/claimed-task-actions-report-problem.component';
+import { SingleStatletTableComponent } from './app/atmire-cua/statlets/shared/single-statlet/graph-types/single-statlet-table/single-statlet-table.component';
+import { OkrSearchHierarchyFilterComponent } from './app/shared/search/search-filters/search-filter/okr-search-hierarchy-filter/okr-search-hierarchy-filter.component';
+import { OkrVocabularyTreeviewComponent } from './app/shared/okr-vocabulary-treeview/okr-vocabulary-treeview.component';
+
+export const ENTRY_COMPONENTS = [
+ PublicationComponent,
+ ItemSearchResultListElementComponent,
+ PersonSearchResultListElementComponent,
+ JournalSearchResultListElementComponent,
+ JournalVolumeSearchResultListElementComponent,
+ JournalIssueSearchResultListElementComponent,
+ UntypedItemComponent,
+ AltmetricDonutComponent,
+ CitationsSectionComponent,
+ CcIconsComponent,
+ ItemPageWbDateFieldComponent,
+ ItemPageWbGenericWithFallbackComponent,
+ ItemPageWbExternalContentComponent,
+ JournalComponent,
+ JournalIssueComponent,
+ JournalVolumeComponent,
+ JournalVolumeGridElementComponent,
+ JournalVolumeSearchResultGridElementComponent,
+ JournalIssueSearchResultGridElementComponent,
+ JournalIssueGridElementComponent,
+ JournalVolumeSidebarSearchListElementComponent,
+ JournalIssueSidebarSearchListElementComponent,
+ JournalIssueListElementComponent,
+ JournalVolumeListElementComponent,
+ FeaturedPublicationsListElementComponent,
+ ClaimedTaskActionsMarkDuplicateComponent,
+ ClaimedTaskActionsReportProblemComponent,
+ SingleStatletTableComponent,
+ OkrSearchHierarchyFilterComponent,
+ OkrVocabularyTreeviewComponent,
+];