mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-18 15:33:04 +00:00
Merge pull request #1478 from 4Science/CST-4633-search-refactoring
MyDSpace Search component refactoring
This commit is contained in:
@@ -53,7 +53,7 @@ describe('Search Page', () => {
|
||||
|
||||
// Click to display grid view
|
||||
// TODO: These buttons should likely have an easier way to uniquely select
|
||||
cy.get('#search-sidebar-content > ds-view-mode-switch > .btn-group > [href="/search?spc.sf=score&spc.sd=DESC&view=grid"] > .fas').click();
|
||||
cy.get('#search-sidebar-content > ds-view-mode-switch > .btn-group > [href="/search?view=grid"] > .fas').click();
|
||||
|
||||
// <ds-search-page> tag must be loaded
|
||||
cy.get('ds-search-page').should('exist');
|
||||
|
@@ -9,13 +9,15 @@ import { GroupFormComponent } from './group-registry/group-form/group-form.compo
|
||||
import { MembersListComponent } from './group-registry/group-form/members-list/members-list.component';
|
||||
import { SubgroupsListComponent } from './group-registry/group-form/subgroup-list/subgroups-list.component';
|
||||
import { GroupsRegistryComponent } from './group-registry/groups-registry.component';
|
||||
import { FormModule } from '../shared/form/form.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
RouterModule,
|
||||
AccessControlRoutingModule
|
||||
AccessControlRoutingModule,
|
||||
FormModule
|
||||
],
|
||||
declarations: [
|
||||
EPeopleRegistryComponent,
|
||||
|
@@ -8,6 +8,7 @@ import { SharedModule } from '../../shared/shared.module';
|
||||
import { MetadataSchemaFormComponent } from './metadata-registry/metadata-schema-form/metadata-schema-form.component';
|
||||
import { MetadataFieldFormComponent } from './metadata-schema/metadata-field-form/metadata-field-form.component';
|
||||
import { BitstreamFormatsModule } from './bitstream-formats/bitstream-formats.module';
|
||||
import { FormModule } from '../../shared/form/form.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -15,7 +16,8 @@ import { BitstreamFormatsModule } from './bitstream-formats/bitstream-formats.mo
|
||||
SharedModule,
|
||||
RouterModule,
|
||||
BitstreamFormatsModule,
|
||||
AdminRegistriesRoutingModule
|
||||
AdminRegistriesRoutingModule,
|
||||
FormModule
|
||||
],
|
||||
declarations: [
|
||||
MetadataRegistryComponent,
|
||||
|
@@ -7,13 +7,15 @@ import { FormatFormComponent } from './format-form/format-form.component';
|
||||
import { EditBitstreamFormatComponent } from './edit-bitstream-format/edit-bitstream-format.component';
|
||||
import { BitstreamFormatsRoutingModule } from './bitstream-formats-routing.module';
|
||||
import { AddBitstreamFormatComponent } from './add-bitstream-format/add-bitstream-format.component';
|
||||
import { FormModule } from '../../../shared/form/form.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
RouterModule,
|
||||
BitstreamFormatsRoutingModule
|
||||
BitstreamFormatsRoutingModule,
|
||||
FormModule
|
||||
],
|
||||
declarations: [
|
||||
BitstreamFormatsComponent,
|
||||
|
@@ -10,6 +10,7 @@ import { CollectionAdminSearchResultGridElementComponent } from './admin-search-
|
||||
import { ItemAdminSearchResultActionsComponent } from './admin-search-results/item-admin-search-result-actions.component';
|
||||
import { JournalEntitiesModule } from '../../entity-groups/journal-entities/journal-entities.module';
|
||||
import { ResearchEntitiesModule } from '../../entity-groups/research-entities/research-entities.module';
|
||||
import { SearchModule } from '../../shared/search/search.module';
|
||||
|
||||
const ENTRY_COMPONENTS = [
|
||||
// put only entry components that use custom decorator
|
||||
@@ -24,6 +25,7 @@ const ENTRY_COMPONENTS = [
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
SearchModule,
|
||||
SharedModule.withEntryComponents(),
|
||||
JournalEntitiesModule.withEntryComponents(),
|
||||
ResearchEntitiesModule.withEntryComponents()
|
||||
|
@@ -5,6 +5,7 @@ import { WorkflowItemSearchResultAdminWorkflowGridElementComponent } from './adm
|
||||
import { WorkflowItemAdminWorkflowActionsComponent } from './admin-workflow-search-results/workflow-item-admin-workflow-actions.component';
|
||||
import { WorkflowItemSearchResultAdminWorkflowListElementComponent } from './admin-workflow-search-results/admin-workflow-search-result-list-element/workflow-item/workflow-item-search-result-admin-workflow-list-element.component';
|
||||
import { AdminWorkflowPageComponent } from './admin-workflow-page.component';
|
||||
import { SearchModule } from '../../shared/search/search.module';
|
||||
|
||||
const ENTRY_COMPONENTS = [
|
||||
// put only entry components that use custom decorator
|
||||
@@ -14,6 +15,7 @@ const ENTRY_COMPONENTS = [
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
SearchModule,
|
||||
SharedModule.withEntryComponents()
|
||||
],
|
||||
declarations: [
|
||||
|
@@ -24,7 +24,7 @@ const ENTRY_COMPONENTS = [
|
||||
AccessControlModule,
|
||||
AdminSearchModule.withEntryComponents(),
|
||||
AdminWorkflowModuleModule.withEntryComponents(),
|
||||
SharedModule,
|
||||
SharedModule
|
||||
],
|
||||
declarations: [
|
||||
AdminCurationTasksComponent,
|
||||
|
@@ -4,6 +4,8 @@ import { SharedModule } from '../shared/shared.module';
|
||||
import { EditBitstreamPageComponent } from './edit-bitstream-page/edit-bitstream-page.component';
|
||||
import { BitstreamPageRoutingModule } from './bitstream-page-routing.module';
|
||||
import { BitstreamAuthorizationsComponent } from './bitstream-authorizations/bitstream-authorizations.component';
|
||||
import { FormModule } from '../shared/form/form.module';
|
||||
import { ResourcePoliciesModule } from '../shared/resource-policies/resource-policies.module';
|
||||
|
||||
/**
|
||||
* This module handles all components that are necessary for Bitstream related pages
|
||||
@@ -12,7 +14,9 @@ import { BitstreamAuthorizationsComponent } from './bitstream-authorizations/bit
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
BitstreamPageRoutingModule
|
||||
BitstreamPageRoutingModule,
|
||||
FormModule,
|
||||
ResourcePoliciesModule
|
||||
],
|
||||
declarations: [
|
||||
BitstreamAuthorizationsComponent,
|
||||
|
@@ -6,6 +6,7 @@ import { BrowseByMetadataPageComponent } from './browse-by-metadata-page/browse-
|
||||
import { BrowseByDatePageComponent } from './browse-by-date-page/browse-by-date-page.component';
|
||||
import { BrowseBySwitcherComponent } from './browse-by-switcher/browse-by-switcher.component';
|
||||
import { ThemedBrowseBySwitcherComponent } from './browse-by-switcher/themed-browse-by-switcher.component';
|
||||
import { ComcolModule } from '../shared/comcol/comcol.module';
|
||||
|
||||
const ENTRY_COMPONENTS = [
|
||||
// put only entry components that use custom decorator
|
||||
@@ -17,6 +18,7 @@ const ENTRY_COMPONENTS = [
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
ComcolModule,
|
||||
SharedModule
|
||||
],
|
||||
declarations: [
|
||||
|
@@ -10,7 +10,7 @@ import {
|
||||
} from '@ng-dynamic-forms/core';
|
||||
|
||||
import { Collection } from '../../core/shared/collection.model';
|
||||
import { ComColFormComponent } from '../../shared/comcol-forms/comcol-form/comcol-form.component';
|
||||
import { ComColFormComponent } from '../../shared/comcol/comcol-forms/comcol-form/comcol-form.component';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||
import { AuthService } from '../../core/auth/auth.service';
|
||||
@@ -28,8 +28,8 @@ import { NONE_ENTITY_TYPE } from '../../core/shared/item-relationships/item-type
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-collection-form',
|
||||
styleUrls: ['../../shared/comcol-forms/comcol-form/comcol-form.component.scss'],
|
||||
templateUrl: '../../shared/comcol-forms/comcol-form/comcol-form.component.html'
|
||||
styleUrls: ['../../shared/comcol/comcol-forms/comcol-form/comcol-form.component.scss'],
|
||||
templateUrl: '../../shared/comcol/comcol-forms/comcol-form/comcol-form.component.html'
|
||||
})
|
||||
export class CollectionFormComponent extends ComColFormComponent<Collection> implements OnInit {
|
||||
/**
|
||||
|
@@ -2,9 +2,13 @@ import { NgModule } from '@angular/core';
|
||||
|
||||
import { CollectionFormComponent } from './collection-form.component';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
import { ComcolModule } from '../../shared/comcol/comcol.module';
|
||||
import { FormModule } from '../../shared/form/form.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
ComcolModule,
|
||||
FormModule,
|
||||
SharedModule
|
||||
],
|
||||
declarations: [
|
||||
|
@@ -33,7 +33,7 @@ import { ErrorComponent } from '../../shared/error/error.component';
|
||||
import { LoadingComponent } from '../../shared/loading/loading.component';
|
||||
import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service';
|
||||
import { SearchService } from '../../core/shared/search/search.service';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model';
|
||||
import {
|
||||
createFailedRemoteDataObject$,
|
||||
createSuccessfulRemoteDataObject,
|
||||
|
@@ -9,10 +9,11 @@ import { Collection } from '../../core/shared/collection.model';
|
||||
import { PaginatedList } from '../../core/data/paginated-list.model';
|
||||
import { map, startWith, switchMap, take } from 'rxjs/operators';
|
||||
import {
|
||||
getRemoteDataPayload,
|
||||
getAllSucceededRemoteData,
|
||||
getFirstCompletedRemoteData,
|
||||
getFirstSucceededRemoteData,
|
||||
toDSpaceObjectListRD,
|
||||
getFirstCompletedRemoteData, getAllSucceededRemoteData
|
||||
getRemoteDataPayload,
|
||||
toDSpaceObjectListRD
|
||||
} from '../../core/shared/operators';
|
||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||
import { DSpaceObjectType } from '../../core/shared/dspace-object-type.model';
|
||||
@@ -24,7 +25,7 @@ import { CollectionDataService } from '../../core/data/collection-data.service';
|
||||
import { isNotEmpty } from '../../shared/empty.util';
|
||||
import { SEARCH_CONFIG_SERVICE } from '../../my-dspace-page/my-dspace-page.component';
|
||||
import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model';
|
||||
import { SearchService } from '../../core/shared/search/search.service';
|
||||
import { followLink } from '../../shared/utils/follow-link-config.model';
|
||||
import { NoContent } from '../../core/shared/NoContent.model';
|
||||
|
@@ -1,13 +1,8 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import {
|
||||
BehaviorSubject,
|
||||
combineLatest as observableCombineLatest,
|
||||
Observable,
|
||||
Subject
|
||||
} from 'rxjs';
|
||||
import { BehaviorSubject, combineLatest as observableCombineLatest, Observable, Subject } from 'rxjs';
|
||||
import { filter, map, mergeMap, startWith, switchMap, take } from 'rxjs/operators';
|
||||
import { PaginatedSearchOptions } from '../shared/search/paginated-search-options.model';
|
||||
import { PaginatedSearchOptions } from '../shared/search/models/paginated-search-options.model';
|
||||
import { SearchService } from '../core/shared/search/search.service';
|
||||
import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model';
|
||||
import { CollectionDataService } from '../core/data/collection-data.service';
|
||||
|
@@ -14,6 +14,7 @@ import { SearchService } from '../core/shared/search/search.service';
|
||||
import { StatisticsModule } from '../statistics/statistics.module';
|
||||
import { CollectionFormModule } from './collection-form/collection-form.module';
|
||||
import { ThemedCollectionPageComponent } from './themed-collection-page.component';
|
||||
import { ComcolModule } from '../shared/comcol/comcol.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -22,7 +23,8 @@ import { ThemedCollectionPageComponent } from './themed-collection-page.componen
|
||||
CollectionPageRoutingModule,
|
||||
StatisticsModule.forRoot(),
|
||||
EditItemPageModule,
|
||||
CollectionFormModule
|
||||
CollectionFormModule,
|
||||
ComcolModule
|
||||
],
|
||||
declarations: [
|
||||
CollectionPageComponent,
|
||||
|
@@ -2,12 +2,12 @@ import { Component } from '@angular/core';
|
||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||
import { RouteService } from '../../core/services/route.service';
|
||||
import { Router } from '@angular/router';
|
||||
import { CreateComColPageComponent } from '../../shared/comcol-forms/create-comcol-page/create-comcol-page.component';
|
||||
import { CreateComColPageComponent } from '../../shared/comcol/comcol-forms/create-comcol-page/create-comcol-page.component';
|
||||
import { Collection } from '../../core/shared/collection.model';
|
||||
import { CollectionDataService } from '../../core/data/collection-data.service';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {RequestService} from '../../core/data/request.service';
|
||||
import { RequestService } from '../../core/data/request.service';
|
||||
|
||||
/**
|
||||
* Component that represents the page where a user can create a new Collection
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { DeleteComColPageComponent } from '../../shared/comcol-forms/delete-comcol-page/delete-comcol-page.component';
|
||||
import { DeleteComColPageComponent } from '../../shared/comcol/comcol-forms/delete-comcol-page/delete-comcol-page.component';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { CollectionDataService } from '../../core/data/collection-data.service';
|
||||
import { Collection } from '../../core/shared/collection.model';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {RequestService} from '../../core/data/request.service';
|
||||
import { RequestService } from '../../core/data/request.service';
|
||||
|
||||
/**
|
||||
* Component that represents the page where a user can delete an existing Collection
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ComcolMetadataComponent } from '../../../shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component';
|
||||
import { ComcolMetadataComponent } from '../../../shared/comcol/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component';
|
||||
import { Collection } from '../../../core/shared/collection.model';
|
||||
import { CollectionDataService } from '../../../core/data/collection-data.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
@@ -12,6 +12,7 @@ import { RequestService } from '../../../core/data/request.service';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { ComcolModule } from '../../../shared/comcol/comcol.module';
|
||||
|
||||
describe('CollectionRolesComponent', () => {
|
||||
|
||||
@@ -65,6 +66,7 @@ describe('CollectionRolesComponent', () => {
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
ComcolModule,
|
||||
SharedModule,
|
||||
RouterTestingModule.withRoutes([]),
|
||||
TranslateModule.forRoot(),
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { EditComColPageComponent } from '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component';
|
||||
import { EditComColPageComponent } from '../../shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component';
|
||||
import { Collection } from '../../core/shared/collection.model';
|
||||
import { getCollectionPageRoute } from '../collection-page-routing-paths';
|
||||
|
||||
@@ -9,7 +9,7 @@ import { getCollectionPageRoute } from '../collection-page-routing-paths';
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-edit-collection',
|
||||
templateUrl: '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html'
|
||||
templateUrl: '../../shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.html'
|
||||
})
|
||||
export class EditCollectionPageComponent extends EditComColPageComponent<Collection> {
|
||||
type = 'collection';
|
||||
|
@@ -10,6 +10,9 @@ import { CollectionSourceComponent } from './collection-source/collection-source
|
||||
import { CollectionAuthorizationsComponent } from './collection-authorizations/collection-authorizations.component';
|
||||
import { CollectionFormModule } from '../collection-form/collection-form.module';
|
||||
import { CollectionSourceControlsComponent } from './collection-source/collection-source-controls/collection-source-controls.component';
|
||||
import { ResourcePoliciesModule } from '../../shared/resource-policies/resource-policies.module';
|
||||
import { FormModule } from '../../shared/form/form.module';
|
||||
import { ComcolModule } from '../../shared/comcol/comcol.module';
|
||||
|
||||
/**
|
||||
* Module that contains all components related to the Edit Collection page administrator functionality
|
||||
@@ -19,7 +22,10 @@ import { CollectionSourceControlsComponent } from './collection-source/collectio
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
EditCollectionPageRoutingModule,
|
||||
CollectionFormModule
|
||||
CollectionFormModule,
|
||||
ResourcePoliciesModule,
|
||||
FormModule,
|
||||
ComcolModule
|
||||
],
|
||||
declarations: [
|
||||
EditCollectionPageComponent,
|
||||
|
@@ -6,7 +6,7 @@ import {
|
||||
DynamicTextAreaModel
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { Community } from '../../core/shared/community.model';
|
||||
import { ComColFormComponent } from '../../shared/comcol-forms/comcol-form/comcol-form.component';
|
||||
import { ComColFormComponent } from '../../shared/comcol/comcol-forms/comcol-form/comcol-form.component';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||
@@ -19,8 +19,8 @@ import { ObjectCacheService } from '../../core/cache/object-cache.service';
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-community-form',
|
||||
styleUrls: ['../../shared/comcol-forms/comcol-form/comcol-form.component.scss'],
|
||||
templateUrl: '../../shared/comcol-forms/comcol-form/comcol-form.component.html'
|
||||
styleUrls: ['../../shared/comcol/comcol-forms/comcol-form/comcol-form.component.scss'],
|
||||
templateUrl: '../../shared/comcol/comcol-forms/comcol-form/comcol-form.component.html'
|
||||
})
|
||||
export class CommunityFormComponent extends ComColFormComponent<Community> {
|
||||
/**
|
||||
|
@@ -2,9 +2,13 @@ import { NgModule } from '@angular/core';
|
||||
|
||||
import { CommunityFormComponent } from './community-form.component';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
import { ComcolModule } from '../../shared/comcol/comcol.module';
|
||||
import { FormModule } from '../../shared/form/form.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
ComcolModule,
|
||||
FormModule,
|
||||
SharedModule
|
||||
],
|
||||
declarations: [
|
||||
|
@@ -12,6 +12,7 @@ import { DeleteCommunityPageComponent } from './delete-community-page/delete-com
|
||||
import { StatisticsModule } from '../statistics/statistics.module';
|
||||
import { CommunityFormModule } from './community-form/community-form.module';
|
||||
import { ThemedCommunityPageComponent } from './themed-community-page.component';
|
||||
import { ComcolModule } from '../shared/comcol/comcol.module';
|
||||
|
||||
const DECLARATIONS = [CommunityPageComponent,
|
||||
ThemedCommunityPageComponent,
|
||||
@@ -26,7 +27,8 @@ const DECLARATIONS = [CommunityPageComponent,
|
||||
SharedModule,
|
||||
CommunityPageRoutingModule,
|
||||
StatisticsModule.forRoot(),
|
||||
CommunityFormModule
|
||||
CommunityFormModule,
|
||||
ComcolModule
|
||||
],
|
||||
declarations: [
|
||||
...DECLARATIONS
|
||||
|
@@ -3,7 +3,7 @@ import { Community } from '../../core/shared/community.model';
|
||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||
import { RouteService } from '../../core/services/route.service';
|
||||
import { Router } from '@angular/router';
|
||||
import { CreateComColPageComponent } from '../../shared/comcol-forms/create-comcol-page/create-comcol-page.component';
|
||||
import { CreateComColPageComponent } from '../../shared/comcol/comcol-forms/create-comcol-page/create-comcol-page.component';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { RequestService } from '../../core/data/request.service';
|
||||
|
@@ -2,10 +2,10 @@ import { Component } from '@angular/core';
|
||||
import { Community } from '../../core/shared/community.model';
|
||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { DeleteComColPageComponent } from '../../shared/comcol-forms/delete-comcol-page/delete-comcol-page.component';
|
||||
import { DeleteComColPageComponent } from '../../shared/comcol/comcol-forms/delete-comcol-page/delete-comcol-page.component';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {RequestService} from '../../core/data/request.service';
|
||||
import { RequestService } from '../../core/data/request.service';
|
||||
|
||||
/**
|
||||
* Component that represents the page where a user can delete an existing Community
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ComcolMetadataComponent } from '../../../shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component';
|
||||
import { ComcolMetadataComponent } from '../../../shared/comcol/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Community } from '../../../core/shared/community.model';
|
||||
import { CommunityDataService } from '../../../core/data/community-data.service';
|
||||
|
@@ -12,6 +12,7 @@ import { SharedModule } from '../../../shared/shared.module';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { ComcolModule } from '../../../shared/comcol/comcol.module';
|
||||
|
||||
describe('CommunityRolesComponent', () => {
|
||||
|
||||
@@ -50,6 +51,7 @@ describe('CommunityRolesComponent', () => {
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
ComcolModule,
|
||||
SharedModule,
|
||||
RouterTestingModule.withRoutes([]),
|
||||
TranslateModule.forRoot(),
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Community } from '../../core/shared/community.model';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { EditComColPageComponent } from '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component';
|
||||
import { EditComColPageComponent } from '../../shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component';
|
||||
import { getCommunityPageRoute } from '../community-page-routing-paths';
|
||||
|
||||
/**
|
||||
@@ -9,7 +9,7 @@ import { getCommunityPageRoute } from '../community-page-routing-paths';
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-edit-community',
|
||||
templateUrl: '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html'
|
||||
templateUrl: '../../shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.html'
|
||||
})
|
||||
export class EditCommunityPageComponent extends EditComColPageComponent<Community> {
|
||||
type = 'community';
|
||||
|
@@ -8,6 +8,8 @@ import { CommunityMetadataComponent } from './community-metadata/community-metad
|
||||
import { CommunityRolesComponent } from './community-roles/community-roles.component';
|
||||
import { CommunityAuthorizationsComponent } from './community-authorizations/community-authorizations.component';
|
||||
import { CommunityFormModule } from '../community-form/community-form.module';
|
||||
import { ResourcePoliciesModule } from '../../shared/resource-policies/resource-policies.module';
|
||||
import { ComcolModule } from '../../shared/comcol/comcol.module';
|
||||
|
||||
/**
|
||||
* Module that contains all components related to the Edit Community page administrator functionality
|
||||
@@ -17,7 +19,9 @@ import { CommunityFormModule } from '../community-form/community-form.module';
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
EditCommunityPageRoutingModule,
|
||||
CommunityFormModule
|
||||
CommunityFormModule,
|
||||
ComcolModule,
|
||||
ResourcePoliciesModule
|
||||
],
|
||||
declarations: [
|
||||
EditCommunityPageComponent,
|
||||
|
@@ -20,7 +20,7 @@ import { PaginatedList } from './paginated-list.model';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { FindListOptions, GetRequest } from './request.models';
|
||||
import { RequestService } from './request.service';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model';
|
||||
import { Bitstream } from '../shared/bitstream.model';
|
||||
import { RequestEntryState } from './request.reducer';
|
||||
|
||||
|
@@ -12,7 +12,7 @@ import { HttpClient } from '@angular/common/http';
|
||||
import { FindListOptions } from './request.models';
|
||||
import { Observable } from 'rxjs';
|
||||
import { distinctUntilChanged, map, switchMap, take } from 'rxjs/operators';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model';
|
||||
import { hasValue, isNotEmptyOperator } from '../../shared/empty.util';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { PaginatedList } from './paginated-list.model';
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { SearchFilterConfig } from '../../shared/search/search-filter-config.model';
|
||||
import { SearchFilterConfig } from '../../shared/search/models/search-filter-config.model';
|
||||
import { ParsedResponse } from '../cache/response.models';
|
||||
import { RawRestResponse } from '../dspace-rest/raw-rest-response.model';
|
||||
import { DSpaceSerializer } from '../dspace-rest/dspace.serializer';
|
||||
import { RestRequest } from './request.models';
|
||||
import { DspaceRestResponseParsingService } from './dspace-rest-response-parsing.service';
|
||||
import { FacetConfigResponse } from '../../shared/search/facet-config-response.model';
|
||||
import { FacetConfigResponse } from '../../shared/search/models/facet-config-response.model';
|
||||
|
||||
@Injectable()
|
||||
export class FacetConfigResponseParsingService extends DspaceRestResponseParsingService {
|
||||
|
@@ -1,10 +1,10 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { FacetValue } from '../../shared/search/facet-value.model';
|
||||
import { FacetValue } from '../../shared/search/models/facet-value.model';
|
||||
import { ParsedResponse } from '../cache/response.models';
|
||||
import { RawRestResponse } from '../dspace-rest/raw-rest-response.model';
|
||||
import { DSpaceSerializer } from '../dspace-rest/dspace.serializer';
|
||||
import { RestRequest } from './request.models';
|
||||
import { FacetValues } from '../../shared/search/facet-values.model';
|
||||
import { FacetValues } from '../../shared/search/models/facet-values.model';
|
||||
import { DspaceRestResponseParsingService } from './dspace-rest-response-parsing.service';
|
||||
|
||||
@Injectable()
|
||||
|
@@ -25,7 +25,7 @@ import { PaginatedList } from './paginated-list.model';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { DeleteRequest, FindListOptions, GetRequest, PostRequest, PutRequest, RestRequest } from './request.models';
|
||||
import { RequestService } from './request.service';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model';
|
||||
import { Bundle } from '../shared/bundle.model';
|
||||
import { MetadataMap } from '../shared/metadata.models';
|
||||
import { BundleDataService } from './bundle-data.service';
|
||||
|
@@ -5,9 +5,9 @@ import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.util
|
||||
import { createPaginatedList } from '../../shared/testing/utils.test';
|
||||
import { buildPaginatedList } from './paginated-list.model';
|
||||
import { PageInfo } from '../shared/page-info.model';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model';
|
||||
import { RelationshipOptions } from '../../shared/form/builder/models/relationship-options.model';
|
||||
import { SearchResult } from '../../shared/search/search-result.model';
|
||||
import { SearchResult } from '../../shared/search/models/search-result.model';
|
||||
import { Item } from '../shared/item.model';
|
||||
import { skip, take } from 'rxjs/operators';
|
||||
import { ExternalSource } from '../shared/external-source.model';
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import { ExternalSourceService } from './external-source.service';
|
||||
import { SearchService } from '../shared/search/search.service';
|
||||
import { concat, distinctUntilChanged, map, multicast, startWith, take, takeWhile } from 'rxjs/operators';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model';
|
||||
import { Observable, ReplaySubject } from 'rxjs';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { PaginatedList } from './paginated-list.model';
|
||||
import { SearchResult } from '../../shared/search/search-result.model';
|
||||
import { SearchResult } from '../../shared/search/models/search-result.model';
|
||||
import { DSpaceObject } from '../shared/dspace-object.model';
|
||||
import { RelationshipOptions } from '../../shared/form/builder/models/relationship-options.model';
|
||||
import { Item } from '../shared/item.model';
|
||||
|
@@ -4,7 +4,7 @@ import { DSpaceSerializer } from '../dspace-rest/dspace.serializer';
|
||||
import { RestRequest } from './request.models';
|
||||
import { RawRestResponse } from '../dspace-rest/raw-rest-response.model';
|
||||
import { hasValue } from '../../shared/empty.util';
|
||||
import { SearchObjects } from '../../shared/search/search-objects.model';
|
||||
import { SearchObjects } from '../../shared/search/models/search-objects.model';
|
||||
import { MetadataMap, MetadataValue } from '../shared/metadata.models';
|
||||
import { DspaceRestResponseParsingService } from './dspace-rest-response-parsing.service';
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { hasValue } from '../../shared/empty.util';
|
||||
import { SearchObjects } from '../../shared/search/search-objects.model';
|
||||
import { SearchObjects } from '../../shared/search/models/search-objects.model';
|
||||
import { ParsedResponse } from '../cache/response.models';
|
||||
import { RawRestResponse } from '../dspace-rest/raw-rest-response.model';
|
||||
import { DSpaceSerializer } from '../dspace-rest/dspace.serializer';
|
||||
|
@@ -12,7 +12,7 @@ import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { FindListOptions, PostRequest, RestRequest } from './request.models';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { PaginatedList } from './paginated-list.model';
|
||||
import { Version } from '../shared/version.model';
|
||||
|
@@ -13,7 +13,7 @@ import {
|
||||
withLatestFrom
|
||||
} from 'rxjs/operators';
|
||||
import { hasNoValue, hasValue, hasValueOperator, isNotEmpty } from '../../shared/empty.util';
|
||||
import { SearchResult } from '../../shared/search/search-result.model';
|
||||
import { SearchResult } from '../../shared/search/models/search-result.model';
|
||||
import { PaginatedList } from '../data/paginated-list.model';
|
||||
import { RemoteData } from '../data/remote-data';
|
||||
import { RestRequest } from '../data/request.models';
|
||||
|
@@ -2,8 +2,8 @@ import { SearchConfigurationService } from './search-configuration.service';
|
||||
import { ActivatedRouteStub } from '../../../shared/testing/active-router.stub';
|
||||
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
|
||||
import { SortDirection, SortOptions } from '../../cache/models/sort-options.model';
|
||||
import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model';
|
||||
import { SearchFilter } from '../../../shared/search/search-filter.model';
|
||||
import { PaginatedSearchOptions } from '../../../shared/search/models/paginated-search-options.model';
|
||||
import { SearchFilter } from '../../../shared/search/models/search-filter.model';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub';
|
||||
|
||||
|
@@ -3,30 +3,25 @@ import { ActivatedRoute, Params } from '@angular/router';
|
||||
|
||||
import {
|
||||
BehaviorSubject,
|
||||
combineLatest,
|
||||
combineLatest as observableCombineLatest,
|
||||
merge as observableMerge,
|
||||
Observable,
|
||||
Subscription
|
||||
} from 'rxjs';
|
||||
import { distinctUntilChanged, filter, map, startWith, switchMap, take } from 'rxjs/operators';
|
||||
import { filter, map, startWith } from 'rxjs/operators';
|
||||
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
|
||||
import { SearchOptions } from '../../../shared/search/search-options.model';
|
||||
import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model';
|
||||
import { SearchFilter } from '../../../shared/search/search-filter.model';
|
||||
import { SearchOptions } from '../../../shared/search/models/search-options.model';
|
||||
import { PaginatedSearchOptions } from '../../../shared/search/models/paginated-search-options.model';
|
||||
import { SearchFilter } from '../../../shared/search/models/search-filter.model';
|
||||
import { RemoteData } from '../../data/remote-data';
|
||||
import { DSpaceObjectType } from '../dspace-object-type.model';
|
||||
import { SortDirection, SortOptions } from '../../cache/models/sort-options.model';
|
||||
import { RouteService } from '../../services/route.service';
|
||||
import {
|
||||
getAllSucceededRemoteDataPayload,
|
||||
getFirstSucceededRemoteData
|
||||
} from '../operators';
|
||||
import { getAllSucceededRemoteDataPayload, getFirstSucceededRemoteData } from '../operators';
|
||||
import { hasNoValue, hasValue, isNotEmpty, isNotEmptyOperator } from '../../../shared/empty.util';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
|
||||
import { SearchConfig } from './search-filters/search-config.model';
|
||||
import { SearchConfig, SortConfig } from './search-filters/search-config.model';
|
||||
import { SearchService } from './search.service';
|
||||
import { of } from 'rxjs';
|
||||
import { PaginationService } from '../../pagination/pagination.service';
|
||||
|
||||
/**
|
||||
@@ -35,7 +30,21 @@ import { PaginationService } from '../../pagination/pagination.service';
|
||||
@Injectable()
|
||||
export class SearchConfigurationService implements OnDestroy {
|
||||
|
||||
/**
|
||||
* Default pagination id
|
||||
*/
|
||||
public paginationID = 'spc';
|
||||
|
||||
/**
|
||||
* Emits the current search options
|
||||
*/
|
||||
public searchOptions: BehaviorSubject<SearchOptions>;
|
||||
|
||||
/**
|
||||
* Emits the current search options including pagination and sort
|
||||
*/
|
||||
public paginatedSearchOptions: BehaviorSubject<PaginatedSearchOptions>;
|
||||
|
||||
/**
|
||||
* Default pagination settings
|
||||
*/
|
||||
@@ -45,16 +54,6 @@ export class SearchConfigurationService implements OnDestroy {
|
||||
currentPage: 1
|
||||
});
|
||||
|
||||
/**
|
||||
* Default sort settings
|
||||
*/
|
||||
protected defaultSort = new SortOptions('score', SortDirection.DESC);
|
||||
|
||||
/**
|
||||
* Default configuration parameter setting
|
||||
*/
|
||||
protected defaultConfiguration;
|
||||
|
||||
/**
|
||||
* Default scope setting
|
||||
*/
|
||||
@@ -71,23 +70,14 @@ export class SearchConfigurationService implements OnDestroy {
|
||||
protected _defaults: Observable<RemoteData<PaginatedSearchOptions>>;
|
||||
|
||||
/**
|
||||
* Emits the current search options
|
||||
* A map of subscriptions to unsubscribe from on destroy
|
||||
*/
|
||||
public searchOptions: BehaviorSubject<SearchOptions>;
|
||||
|
||||
/**
|
||||
* Emits the current search options including pagination and sort
|
||||
*/
|
||||
public paginatedSearchOptions: BehaviorSubject<PaginatedSearchOptions>;
|
||||
|
||||
/**
|
||||
* List of subscriptions to unsubscribe from on destroy
|
||||
*/
|
||||
protected subs: Subscription[] = [];
|
||||
protected subs: Map<string, Subscription[]> = new Map<string, Subscription[]>(null);
|
||||
|
||||
/**
|
||||
* Initialize the search options
|
||||
* @param {RouteService} routeService
|
||||
* @param {PaginationService} paginationService
|
||||
* @param {ActivatedRoute} route
|
||||
*/
|
||||
constructor(protected routeService: RouteService,
|
||||
@@ -98,29 +88,28 @@ export class SearchConfigurationService implements OnDestroy {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the search options
|
||||
* Default values for the Search Options
|
||||
*/
|
||||
protected initDefaults() {
|
||||
this.defaults
|
||||
.pipe(getFirstSucceededRemoteData())
|
||||
.subscribe((defRD: RemoteData<PaginatedSearchOptions>) => {
|
||||
const defs = defRD.payload;
|
||||
this.paginatedSearchOptions = new BehaviorSubject<PaginatedSearchOptions>(defs);
|
||||
this.searchOptions = new BehaviorSubject<SearchOptions>(defs);
|
||||
this.subs.push(this.subscribeToSearchOptions(defs));
|
||||
this.subs.push(this.subscribeToPaginatedSearchOptions(defs.pagination.id, defs));
|
||||
get defaults(): Observable<RemoteData<PaginatedSearchOptions>> {
|
||||
if (hasNoValue(this._defaults)) {
|
||||
const options = new PaginatedSearchOptions({
|
||||
pagination: this.defaultPagination,
|
||||
scope: this.defaultScope,
|
||||
query: this.defaultQuery
|
||||
});
|
||||
this._defaults = createSuccessfulRemoteDataObject$(options, new Date().getTime());
|
||||
}
|
||||
);
|
||||
return this._defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Observable<string>} Emits the current configuration string
|
||||
*/
|
||||
getCurrentConfiguration(defaultConfiguration: string) {
|
||||
return observableCombineLatest(
|
||||
return observableCombineLatest([
|
||||
this.routeService.getQueryParameterValue('configuration').pipe(startWith(undefined)),
|
||||
this.routeService.getRouteParameterValue('configuration').pipe(startWith(undefined))
|
||||
).pipe(
|
||||
]).pipe(
|
||||
map(([queryConfig, routeConfig]) => {
|
||||
return queryConfig || routeConfig || defaultConfiguration;
|
||||
})
|
||||
@@ -208,59 +197,82 @@ export class SearchConfigurationService implements OnDestroy {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an observable of SearchConfig every time the configuration$ stream emits.
|
||||
* @param configuration$
|
||||
* @param service
|
||||
* Creates an observable of SearchConfig every time the configuration stream emits.
|
||||
* @param configuration The search configuration
|
||||
* @param service The search service to use
|
||||
* @param scope The search scope if exists
|
||||
*/
|
||||
getConfigurationSearchConfigObservable(configuration$: Observable<string>, service: SearchService): Observable<SearchConfig> {
|
||||
return configuration$.pipe(
|
||||
distinctUntilChanged(),
|
||||
switchMap((configuration) => service.getSearchConfigurationFor(null, configuration)),
|
||||
getAllSucceededRemoteDataPayload());
|
||||
getConfigurationSearchConfig(configuration: string, service: SearchService, scope?: string): Observable<SearchConfig> {
|
||||
return service.getSearchConfigurationFor(scope, configuration).pipe(
|
||||
getAllSucceededRemoteDataPayload()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Every time searchConfig change (after a configuration change) it update the navigation with the default sort option
|
||||
* and emit the new paginateSearchOptions value.
|
||||
* @param configuration$
|
||||
* @param service
|
||||
* Return the SortOptions list available for the given SearchConfig
|
||||
* @param searchConfig The SearchConfig object
|
||||
*/
|
||||
initializeSortOptionsFromConfiguration(searchConfig$: Observable<SearchConfig>) {
|
||||
const subscription = searchConfig$.pipe(switchMap((searchConfig) => combineLatest([
|
||||
of(searchConfig),
|
||||
this.paginatedSearchOptions.pipe(take(1))
|
||||
]))).subscribe(([searchConfig, searchOptions]) => {
|
||||
const field = searchConfig.sortOptions[0].name;
|
||||
const direction = searchConfig.sortOptions[0].sortOrder.toLowerCase() === SortDirection.ASC.toLowerCase() ? SortDirection.ASC : SortDirection.DESC;
|
||||
const updateValue = Object.assign(new PaginatedSearchOptions({}), searchOptions, {
|
||||
sort: new SortOptions(field, direction)
|
||||
});
|
||||
this.paginationService.updateRoute(this.paginationID,
|
||||
{
|
||||
sortDirection: updateValue.sort.direction,
|
||||
sortField: updateValue.sort.field,
|
||||
});
|
||||
this.paginatedSearchOptions.next(updateValue);
|
||||
});
|
||||
this.subs.push(subscription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an observable of available SortOptions[] every time the searchConfig$ stream emits.
|
||||
* @param searchConfig$
|
||||
* @param service
|
||||
*/
|
||||
getConfigurationSortOptionsObservable(searchConfig$: Observable<SearchConfig>): Observable<SortOptions[]> {
|
||||
return searchConfig$.pipe(map((searchConfig) => {
|
||||
const sortOptions = [];
|
||||
searchConfig.sortOptions.forEach(sortOption => {
|
||||
sortOptions.push(new SortOptions(sortOption.name, SortDirection.ASC));
|
||||
sortOptions.push(new SortOptions(sortOption.name, SortDirection.DESC));
|
||||
});
|
||||
return sortOptions;
|
||||
getConfigurationSortOptions(searchConfig: SearchConfig): SortOptions[] {
|
||||
return searchConfig.sortOptions.map((entry: SortConfig) => ({
|
||||
field: entry.name,
|
||||
direction: entry.sortOrder.toLowerCase() === SortDirection.ASC.toLowerCase() ? SortDirection.ASC : SortDirection.DESC
|
||||
}));
|
||||
}
|
||||
|
||||
setPaginationId(paginationId): void {
|
||||
if (isNotEmpty(paginationId)) {
|
||||
const currentValue: PaginatedSearchOptions = this.paginatedSearchOptions.getValue();
|
||||
const updatedValue: PaginatedSearchOptions = Object.assign(new PaginatedSearchOptions({}), currentValue, {
|
||||
pagination: Object.assign({}, currentValue.pagination, {
|
||||
id: paginationId
|
||||
})
|
||||
});
|
||||
// unsubscribe from subscription related to old pagination id
|
||||
this.unsubscribeFromSearchOptions(this.paginationID);
|
||||
|
||||
// change to the new pagination id
|
||||
this.paginationID = paginationId;
|
||||
this.paginatedSearchOptions.next(updatedValue);
|
||||
this.setSearchSubscription(this.paginationID, this.paginatedSearchOptions.value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure to unsubscribe from all existing subscription to prevent memory leaks
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.subs
|
||||
.forEach((subs: Subscription[]) => subs
|
||||
.filter((sub) => hasValue(sub))
|
||||
.forEach((sub) => sub.unsubscribe())
|
||||
);
|
||||
|
||||
this.subs = new Map<string, Subscription[]>(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the search options
|
||||
*/
|
||||
protected initDefaults() {
|
||||
this.defaults
|
||||
.pipe(getFirstSucceededRemoteData())
|
||||
.subscribe((defRD: RemoteData<PaginatedSearchOptions>) => {
|
||||
const defs = defRD.payload;
|
||||
this.paginatedSearchOptions = new BehaviorSubject<PaginatedSearchOptions>(defs);
|
||||
this.searchOptions = new BehaviorSubject<SearchOptions>(defs);
|
||||
this.setSearchSubscription(this.paginationID, defs);
|
||||
});
|
||||
}
|
||||
|
||||
private setSearchSubscription(paginationID: string, defaults: PaginatedSearchOptions) {
|
||||
this.unsubscribeFromSearchOptions(paginationID);
|
||||
const subs = [
|
||||
this.subscribeToSearchOptions(defaults),
|
||||
this.subscribeToPaginatedSearchOptions(paginationID || defaults.pagination.id, defaults)
|
||||
];
|
||||
this.subs.set(this.paginationID, subs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a subscription to all necessary parameters to make sure the searchOptions emits a new value every time they update
|
||||
* @param {SearchOptions} defaults Default values for when no parameters are available
|
||||
@@ -283,14 +295,15 @@ export class SearchConfigurationService implements OnDestroy {
|
||||
|
||||
/**
|
||||
* Sets up a subscription to all necessary parameters to make sure the paginatedSearchOptions emits a new value every time they update
|
||||
* @param {string} paginationId The pagination ID
|
||||
* @param {PaginatedSearchOptions} defaults Default values for when no parameters are available
|
||||
* @returns {Subscription} The subscription to unsubscribe from
|
||||
*/
|
||||
private subscribeToPaginatedSearchOptions(paginationId: string, defaults: PaginatedSearchOptions): Subscription {
|
||||
return observableMerge(
|
||||
this.getConfigurationPart(defaults.configuration),
|
||||
this.getPaginationPart(paginationId, defaults.pagination),
|
||||
this.getSortPart(paginationId, defaults.sort),
|
||||
this.getConfigurationPart(defaults.configuration),
|
||||
this.getScopePart(defaults.scope),
|
||||
this.getQueryPart(defaults.query),
|
||||
this.getDSOTypePart(),
|
||||
@@ -304,30 +317,16 @@ export class SearchConfigurationService implements OnDestroy {
|
||||
}
|
||||
|
||||
/**
|
||||
* Default values for the Search Options
|
||||
* Unsubscribe from all subscriptions related to the given paginationID
|
||||
* @param paginationId The pagination id
|
||||
*/
|
||||
get defaults(): Observable<RemoteData<PaginatedSearchOptions>> {
|
||||
if (hasNoValue(this._defaults)) {
|
||||
const options = new PaginatedSearchOptions({
|
||||
pagination: this.defaultPagination,
|
||||
configuration: this.defaultConfiguration,
|
||||
sort: this.defaultSort,
|
||||
scope: this.defaultScope,
|
||||
query: this.defaultQuery
|
||||
});
|
||||
this._defaults = createSuccessfulRemoteDataObject$(options, new Date().getTime());
|
||||
private unsubscribeFromSearchOptions(paginationId: string): void {
|
||||
if (this.subs.has(this.paginationID)) {
|
||||
this.subs.get(this.paginationID)
|
||||
.filter((sub) => hasValue(sub))
|
||||
.forEach((sub) => sub.unsubscribe());
|
||||
this.subs.delete(paginationId);
|
||||
}
|
||||
return this._defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure to unsubscribe from all existing subscription to prevent memory leaks
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.subs.forEach((sub) => {
|
||||
sub.unsubscribe();
|
||||
});
|
||||
this.subs = [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -10,8 +10,8 @@ import {
|
||||
SearchFilterToggleAction
|
||||
} from '../../../shared/search/search-filters/search-filter/search-filter.actions';
|
||||
import { SearchFiltersState } from '../../../shared/search/search-filters/search-filter/search-filter.reducer';
|
||||
import { SearchFilterConfig } from '../../../shared/search/search-filter-config.model';
|
||||
import { FilterType } from '../../../shared/search/filter-type.model';
|
||||
import { SearchFilterConfig } from '../../../shared/search/models/search-filter-config.model';
|
||||
import { FilterType } from '../../../shared/search/models/filter-type.model';
|
||||
import { ActivatedRouteStub } from '../../../shared/testing/active-router.stub';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { SortDirection, SortOptions } from '../../cache/models/sort-options.model';
|
||||
|
@@ -16,7 +16,7 @@ import {
|
||||
SearchFilterToggleAction
|
||||
} from '../../../shared/search/search-filters/search-filter/search-filter.actions';
|
||||
import { hasValue, isNotEmpty, } from '../../../shared/empty.util';
|
||||
import { SearchFilterConfig } from '../../../shared/search/search-filter-config.model';
|
||||
import { SearchFilterConfig } from '../../../shared/search/models/search-filter-config.model';
|
||||
import { SortDirection, SortOptions } from '../../cache/models/sort-options.model';
|
||||
import { RouteService } from '../../services/route.service';
|
||||
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
|
||||
|
@@ -29,7 +29,7 @@ export class SearchConfig implements CacheableObject {
|
||||
* The configured sort options.
|
||||
*/
|
||||
@autoserialize
|
||||
sortOptions: SortOption[];
|
||||
sortOptions: SortConfig[];
|
||||
|
||||
/**
|
||||
* The object type.
|
||||
@@ -63,7 +63,7 @@ export interface FilterConfig {
|
||||
/**
|
||||
* Interface to model sort option's configuration.
|
||||
*/
|
||||
export interface SortOption {
|
||||
export interface SortConfig {
|
||||
name: string;
|
||||
sortOrder: string;
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@ import { ActivatedRouteStub } from '../../../shared/testing/active-router.stub';
|
||||
import { RouterStub } from '../../../shared/testing/router.stub';
|
||||
import { HALEndpointService } from '../hal-endpoint.service';
|
||||
import { combineLatest as observableCombineLatest, Observable, of as observableOf } from 'rxjs';
|
||||
import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model';
|
||||
import { PaginatedSearchOptions } from '../../../shared/search/models/paginated-search-options.model';
|
||||
import { RemoteData } from '../../data/remote-data';
|
||||
import { RequestEntry } from '../../data/request.reducer';
|
||||
import { getMockRequestService } from '../../../shared/mocks/request.service.mock';
|
||||
@@ -21,11 +21,8 @@ import { RouteService } from '../../services/route.service';
|
||||
import { routeServiceStub } from '../../../shared/testing/route-service.stub';
|
||||
import { RemoteDataBuildService } from '../../cache/builders/remote-data-build.service';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
|
||||
import { SearchObjects } from '../../../shared/search/search-objects.model';
|
||||
import { SearchObjects } from '../../../shared/search/models/search-objects.model';
|
||||
import { PaginationService } from '../../pagination/pagination.service';
|
||||
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
|
||||
import { SortDirection, SortOptions } from '../../cache/models/sort-options.model';
|
||||
import { FindListOptions } from '../../data/request.models';
|
||||
import { SearchConfigurationService } from './search-configuration.service';
|
||||
import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub';
|
||||
|
||||
|
@@ -14,24 +14,24 @@ import { GenericConstructor } from '../generic-constructor';
|
||||
import { HALEndpointService } from '../hal-endpoint.service';
|
||||
import { URLCombiner } from '../../url-combiner/url-combiner';
|
||||
import { hasValue, hasValueOperator, isNotEmpty } from '../../../shared/empty.util';
|
||||
import { SearchOptions } from '../../../shared/search/search-options.model';
|
||||
import { SearchFilterConfig } from '../../../shared/search/search-filter-config.model';
|
||||
import { SearchOptions } from '../../../shared/search/models/search-options.model';
|
||||
import { SearchFilterConfig } from '../../../shared/search/models/search-filter-config.model';
|
||||
import { SearchResponseParsingService } from '../../data/search-response-parsing.service';
|
||||
import { SearchObjects } from '../../../shared/search/search-objects.model';
|
||||
import { SearchObjects } from '../../../shared/search/models/search-objects.model';
|
||||
import { FacetValueResponseParsingService } from '../../data/facet-value-response-parsing.service';
|
||||
import { FacetConfigResponseParsingService } from '../../data/facet-config-response-parsing.service';
|
||||
import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model';
|
||||
import { PaginatedSearchOptions } from '../../../shared/search/models/paginated-search-options.model';
|
||||
import { CommunityDataService } from '../../data/community-data.service';
|
||||
import { ViewMode } from '../view-mode.model';
|
||||
import { DSpaceObjectDataService } from '../../data/dspace-object-data.service';
|
||||
import { RemoteDataBuildService } from '../../cache/builders/remote-data-build.service';
|
||||
import { getFirstCompletedRemoteData, getRemoteDataPayload } from '../operators';
|
||||
import { RouteService } from '../../services/route.service';
|
||||
import { SearchResult } from '../../../shared/search/search-result.model';
|
||||
import { SearchResult } from '../../../shared/search/models/search-result.model';
|
||||
import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model';
|
||||
import { getSearchResultFor } from '../../../shared/search/search-result-element-decorator';
|
||||
import { FacetConfigResponse } from '../../../shared/search/facet-config-response.model';
|
||||
import { FacetValues } from '../../../shared/search/facet-values.model';
|
||||
import { FacetConfigResponse } from '../../../shared/search/models/facet-config-response.model';
|
||||
import { FacetValues } from '../../../shared/search/models/facet-values.model';
|
||||
import { SearchConfig } from './search-filters/search-config.model';
|
||||
import { PaginationService } from '../../pagination/pagination.service';
|
||||
import { SearchConfigurationService } from './search-configuration.service';
|
||||
@@ -407,6 +407,7 @@ export class SearchService implements OnDestroy {
|
||||
/**
|
||||
* Changes the current view mode in the current URL
|
||||
* @param {ViewMode} viewMode Mode to switch to
|
||||
* @param {string[]} searchLinkParts
|
||||
*/
|
||||
setViewMode(viewMode: ViewMode, searchLinkParts?: string[]) {
|
||||
this.paginationService.getCurrentPagination(this.searchConfigurationService.paginationID, new PaginationComponentOptions()).pipe(take(1))
|
||||
|
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
|
||||
export enum ViewMode {
|
||||
ListElement = 'listElement',
|
||||
GridElement = 'gridElement',
|
||||
DetailedListElement = 'detailedListElement',
|
||||
StandalonePage = 'standalonePage',
|
||||
ListElement = 'list',
|
||||
GridElement = 'grid',
|
||||
DetailedListElement = 'detailed',
|
||||
StandalonePage = 'standalone',
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@ import { JournalVolumeSearchResultGridElementComponent } from './item-grid-eleme
|
||||
import { JournalVolumeSidebarSearchListElementComponent } from './item-list-elements/sidebar-search-list-elements/journal-volume/journal-volume-sidebar-search-list-element.component';
|
||||
import { JournalIssueSidebarSearchListElementComponent } from './item-list-elements/sidebar-search-list-elements/journal-issue/journal-issue-sidebar-search-list-element.component';
|
||||
import { JournalSidebarSearchListElementComponent } from './item-list-elements/sidebar-search-list-elements/journal/journal-sidebar-search-list-element.component';
|
||||
import { ItemSharedModule } from '../../item-page/item-shared.module';
|
||||
|
||||
const ENTRY_COMPONENTS = [
|
||||
// put only entry components that use custom decorator
|
||||
@@ -45,6 +46,7 @@ const ENTRY_COMPONENTS = [
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
ItemSharedModule,
|
||||
SharedModule
|
||||
],
|
||||
declarations: [
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
import { OrgUnitComponent } from './item-pages/org-unit/org-unit.component';
|
||||
import { PersonComponent } from './item-pages/person/person.component';
|
||||
@@ -27,6 +28,7 @@ import { ExternalSourceEntryListSubmissionElementComponent } from './submission/
|
||||
import { OrgUnitSidebarSearchListElementComponent } from './item-list-elements/sidebar-search-list-elements/org-unit/org-unit-sidebar-search-list-element.component';
|
||||
import { PersonSidebarSearchListElementComponent } from './item-list-elements/sidebar-search-list-elements/person/person-sidebar-search-list-element.component';
|
||||
import { ProjectSidebarSearchListElementComponent } from './item-list-elements/sidebar-search-list-elements/project/project-sidebar-search-list-element.component';
|
||||
import { ItemSharedModule } from '../../item-page/item-shared.module';
|
||||
|
||||
const ENTRY_COMPONENTS = [
|
||||
// put only entry components that use custom decorator
|
||||
@@ -65,7 +67,9 @@ const COMPONENTS = [
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedModule
|
||||
ItemSharedModule,
|
||||
SharedModule,
|
||||
NgbTooltipModule
|
||||
],
|
||||
declarations: [
|
||||
...COMPONENTS,
|
||||
@@ -79,7 +83,7 @@ export class ResearchEntitiesModule {
|
||||
static withEntryComponents() {
|
||||
return {
|
||||
ngModule: ResearchEntitiesModule,
|
||||
providers: ENTRY_COMPONENTS.map((component) => ({provide: component}))
|
||||
providers: ENTRY_COMPONENTS.map((component) => ({ provide: component }))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,8 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
import { EditItemPageRoutingModule } from './edit-item-page.routing.module';
|
||||
import { EditItemPageComponent } from './edit-item-page.component';
|
||||
@@ -31,6 +34,8 @@ import { VirtualMetadataComponent } from './virtual-metadata/virtual-metadata.co
|
||||
import { ItemVersionHistoryComponent } from './item-version-history/item-version-history.component';
|
||||
import { ItemAuthorizationsComponent } from './item-authorizations/item-authorizations.component';
|
||||
import { ObjectValuesPipe } from '../../shared/utils/object-values-pipe';
|
||||
import { ResourcePoliciesModule } from '../../shared/resource-policies/resource-policies.module';
|
||||
|
||||
|
||||
/**
|
||||
* Module that contains all components related to the Edit Item page administrator functionality
|
||||
@@ -39,9 +44,11 @@ import { ObjectValuesPipe } from '../../shared/utils/object-values-pipe';
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
NgbTooltipModule,
|
||||
EditItemPageRoutingModule,
|
||||
SearchPageModule,
|
||||
DragDropModule
|
||||
DragDropModule,
|
||||
ResourcePoliciesModule
|
||||
],
|
||||
declarations: [
|
||||
EditItemPageComponent,
|
||||
|
@@ -15,14 +15,11 @@ import { getFirstSucceededRemoteData, getRemoteDataPayload } from '../../../core
|
||||
import { RemoteData } from '../../../core/data/remote-data';
|
||||
import { PaginatedList } from '../../../core/data/paginated-list.model';
|
||||
import { Bundle } from '../../../core/shared/bundle.model';
|
||||
import {
|
||||
FieldUpdate,
|
||||
FieldUpdates
|
||||
} from '../../../core/data/object-updates/object-updates.reducer';
|
||||
import { FieldUpdate, FieldUpdates } from '../../../core/data/object-updates/object-updates.reducer';
|
||||
import { Bitstream } from '../../../core/shared/bitstream.model';
|
||||
import { FieldChangeType } from '../../../core/data/object-updates/object-updates.actions';
|
||||
import { BundleDataService } from '../../../core/data/bundle-data.service';
|
||||
import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model';
|
||||
import { PaginatedSearchOptions } from '../../../shared/search/models/paginated-search-options.model';
|
||||
import { ResponsiveColumnSizes } from '../../../shared/responsive-table-sizes/responsive-column-sizes';
|
||||
import { ResponsiveTableSizes } from '../../../shared/responsive-table-sizes/responsive-table-sizes';
|
||||
import { NoContent } from '../../../core/shared/NoContent.model';
|
||||
|
@@ -5,7 +5,7 @@ import { Bitstream } from '../../../../../core/shared/bitstream.model';
|
||||
import { ObjectUpdatesService } from '../../../../../core/data/object-updates/object-updates.service';
|
||||
import { BundleDataService } from '../../../../../core/data/bundle-data.service';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
import { PaginatedSearchOptions } from '../../../../../shared/search/paginated-search-options.model';
|
||||
import { PaginatedSearchOptions } from '../../../../../shared/search/models/paginated-search-options.model';
|
||||
import { ResponsiveTableSizes } from '../../../../../shared/responsive-table-sizes/responsive-table-sizes';
|
||||
import { followLink } from '../../../../../shared/utils/follow-link-config.model';
|
||||
import { ObjectValuesPipe } from '../../../../../shared/utils/object-values-pipe';
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { EventEmitter } from '@angular/core';
|
||||
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
@@ -25,7 +25,7 @@ import { ObjectSelectService } from '../../../shared/object-select/object-select
|
||||
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
|
||||
import { PaginationComponent } from '../../../shared/pagination/pagination.component';
|
||||
import { SearchFormComponent } from '../../../shared/search-form/search-form.component';
|
||||
import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model';
|
||||
import { PaginatedSearchOptions } from '../../../shared/search/models/paginated-search-options.model';
|
||||
import { HostWindowServiceStub } from '../../../shared/testing/host-window-service.stub';
|
||||
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
|
||||
import { ObjectSelectServiceStub } from '../../../shared/testing/object-select-service.stub';
|
||||
|
@@ -9,11 +9,12 @@ import { PaginatedList } from '../../../core/data/paginated-list.model';
|
||||
import { Collection } from '../../../core/shared/collection.model';
|
||||
import { Item } from '../../../core/shared/item.model';
|
||||
import {
|
||||
getAllSucceededRemoteData,
|
||||
getFirstCompletedRemoteData,
|
||||
getFirstSucceededRemoteData,
|
||||
getFirstSucceededRemoteDataPayload,
|
||||
getRemoteDataPayload,
|
||||
getFirstSucceededRemoteData,
|
||||
toDSpaceObjectListRD,
|
||||
getAllSucceededRemoteData, getFirstCompletedRemoteData
|
||||
toDSpaceObjectListRD
|
||||
} from '../../../core/shared/operators';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { filter, map, startWith, switchMap, take } from 'rxjs/operators';
|
||||
@@ -22,7 +23,7 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { DSpaceObjectType } from '../../../core/shared/dspace-object-type.model';
|
||||
import { hasValue, isNotEmpty } from '../../../shared/empty.util';
|
||||
import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model';
|
||||
import { PaginatedSearchOptions } from '../../../shared/search/models/paginated-search-options.model';
|
||||
import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service';
|
||||
import { SearchService } from '../../../core/shared/search/search.service';
|
||||
import { NoContent } from '../../../core/shared/NoContent.model';
|
||||
|
@@ -3,7 +3,13 @@ import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { LinkService } from '../../../../core/cache/builders/link.service';
|
||||
import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions';
|
||||
import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service';
|
||||
import { combineLatest as observableCombineLatest, from as observableFrom, BehaviorSubject, Observable, Subscription } from 'rxjs';
|
||||
import {
|
||||
BehaviorSubject,
|
||||
combineLatest as observableCombineLatest,
|
||||
from as observableFrom,
|
||||
Observable,
|
||||
Subscription
|
||||
} from 'rxjs';
|
||||
import {
|
||||
FieldUpdate,
|
||||
FieldUpdates,
|
||||
@@ -25,7 +31,7 @@ import { ItemType } from '../../../../core/shared/item-relationships/item-type.m
|
||||
import { DsDynamicLookupRelationModalComponent } from '../../../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component';
|
||||
import { RelationshipOptions } from '../../../../shared/form/builder/models/relationship-options.model';
|
||||
import { SelectableListService } from '../../../../shared/object-list/selectable-list/selectable-list.service';
|
||||
import { SearchResult } from '../../../../shared/search/search-result.model';
|
||||
import { SearchResult } from '../../../../shared/search/models/search-result.model';
|
||||
import { followLink } from '../../../../shared/utils/follow-link-config.model';
|
||||
import { PaginatedList } from '../../../../core/data/paginated-list.model';
|
||||
import { RemoteData } from '../../../../core/data/remote-data';
|
||||
|
36
src/app/item-page/item-shared.module.ts
Normal file
36
src/app/item-page/item-shared.module.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { RelatedEntitiesSearchComponent } from './simple/related-entities/related-entities-search/related-entities-search.component';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SearchModule } from '../shared/search/search.module';
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { DYNAMIC_FORM_CONTROL_MAP_FN } from '@ng-dynamic-forms/core';
|
||||
import { dsDynamicFormControlMapFn } from '../shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component';
|
||||
import { TabbedRelatedEntitiesSearchComponent } from './simple/related-entities/tabbed-related-entities-search/tabbed-related-entities-search.component';
|
||||
|
||||
const COMPONENTS = [
|
||||
RelatedEntitiesSearchComponent,
|
||||
TabbedRelatedEntitiesSearchComponent
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
...COMPONENTS
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SearchModule,
|
||||
SharedModule,
|
||||
TranslateModule
|
||||
],
|
||||
exports: [
|
||||
...COMPONENTS
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: DYNAMIC_FORM_CONTROL_MAP_FN,
|
||||
useValue: dsDynamicFormControlMapFn
|
||||
}
|
||||
]
|
||||
})
|
||||
export class ItemSharedModule { }
|
@@ -1,7 +1,6 @@
|
||||
<ds-configuration-search-page
|
||||
[fixedFilterQuery]="fixedFilter"
|
||||
[configuration]="configuration"
|
||||
[configuration$]="configuration$"
|
||||
[searchEnabled]="searchEnabled"
|
||||
[sideBarWidth]="sideBarWidth">
|
||||
</ds-configuration-search-page>
|
||||
|
@@ -38,10 +38,4 @@ describe('RelatedEntitiesSearchComponent', () => {
|
||||
expect(comp.fixedFilter).toEqual(mockFilter);
|
||||
});
|
||||
|
||||
it('should create a configuration$', () => {
|
||||
comp.configuration$.subscribe((configuration) => {
|
||||
expect(configuration).toEqual(mockConfiguration);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { Item } from '../../../../core/shared/item.model';
|
||||
import { isNotEmpty } from '../../../../shared/empty.util';
|
||||
import { getFilterByRelation } from '../../../../shared/utils/relation-query.utils';
|
||||
@@ -10,7 +9,7 @@ import { getFilterByRelation } from '../../../../shared/utils/relation-query.uti
|
||||
})
|
||||
/**
|
||||
* A component to show related items as search results.
|
||||
* Related items can be facetted, or queried using an
|
||||
* Related items can be faceted, or queried using an
|
||||
* optional search box.
|
||||
*/
|
||||
export class RelatedEntitiesSearchComponent implements OnInit {
|
||||
@@ -44,15 +43,11 @@ export class RelatedEntitiesSearchComponent implements OnInit {
|
||||
@Input() sideBarWidth = 4;
|
||||
|
||||
fixedFilter: string;
|
||||
configuration$: Observable<string>;
|
||||
|
||||
ngOnInit(): void {
|
||||
if (isNotEmpty(this.relationType) && isNotEmpty(this.item)) {
|
||||
this.fixedFilter = getFilterByRelation(this.relationType, this.item.id);
|
||||
}
|
||||
if (isNotEmpty(this.configuration)) {
|
||||
this.configuration$ = of(this.configuration);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,16 +1,16 @@
|
||||
import { of as observableOf } from 'rxjs';
|
||||
|
||||
import { MyDSpaceConfigurationService } from './my-dspace-configuration.service';
|
||||
import { PaginatedSearchOptions } from '../shared/search/paginated-search-options.model';
|
||||
import { PaginatedSearchOptions } from '../shared/search/models/paginated-search-options.model';
|
||||
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
|
||||
import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model';
|
||||
import { SearchFilter } from '../shared/search/search-filter.model';
|
||||
import { SearchFilter } from '../shared/search/models/search-filter.model';
|
||||
import { ActivatedRouteStub } from '../shared/testing/active-router.stub';
|
||||
import { RoleServiceMock } from '../shared/mocks/role-service.mock';
|
||||
import { cold, hot } from 'jasmine-marbles';
|
||||
import { MyDSpaceConfigurationValueType } from './my-dspace-configuration-value-type';
|
||||
import { PaginationServiceStub } from '../shared/testing/pagination-service.stub';
|
||||
import { PaginationService } from '../core/pagination/pagination.service';
|
||||
import { Context } from '../core/shared/context.model';
|
||||
|
||||
describe('MyDSpaceConfigurationService', () => {
|
||||
let service: MyDSpaceConfigurationService;
|
||||
@@ -242,11 +242,13 @@ describe('MyDSpaceConfigurationService', () => {
|
||||
b: [
|
||||
{
|
||||
value: MyDSpaceConfigurationValueType.Workspace,
|
||||
label: `mydspace.show.${MyDSpaceConfigurationValueType.Workspace}`
|
||||
label: `mydspace.show.${MyDSpaceConfigurationValueType.Workspace}`,
|
||||
context: Context.Workspace
|
||||
},
|
||||
{
|
||||
value: MyDSpaceConfigurationValueType.Workflow,
|
||||
label: `mydspace.show.${MyDSpaceConfigurationValueType.Workflow}`
|
||||
label: `mydspace.show.${MyDSpaceConfigurationValueType.Workflow}`,
|
||||
context: Context.Workflow
|
||||
}
|
||||
]
|
||||
}));
|
||||
|
@@ -12,6 +12,13 @@ import { PaginationComponentOptions } from '../shared/pagination/pagination-comp
|
||||
import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model';
|
||||
import { RouteService } from '../core/services/route.service';
|
||||
import { PaginationService } from '../core/pagination/pagination.service';
|
||||
import { Context } from '../core/shared/context.model';
|
||||
|
||||
export const MyDSpaceConfigurationToContextMap = new Map([
|
||||
[MyDSpaceConfigurationValueType.Workspace, Context.Workspace],
|
||||
[MyDSpaceConfigurationValueType.Workflow, Context.Workflow]
|
||||
]);
|
||||
|
||||
|
||||
/**
|
||||
* Service that performs all actions that have to do with the current mydspace configuration
|
||||
@@ -110,7 +117,8 @@ export class MyDSpaceConfigurationService extends SearchConfigurationService {
|
||||
availableConfigurationTypes.forEach((type) => {
|
||||
const value = type;
|
||||
const label = `mydspace.show.${value}`;
|
||||
configurationOptions.push({ value, label });
|
||||
const context = MyDSpaceConfigurationToContextMap.get(type);
|
||||
configurationOptions.push({ value, label, context });
|
||||
});
|
||||
return configurationOptions;
|
||||
})
|
||||
|
@@ -13,7 +13,7 @@ import { UploaderOptions } from '../../shared/uploader/uploader-options.model';
|
||||
import { HALEndpointService } from '../../core/shared/hal-endpoint.service';
|
||||
import { NotificationType } from '../../shared/notifications/models/notification-type';
|
||||
import { hasValue } from '../../shared/empty.util';
|
||||
import { SearchResult } from '../../shared/search/search-result.model';
|
||||
import { SearchResult } from '../../shared/search/models/search-result.model';
|
||||
import { CollectionSelectorComponent } from '../collection-selector/collection-selector.component';
|
||||
import { UploaderComponent } from '../../shared/uploader/uploader.component';
|
||||
import { UploaderError } from '../../shared/uploader/uploader-error.model';
|
||||
|
@@ -1,56 +1,10 @@
|
||||
<div class="container">
|
||||
<ds-my-dspace-new-submission *dsShowOnlyForRole="[roleTypeEnum.Submitter]"></ds-my-dspace-new-submission>
|
||||
<div class="search-page row">
|
||||
<ds-search-sidebar *ngIf="!(isXsOrSm$ | async)" class="col-3 sidebar-md-sticky"
|
||||
id="search-sidebar"
|
||||
[configurationList]="(configurationList$ | async)"
|
||||
[resultCount]="(resultsRD$ | async)?.payload?.totalElements"
|
||||
[viewModeList]="viewModeList"
|
||||
[searchOptions]="(searchOptions$ | async)"
|
||||
[sortOptions]="(sortOptions$ | async)"
|
||||
[refreshFilters]="refreshFilters.asObservable()"
|
||||
[inPlaceSearch]="inPlaceSearch"></ds-search-sidebar>
|
||||
<div class="col-12 col-md-9">
|
||||
<ds-search-form id="search-form"
|
||||
[query]="(searchOptions$ | async)?.query"
|
||||
[scope]="(searchOptions$ | async)?.scope"
|
||||
[currentUrl]="getSearchLink()"
|
||||
[showScopeSelector]="true"
|
||||
[inPlaceSearch]="inPlaceSearch"
|
||||
[searchPlaceholder]="'mydspace.search-form.placeholder' | translate">
|
||||
</ds-search-form>
|
||||
<ds-search-labels [inPlaceSearch]="inPlaceSearch"></ds-search-labels>
|
||||
<div class="row">
|
||||
<div id="search-body"
|
||||
class="row-offcanvas row-offcanvas-left w-100"
|
||||
[@pushInOut]="(isSidebarCollapsed() | async) ? 'collapsed' : 'expanded'">
|
||||
<ds-search-sidebar *ngIf="(isXsOrSm$ | async)" class="col-12"
|
||||
id="search-sidebar-sm"
|
||||
[configurationList]="(configurationList$ | async)"
|
||||
[resultCount]="(resultsRD$ | async)?.payload?.totalElements"
|
||||
(toggleSidebar)="closeSidebar()"
|
||||
[ngClass]="{'active': !(isSidebarCollapsed() | async)}"
|
||||
[searchOptions]="(searchOptions$ | async)"
|
||||
[sortOptions]="(sortOptions$ | async)"
|
||||
[refreshFilters]="refreshFilters.asObservable()"
|
||||
[inPlaceSearch]="inPlaceSearch">
|
||||
</ds-search-sidebar>
|
||||
<div id="search-content" class="col-12">
|
||||
<div class="d-block d-md-none search-controls clearfix">
|
||||
<ds-view-mode-switch [viewModeList]="viewModeList" [inPlaceSearch]="inPlaceSearch"></ds-view-mode-switch>
|
||||
<button (click)="openSidebar()" aria-controls="#search-body"
|
||||
class="btn btn-outline-primary float-right open-sidebar"><i
|
||||
class="fas fa-sliders"></i> {{"search.sidebar.open"
|
||||
| translate}}
|
||||
</button>
|
||||
</div>
|
||||
<ds-my-dspace-results [searchResults]="resultsRD$ | async"
|
||||
[searchConfig]="searchOptions$ | async"
|
||||
[context]="context$ | async"
|
||||
(contentChange)="onResultsContentChange()"></ds-my-dspace-results>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ds-search *ngIf="configuration && context"
|
||||
[configuration]="configuration"
|
||||
[configurationList]="(configurationList$ | async)"
|
||||
[context]="context"
|
||||
[viewModeList]="viewModeList"
|
||||
></ds-search>
|
||||
|
@@ -1 +1 @@
|
||||
@import '../search-page/search.component.scss';
|
||||
@import '../shared/search/search.component';
|
||||
|
@@ -1,213 +1,88 @@
|
||||
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { ComponentFixture, fakeAsync, flush, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { cold } from 'jasmine-marbles';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
|
||||
import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model';
|
||||
import { CommunityDataService } from '../core/data/community-data.service';
|
||||
import { HostWindowService } from '../shared/host-window.service';
|
||||
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
|
||||
import { MyDSpacePageComponent, SEARCH_CONFIG_SERVICE } from './my-dspace-page.component';
|
||||
import { RouteService } from '../core/services/route.service';
|
||||
import { routeServiceStub } from '../shared/testing/route-service.stub';
|
||||
import { SearchConfigurationServiceStub } from '../shared/testing/search-configuration-service.stub';
|
||||
import { SearchService } from '../core/shared/search/search.service';
|
||||
import { SearchConfigurationService } from '../core/shared/search/search-configuration.service';
|
||||
import { PaginatedSearchOptions } from '../shared/search/paginated-search-options.model';
|
||||
import { SidebarService } from '../shared/sidebar/sidebar.service';
|
||||
import { SearchFilterService } from '../core/shared/search/search-filter.service';
|
||||
import { RoleDirective } from '../shared/roles/role.directive';
|
||||
import { RoleService } from '../core/roles/role.service';
|
||||
import { RoleServiceMock } from '../shared/mocks/role-service.mock';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils';
|
||||
import { SidebarServiceStub } from '../shared/testing/sidebar-service.stub';
|
||||
import { MyDSpaceConfigurationService } from './my-dspace-configuration.service';
|
||||
import { MyDSpaceConfigurationValueType } from './my-dspace-configuration-value-type';
|
||||
import { Context } from '../core/shared/context.model';
|
||||
import SpyObj = jasmine.SpyObj;
|
||||
|
||||
describe('MyDSpacePageComponent', () => {
|
||||
let comp: MyDSpacePageComponent;
|
||||
let fixture: ComponentFixture<MyDSpacePageComponent>;
|
||||
let searchServiceObject: SearchService;
|
||||
let searchConfigurationServiceObject: SearchConfigurationService;
|
||||
const store: Store<MyDSpacePageComponent> = jasmine.createSpyObj('store', {
|
||||
/* tslint:disable:no-empty */
|
||||
dispatch: {},
|
||||
/* tslint:enable:no-empty */
|
||||
select: observableOf(true)
|
||||
|
||||
const searchServiceStub: SpyObj<SearchService> = jasmine.createSpyObj('SearchService', {
|
||||
setServiceOptions: jasmine.createSpy('setServiceOptions')
|
||||
});
|
||||
const pagination: PaginationComponentOptions = new PaginationComponentOptions();
|
||||
pagination.id = 'mydspace-results-pagination';
|
||||
pagination.currentPage = 1;
|
||||
pagination.pageSize = 10;
|
||||
const sortOption = { name: 'score', sortOrder: 'DESC', metadata: null };
|
||||
const sort: SortOptions = new SortOptions('score', SortDirection.DESC);
|
||||
const mockResults = createSuccessfulRemoteDataObject$(['test', 'data']);
|
||||
const searchServiceStub = jasmine.createSpyObj('SearchService', {
|
||||
search: mockResults,
|
||||
getEndpoint: observableOf('discover/search/objects'),
|
||||
getSearchLink: '/mydspace',
|
||||
getScopes: observableOf(['test-scope']),
|
||||
setServiceOptions: {},
|
||||
getSearchConfigurationFor: createSuccessfulRemoteDataObject$({ sortOptions: [sortOption]})
|
||||
|
||||
const myDSpaceConfigurationServiceStub: SpyObj<MyDSpaceConfigurationService> = jasmine.createSpyObj('MyDSpaceConfigurationService', {
|
||||
getAvailableConfigurationOptions: jasmine.createSpy('getAvailableConfigurationOptions')
|
||||
});
|
||||
const configurationParam = 'default';
|
||||
const queryParam = 'test query';
|
||||
const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f';
|
||||
const paginatedSearchOptions = new PaginatedSearchOptions({
|
||||
configuration: configurationParam,
|
||||
query: queryParam,
|
||||
scope: scopeParam,
|
||||
pagination,
|
||||
sort
|
||||
});
|
||||
const activatedRouteStub = {
|
||||
snapshot: {
|
||||
queryParamMap: new Map([
|
||||
['query', queryParam],
|
||||
['scope', scopeParam]
|
||||
])
|
||||
|
||||
const configurationList = [
|
||||
{
|
||||
value: MyDSpaceConfigurationValueType.Workspace,
|
||||
label: `mydspace.show.${MyDSpaceConfigurationValueType.Workspace}`,
|
||||
context: Context.Workspace
|
||||
},
|
||||
queryParams: observableOf({
|
||||
query: queryParam,
|
||||
scope: scopeParam
|
||||
})
|
||||
};
|
||||
{
|
||||
value: MyDSpaceConfigurationValueType.Workflow,
|
||||
label: `mydspace.show.${MyDSpaceConfigurationValueType.Workflow}`,
|
||||
context: Context.Workflow
|
||||
}
|
||||
];
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NoopAnimationsModule, NgbCollapseModule],
|
||||
declarations: [MyDSpacePageComponent, RoleDirective],
|
||||
declarations: [MyDSpacePageComponent],
|
||||
providers: [
|
||||
{ provide: SearchService, useValue: searchServiceStub },
|
||||
{
|
||||
provide: CommunityDataService,
|
||||
useValue: jasmine.createSpyObj('communityService', ['findById', 'findAll'])
|
||||
},
|
||||
{ provide: ActivatedRoute, useValue: activatedRouteStub },
|
||||
{ provide: RouteService, useValue: routeServiceStub },
|
||||
{
|
||||
provide: Store, useValue: store
|
||||
},
|
||||
{
|
||||
provide: HostWindowService, useValue: jasmine.createSpyObj('hostWindowService',
|
||||
{
|
||||
isXs: observableOf(true),
|
||||
isSm: observableOf(false),
|
||||
isXsOrSm: observableOf(true)
|
||||
})
|
||||
},
|
||||
{
|
||||
provide: SidebarService,
|
||||
useValue: SidebarServiceStub
|
||||
},
|
||||
{
|
||||
provide: SearchFilterService,
|
||||
useValue: {}
|
||||
}, {
|
||||
provide: SEARCH_CONFIG_SERVICE,
|
||||
useValue: new SearchConfigurationServiceStub()
|
||||
},
|
||||
{
|
||||
provide: RoleService,
|
||||
useValue: new RoleServiceMock()
|
||||
},
|
||||
{ provide: MyDSpaceConfigurationService, useValue: myDSpaceConfigurationServiceStub },
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).overrideComponent(MyDSpacePageComponent, {
|
||||
set: { changeDetection: ChangeDetectionStrategy.Default }
|
||||
set: {
|
||||
providers: [
|
||||
{
|
||||
provide: SEARCH_CONFIG_SERVICE,
|
||||
useValue: myDSpaceConfigurationServiceStub
|
||||
}
|
||||
]
|
||||
}
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MyDSpacePageComponent);
|
||||
comp = fixture.componentInstance; // SearchPageComponent test instance
|
||||
myDSpaceConfigurationServiceStub.getAvailableConfigurationOptions.and.returnValue(observableOf(configurationList));
|
||||
|
||||
fixture.detectChanges();
|
||||
searchServiceObject = (comp as any).service;
|
||||
searchConfigurationServiceObject = (comp as any).searchConfigService;
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
comp = null;
|
||||
searchServiceObject = null;
|
||||
searchConfigurationServiceObject = null;
|
||||
});
|
||||
|
||||
it('should get the scope and query from the route parameters', () => {
|
||||
it('should init properly context and configuration', fakeAsync(() => {
|
||||
|
||||
searchConfigurationServiceObject.paginatedSearchOptions.next(paginatedSearchOptions);
|
||||
expect(comp.searchOptions$).toBeObservable(cold('b', {
|
||||
b: paginatedSearchOptions
|
||||
expect(comp.configurationList$).toBeObservable(cold('(a|)', {
|
||||
a: configurationList
|
||||
}));
|
||||
|
||||
});
|
||||
flush();
|
||||
expect(comp.configuration).toBe(MyDSpaceConfigurationValueType.Workspace);
|
||||
expect(comp.context).toBe(Context.Workspace);
|
||||
}));
|
||||
|
||||
describe('when the open sidebar button is clicked in mobile view', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(comp, 'openSidebar');
|
||||
const openSidebarButton = fixture.debugElement.query(By.css('.open-sidebar'));
|
||||
openSidebarButton.triggerEventHandler('click', null);
|
||||
});
|
||||
|
||||
it('should trigger the openSidebar function', () => {
|
||||
expect(comp.openSidebar).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('when sidebarCollapsed is true in mobile view', () => {
|
||||
let menu: HTMLElement;
|
||||
|
||||
beforeEach(() => {
|
||||
menu = fixture.debugElement.query(By.css('#search-sidebar-sm')).nativeElement;
|
||||
comp.isSidebarCollapsed = () => observableOf(true);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should close the sidebar', () => {
|
||||
expect(menu.classList).not.toContain('active');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('when sidebarCollapsed is false in mobile view', () => {
|
||||
let menu: HTMLElement;
|
||||
|
||||
beforeEach(() => {
|
||||
menu = fixture.debugElement.query(By.css('#search-sidebar-sm')).nativeElement;
|
||||
comp.isSidebarCollapsed = () => observableOf(false);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should open the menu', () => {
|
||||
expect(menu.classList).toContain('active');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('when stable', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should have initialized the sortOptions$ observable', (done) => {
|
||||
|
||||
comp.sortOptions$.subscribe((sortOptions) => {
|
||||
|
||||
expect(sortOptions.length).toEqual(2);
|
||||
expect(sortOptions[0]).toEqual(new SortOptions('score', SortDirection.ASC));
|
||||
expect(sortOptions[1]).toEqual(new SortOptions('score', SortDirection.DESC));
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
@@ -1,36 +1,16 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
Inject,
|
||||
InjectionToken,
|
||||
Input,
|
||||
OnInit
|
||||
} from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, Inject, InjectionToken, OnInit } from '@angular/core';
|
||||
|
||||
import { BehaviorSubject, Observable, Subject, Subscription } from 'rxjs';
|
||||
import { map, switchMap, tap } from 'rxjs/operators';
|
||||
|
||||
import { PaginatedList } from '../core/data/paginated-list.model';
|
||||
import { RemoteData } from '../core/data/remote-data';
|
||||
import { DSpaceObject } from '../core/shared/dspace-object.model';
|
||||
import { pushInOut } from '../shared/animations/push';
|
||||
import { HostWindowService } from '../shared/host-window.service';
|
||||
import { PaginatedSearchOptions } from '../shared/search/paginated-search-options.model';
|
||||
import { Observable } from 'rxjs';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { SearchService } from '../core/shared/search/search.service';
|
||||
import { SidebarService } from '../shared/sidebar/sidebar.service';
|
||||
import { hasValue } from '../shared/empty.util';
|
||||
import { getFirstCompletedRemoteData } from '../core/shared/operators';
|
||||
import { MyDSpaceResponseParsingService } from '../core/data/mydspace-response-parsing.service';
|
||||
import { SearchConfigurationOption } from '../shared/search/search-switch-configuration/search-configuration-option.model';
|
||||
import { RoleType } from '../core/roles/role-types';
|
||||
import { SearchConfigurationService } from '../core/shared/search/search-configuration.service';
|
||||
import { MyDSpaceConfigurationService } from './my-dspace-configuration.service';
|
||||
import { ViewMode } from '../core/shared/view-mode.model';
|
||||
import { MyDSpaceRequest } from '../core/data/request.models';
|
||||
import { SearchResult } from '../shared/search/search-result.model';
|
||||
import { Context } from '../core/shared/context.model';
|
||||
import { SortOptions } from '../core/cache/models/sort-options.model';
|
||||
import { SearchObjects } from '../shared/search/search-objects.model';
|
||||
import { RoleType } from '../core/roles/role-types';
|
||||
|
||||
export const MYDSPACE_ROUTE = '/mydspace';
|
||||
export const SEARCH_CONFIG_SERVICE: InjectionToken<SearchConfigurationService> = new InjectionToken<SearchConfigurationService>('searchConfigurationService');
|
||||
@@ -43,7 +23,6 @@ export const SEARCH_CONFIG_SERVICE: InjectionToken<SearchConfigurationService> =
|
||||
styleUrls: ['./my-dspace-page.component.scss'],
|
||||
templateUrl: './my-dspace-page.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
animations: [pushInOut],
|
||||
providers: [
|
||||
{
|
||||
provide: SEARCH_CONFIG_SERVICE,
|
||||
@@ -53,40 +32,20 @@ export const SEARCH_CONFIG_SERVICE: InjectionToken<SearchConfigurationService> =
|
||||
})
|
||||
export class MyDSpacePageComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* True when the search component should show results on the current page
|
||||
*/
|
||||
@Input() inPlaceSearch = true;
|
||||
|
||||
/**
|
||||
* The list of available configuration options
|
||||
*/
|
||||
configurationList$: Observable<SearchConfigurationOption[]>;
|
||||
|
||||
/**
|
||||
* The current search results
|
||||
* The start context to use in the search: workspace or workflow
|
||||
*/
|
||||
resultsRD$: BehaviorSubject<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>> = new BehaviorSubject(null);
|
||||
context: Context;
|
||||
|
||||
/**
|
||||
* The current paginated search options
|
||||
* The start configuration to use in the search: workspace or workflow
|
||||
*/
|
||||
searchOptions$: Observable<PaginatedSearchOptions>;
|
||||
|
||||
/**
|
||||
* The current available sort options
|
||||
*/
|
||||
sortOptions$: Observable<SortOptions[]>;
|
||||
|
||||
/**
|
||||
* Emits true if were on a small screen
|
||||
*/
|
||||
isXsOrSm$: Observable<boolean>;
|
||||
|
||||
/**
|
||||
* Subscription to unsubscribe from
|
||||
*/
|
||||
sub: Subscription;
|
||||
configuration: string;
|
||||
|
||||
/**
|
||||
* Variable for enumeration RoleType
|
||||
@@ -98,21 +57,8 @@ export class MyDSpacePageComponent implements OnInit {
|
||||
*/
|
||||
viewModeList = [ViewMode.ListElement, ViewMode.DetailedListElement];
|
||||
|
||||
/**
|
||||
* The current context of this page: workspace or workflow
|
||||
*/
|
||||
context$: Observable<Context>;
|
||||
|
||||
/**
|
||||
* Emit an event every time search sidebars must refresh their contents.
|
||||
*/
|
||||
refreshFilters: Subject<any> = new Subject<any>();
|
||||
|
||||
constructor(private service: SearchService,
|
||||
private sidebarService: SidebarService,
|
||||
private windowService: HostWindowService,
|
||||
@Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: MyDSpaceConfigurationService) {
|
||||
this.isXsOrSm$ = this.windowService.isXsOrSm();
|
||||
this.service.setServiceOptions(MyDSpaceResponseParsingService, MyDSpaceRequest);
|
||||
}
|
||||
|
||||
@@ -130,77 +76,12 @@ export class MyDSpacePageComponent implements OnInit {
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.configurationList$ = this.searchConfigService.getAvailableConfigurationOptions();
|
||||
this.searchOptions$ = this.searchConfigService.paginatedSearchOptions;
|
||||
this.sub = this.searchOptions$.pipe(
|
||||
tap(() => this.resultsRD$.next(null)),
|
||||
switchMap((options: PaginatedSearchOptions) => this.service.search(options).pipe(getFirstCompletedRemoteData())))
|
||||
.subscribe((results: RemoteData<SearchObjects<DSpaceObject>>) => {
|
||||
this.resultsRD$.next(results);
|
||||
|
||||
this.configurationList$.pipe(take(1)).subscribe((configurationList: SearchConfigurationOption[]) => {
|
||||
this.configuration = configurationList[0].value;
|
||||
this.context = configurationList[0].context;
|
||||
});
|
||||
|
||||
this.context$ = this.searchConfigService.getCurrentConfiguration('workspace')
|
||||
.pipe(
|
||||
map((configuration: string) => {
|
||||
if (configuration === 'workspace') {
|
||||
return Context.Workspace;
|
||||
} else {
|
||||
return Context.Workflow;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
const configuration$ = this.searchConfigService.getCurrentConfiguration('workspace');
|
||||
const searchConfig$ = this.searchConfigService.getConfigurationSearchConfigObservable(configuration$, this.service);
|
||||
|
||||
this.sortOptions$ = this.searchConfigService.getConfigurationSortOptionsObservable(searchConfig$);
|
||||
this.searchConfigService.initializeSortOptionsFromConfiguration(searchConfig$);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the contentChange event from within the my dspace content.
|
||||
* Notify search sidebars to refresh their content.
|
||||
*/
|
||||
onResultsContentChange() {
|
||||
this.refreshFilters.next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sidebar to a collapsed state
|
||||
*/
|
||||
public closeSidebar(): void {
|
||||
this.sidebarService.collapse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sidebar to an expanded state
|
||||
*/
|
||||
public openSidebar(): void {
|
||||
this.sidebarService.expand();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the sidebar is collapsed
|
||||
* @returns {Observable<boolean>} emits true if the sidebar is currently collapsed, false if it is expanded
|
||||
*/
|
||||
public isSidebarCollapsed(): Observable<boolean> {
|
||||
return this.sidebarService.isCollapsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} The base path to the search page
|
||||
*/
|
||||
public getSearchLink(): string {
|
||||
return this.service.getSearchLink();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from the subscription
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
if (hasValue(this.sub)) {
|
||||
this.sub.unsubscribe();
|
||||
}
|
||||
this.refreshFilters.complete();
|
||||
}
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@ import { SharedModule } from '../shared/shared.module';
|
||||
|
||||
import { MyDspacePageRoutingModule } from './my-dspace-page-routing.module';
|
||||
import { MyDSpacePageComponent } from './my-dspace-page.component';
|
||||
import { MyDSpaceResultsComponent } from './my-dspace-results/my-dspace-results.component';
|
||||
import { MyDSpaceNewSubmissionComponent } from './my-dspace-new-submission/my-dspace-new-submission.component';
|
||||
import { MyDSpaceGuard } from './my-dspace.guard';
|
||||
import { MyDSpaceConfigurationService } from './my-dspace-configuration.service';
|
||||
@@ -14,11 +13,11 @@ import { MyDspaceSearchModule } from './my-dspace-search.module';
|
||||
import { MyDSpaceNewSubmissionDropdownComponent } from './my-dspace-new-submission/my-dspace-new-submission-dropdown/my-dspace-new-submission-dropdown.component';
|
||||
import { MyDSpaceNewExternalDropdownComponent } from './my-dspace-new-submission/my-dspace-new-external-dropdown/my-dspace-new-external-dropdown.component';
|
||||
import { ThemedMyDSpacePageComponent } from './themed-my-dspace-page.component';
|
||||
import { SearchModule } from '../shared/search/search.module';
|
||||
|
||||
const DECLARATIONS = [
|
||||
MyDSpacePageComponent,
|
||||
ThemedMyDSpacePageComponent,
|
||||
MyDSpaceResultsComponent,
|
||||
MyDSpaceNewSubmissionComponent,
|
||||
CollectionSelectorComponent,
|
||||
MyDSpaceNewSubmissionDropdownComponent,
|
||||
@@ -29,6 +28,7 @@ const DECLARATIONS = [
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
SearchModule,
|
||||
MyDspacePageRoutingModule,
|
||||
MyDspaceSearchModule.withEntryComponents()
|
||||
],
|
||||
|
@@ -1,14 +0,0 @@
|
||||
<div *ngIf="searchResults?.hasSucceeded && !searchResults?.isLoading && searchResults?.payload?.page.length > 0" @fadeIn>
|
||||
<ds-viewable-collection
|
||||
[config]="searchConfig.pagination"
|
||||
[hasBorder]="hasBorder"
|
||||
[sortConfig]="searchConfig.sort"
|
||||
[objects]="searchResults"
|
||||
[hideGear]="true"
|
||||
[context]="context"
|
||||
(contentChange)="contentChange.emit()">
|
||||
</ds-viewable-collection>
|
||||
</div>
|
||||
<ds-loading *ngIf="isLoading()" message="{{'loading.mydspace-results' | translate}}"></ds-loading>
|
||||
<ds-error *ngIf="showError()" message="{{errorMessageLabel() | translate}}"></ds-error>
|
||||
<h3 *ngIf="searchResults?.payload?.page.length == 0" class="text-center text-muted" ><span>{{'mydspace.results.no-results' | translate}}</span></h3>
|
@@ -1,68 +0,0 @@
|
||||
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { QueryParamsDirectiveStub } from '../../shared/testing/query-params-directive.stub';
|
||||
import { MyDSpaceResultsComponent } from './my-dspace-results.component';
|
||||
|
||||
describe('MyDSpaceResultsComponent', () => {
|
||||
let comp: MyDSpaceResultsComponent;
|
||||
let fixture: ComponentFixture<MyDSpaceResultsComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), NoopAnimationsModule],
|
||||
declarations: [
|
||||
MyDSpaceResultsComponent,
|
||||
QueryParamsDirectiveStub],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MyDSpaceResultsComponent);
|
||||
comp = fixture.componentInstance; // MyDSpaceResultsComponent test instance
|
||||
});
|
||||
|
||||
it('should display results when results are not empty', () => {
|
||||
(comp as any).searchResults = { hasSucceeded: true, isLoading: false, payload: { page: { length: 2 } } };
|
||||
(comp as any).searchConfig = {};
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.query(By.css('ds-viewable-collection'))).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should not display link when results are not empty', () => {
|
||||
(comp as any).searchResults = { hasSucceeded: true, isLoading: false, payload: { page: { length: 2 } } };
|
||||
(comp as any).searchConfig = {};
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.query(By.css('a'))).toBeNull();
|
||||
});
|
||||
|
||||
it('should display error message if error is 500', () => {
|
||||
(comp as any).searchResults = { hasFailed: true, statusCode: 500 };
|
||||
fixture.detectChanges();
|
||||
expect(comp.showError()).toBeTrue();
|
||||
expect(comp.errorMessageLabel()).toBe('error.search-results');
|
||||
expect(fixture.debugElement.query(By.css('ds-error'))).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should display error message if error is 422', () => {
|
||||
(comp as any).searchResults = { hasFailed: true, statusCode: 422 };
|
||||
fixture.detectChanges();
|
||||
expect(comp.showError()).toBeTrue();
|
||||
expect(comp.errorMessageLabel()).toBe('error.invalid-search-query');
|
||||
expect(fixture.debugElement.query(By.css('ds-error'))).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should display a message if search result is empty', () => {
|
||||
(comp as any).searchResults = { payload: { page: { length: 0 } } };
|
||||
(comp as any).searchConfig = { query: 'foobar' };
|
||||
fixture.detectChanges();
|
||||
|
||||
const linkDes = fixture.debugElement.queryAll(By.css('text-muted'));
|
||||
|
||||
expect(linkDes).toBeDefined();
|
||||
});
|
||||
});
|
@@ -1,69 +0,0 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||
import { fadeIn, fadeInOut } from '../../shared/animations/fade';
|
||||
import { PaginatedList } from '../../core/data/paginated-list.model';
|
||||
import { ViewMode } from '../../core/shared/view-mode.model';
|
||||
import { isEmpty } from '../../shared/empty.util';
|
||||
import { Context } from '../../core/shared/context.model';
|
||||
import { SearchResult } from '../../shared/search/search-result.model';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
|
||||
|
||||
/**
|
||||
* Component that represents all results for mydspace page
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-my-dspace-results',
|
||||
templateUrl: './my-dspace-results.component.html',
|
||||
animations: [
|
||||
fadeIn,
|
||||
fadeInOut
|
||||
]
|
||||
})
|
||||
export class MyDSpaceResultsComponent {
|
||||
|
||||
/**
|
||||
* The actual search result objects
|
||||
*/
|
||||
@Input() searchResults: RemoteData<PaginatedList<SearchResult<DSpaceObject>>>;
|
||||
|
||||
/**
|
||||
* The current configuration of the search
|
||||
*/
|
||||
@Input() searchConfig: PaginatedSearchOptions;
|
||||
|
||||
/**
|
||||
* The current view mode for the search results
|
||||
*/
|
||||
@Input() viewMode: ViewMode;
|
||||
|
||||
/**
|
||||
* The current context for the search results
|
||||
*/
|
||||
@Input() context: Context;
|
||||
|
||||
/**
|
||||
* Emit when one of the results has changed.
|
||||
*/
|
||||
@Output() contentChange = new EventEmitter<any>();
|
||||
|
||||
/**
|
||||
* A boolean representing if search results entry are separated by a line
|
||||
*/
|
||||
hasBorder = true;
|
||||
|
||||
/**
|
||||
* Check if mydspace search results are loading
|
||||
*/
|
||||
isLoading() {
|
||||
return !this.searchResults || isEmpty(this.searchResults) || this.searchResults.isLoading;
|
||||
}
|
||||
|
||||
showError(): boolean {
|
||||
return this.searchResults?.hasFailed && (!this.searchResults?.errorMessage || this.searchResults?.statusCode !== 400);
|
||||
}
|
||||
|
||||
errorMessageLabel(): string {
|
||||
return (this.searchResults?.statusCode === 422) ? 'error.invalid-search-query' : 'error.search-results';
|
||||
}
|
||||
}
|
@@ -6,12 +6,14 @@ import { ProfilePageComponent } from './profile-page.component';
|
||||
import { ProfilePageMetadataFormComponent } from './profile-page-metadata-form/profile-page-metadata-form.component';
|
||||
import { ProfilePageSecurityFormComponent } from './profile-page-security-form/profile-page-security-form.component';
|
||||
import { ThemedProfilePageComponent } from './themed-profile-page.component';
|
||||
import { FormModule } from '../shared/form/form.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
ProfilePageRoutingModule,
|
||||
CommonModule,
|
||||
SharedModule
|
||||
SharedModule,
|
||||
FormModule
|
||||
],
|
||||
exports: [
|
||||
ProfilePageSecurityFormComponent,
|
||||
|
@@ -2,18 +2,14 @@ import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angul
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { Router } from '@angular/router';
|
||||
import { NavigationExtras, Router } from '@angular/router';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { SearchService } from '../core/shared/search/search.service';
|
||||
import { TranslateLoaderMock } from '../shared/mocks/translate-loader.mock';
|
||||
|
||||
import { SearchNavbarComponent } from './search-navbar.component';
|
||||
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
|
||||
import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { PaginationService } from '../core/pagination/pagination.service';
|
||||
import { SearchConfigurationService } from '../core/shared/search/search-configuration.service';
|
||||
import { PaginationServiceStub } from '../shared/testing/pagination-service.stub';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
describe('SearchNavbarComponent', () => {
|
||||
let component: SearchNavbarComponent;
|
||||
@@ -41,6 +37,7 @@ describe('SearchNavbarComponent', () => {
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
BrowserAnimationsModule,
|
||||
RouterTestingModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
@@ -49,10 +46,7 @@ describe('SearchNavbarComponent', () => {
|
||||
})],
|
||||
declarations: [SearchNavbarComponent],
|
||||
providers: [
|
||||
{ provide: SearchService, useValue: mockSearchService },
|
||||
{ provide: PaginationService, useValue: paginationService },
|
||||
{ provide: Router, useValue: routerStub },
|
||||
{ provide: SearchConfigurationService, useValue: {paginationID: 'page-id'} }
|
||||
{ provide: SearchService, useValue: mockSearchService }
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
@@ -61,8 +55,8 @@ describe('SearchNavbarComponent', () => {
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SearchNavbarComponent);
|
||||
component = fixture.componentInstance;
|
||||
router = TestBed.inject(Router);
|
||||
fixture.detectChanges();
|
||||
router = (component as any).router;
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
@@ -73,7 +67,7 @@ describe('SearchNavbarComponent', () => {
|
||||
beforeEach(fakeAsync(() => {
|
||||
spyOn(component, 'expand').and.callThrough();
|
||||
spyOn(component, 'onSubmit').and.callThrough();
|
||||
spyOn(router, 'navigate').and.callThrough();
|
||||
spyOn(router, 'navigate');
|
||||
const searchIcon = fixture.debugElement.query(By.css('#search-navbar-container form .submit-icon'));
|
||||
searchIcon.triggerEventHandler('click', {
|
||||
preventDefault: () => {/**/
|
||||
@@ -99,8 +93,9 @@ describe('SearchNavbarComponent', () => {
|
||||
fixture.detectChanges();
|
||||
}));
|
||||
it('to search page with empty query', () => {
|
||||
const extras: NavigationExtras = {queryParams: { query: '' }, queryParamsHandling: 'merge'};
|
||||
expect(component.onSubmit).toHaveBeenCalledWith({ query: '' });
|
||||
expect(paginationService.updateRouteWithUrl).toHaveBeenCalled();
|
||||
expect(router.navigate).toHaveBeenCalledWith(['search'], extras);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -123,8 +118,10 @@ describe('SearchNavbarComponent', () => {
|
||||
fixture.detectChanges();
|
||||
}));
|
||||
it('to search page with query', async () => {
|
||||
const extras: NavigationExtras = { queryParams: { query: 'test' }, queryParamsHandling: 'merge'};
|
||||
expect(component.onSubmit).toHaveBeenCalledWith({ query: 'test' });
|
||||
expect(paginationService.updateRouteWithUrl).toHaveBeenCalled();
|
||||
|
||||
expect(router.navigate).toHaveBeenCalledWith(['search'], extras);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -3,8 +3,6 @@ import { FormBuilder } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { SearchService } from '../core/shared/search/search.service';
|
||||
import { expandSearchInput } from '../shared/animations/slide';
|
||||
import { PaginationService } from '../core/pagination/pagination.service';
|
||||
import { SearchConfigurationService } from '../core/shared/search/search-configuration.service';
|
||||
|
||||
/**
|
||||
* The search box in the header that expands on focus and collapses on focus out
|
||||
@@ -26,9 +24,7 @@ export class SearchNavbarComponent {
|
||||
// Search input field
|
||||
@ViewChild('searchInput') searchField: ElementRef;
|
||||
|
||||
constructor(private formBuilder: FormBuilder, private router: Router, private searchService: SearchService,
|
||||
private paginationService: PaginationService,
|
||||
private searchConfig: SearchConfigurationService) {
|
||||
constructor(private formBuilder: FormBuilder, private router: Router, private searchService: SearchService) {
|
||||
this.searchForm = this.formBuilder.group(({
|
||||
query: '',
|
||||
}));
|
||||
@@ -65,8 +61,13 @@ export class SearchNavbarComponent {
|
||||
*/
|
||||
onSubmit(data: any) {
|
||||
this.collapse();
|
||||
const linkToNavigateTo = this.searchService.getSearchLink().split('/');
|
||||
const queryParams = Object.assign({}, data);
|
||||
const linkToNavigateTo = [this.searchService.getSearchLink().replace('/', '')];
|
||||
this.searchForm.reset();
|
||||
this.paginationService.updateRouteWithUrl(this.searchConfig.paginationID, linkToNavigateTo, {page: 1}, data);
|
||||
|
||||
this.router.navigate(linkToNavigateTo, {
|
||||
queryParams: queryParams,
|
||||
queryParamsHandling: 'merge'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { configureSearchComponentTestingModule } from './search.component.spec';
|
||||
import { configureSearchComponentTestingModule } from '../shared/search/search.component.spec';
|
||||
import { ConfigurationSearchPageComponent } from './configuration-search-page.component';
|
||||
import { SearchConfigurationService } from '../core/shared/search/search-configuration.service';
|
||||
import { Component, ViewChild } from '@angular/core';
|
||||
|
@@ -1,17 +1,10 @@
|
||||
import { HostWindowService } from '../shared/host-window.service';
|
||||
import { SidebarService } from '../shared/sidebar/sidebar.service';
|
||||
import { SearchComponent } from './search.component';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
Inject,
|
||||
Input,
|
||||
OnInit
|
||||
} from '@angular/core';
|
||||
import { SearchComponent } from '../shared/search/search.component';
|
||||
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
|
||||
import { pushInOut } from '../shared/animations/push';
|
||||
import { SEARCH_CONFIG_SERVICE } from '../my-dspace-page/my-dspace-page.component';
|
||||
import { SearchConfigurationService } from '../core/shared/search/search-configuration.service';
|
||||
import { hasValue } from '../shared/empty.util';
|
||||
import { RouteService } from '../core/services/route.service';
|
||||
import { SearchService } from '../core/shared/search/search.service';
|
||||
import { Router } from '@angular/router';
|
||||
@@ -21,8 +14,8 @@ import { Router } from '@angular/router';
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-configuration-search-page',
|
||||
styleUrls: ['./search.component.scss'],
|
||||
templateUrl: './search.component.html',
|
||||
styleUrls: ['../shared/search/search.component.scss'],
|
||||
templateUrl: '../shared/search/search.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
animations: [pushInOut],
|
||||
providers: [
|
||||
@@ -33,18 +26,7 @@ import { Router } from '@angular/router';
|
||||
]
|
||||
})
|
||||
|
||||
export class ConfigurationSearchPageComponent extends SearchComponent implements OnInit {
|
||||
/**
|
||||
* The configuration to use for the search options
|
||||
* If empty, the configuration will be determined by the route parameter called 'configuration'
|
||||
*/
|
||||
@Input() configuration: string;
|
||||
|
||||
/**
|
||||
* The actual query for the fixed filter.
|
||||
* If empty, the query will be determined by the route parameter called 'filter'
|
||||
*/
|
||||
@Input() fixedFilterQuery: string;
|
||||
export class ConfigurationSearchPageComponent extends SearchComponent {
|
||||
|
||||
constructor(protected service: SearchService,
|
||||
protected sidebarService: SidebarService,
|
||||
@@ -55,20 +37,4 @@ export class ConfigurationSearchPageComponent extends SearchComponent implements
|
||||
super(service, sidebarService, windowService, searchConfigService, routeService, router);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listening to changes in the paginated search options
|
||||
* If something changes, update the search results
|
||||
*
|
||||
* Listen to changes in the scope
|
||||
* If something changes, update the list of scopes for the dropdown
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
super.ngOnInit();
|
||||
if (hasValue(this.configuration)) {
|
||||
this.routeService.setParameter('configuration', this.configuration);
|
||||
}
|
||||
if (hasValue(this.fixedFilterQuery)) {
|
||||
this.routeService.setParameter('fixedFilterQuery', this.fixedFilterQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,16 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { SEARCH_CONFIG_SERVICE } from '../my-dspace-page/my-dspace-page.component';
|
||||
import { SearchConfigurationService } from '../core/shared/search/search-configuration.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-search-page',
|
||||
templateUrl: './search-page.component.html',
|
||||
providers: [
|
||||
{
|
||||
provide: SEARCH_CONFIG_SERVICE,
|
||||
useClass: SearchConfigurationService
|
||||
}
|
||||
]
|
||||
})
|
||||
/**
|
||||
* This component represents the whole search page
|
||||
|
@@ -2,7 +2,6 @@ import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CoreModule } from '../core/core.module';
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { SearchComponent } from './search.component';
|
||||
import { SidebarService } from '../shared/sidebar/sidebar.service';
|
||||
import { ConfigurationSearchPageGuard } from './configuration-search-page.guard';
|
||||
import { SearchTrackerComponent } from './search-tracker.component';
|
||||
@@ -14,10 +13,10 @@ import { SearchConfigurationService } from '../core/shared/search/search-configu
|
||||
import { JournalEntitiesModule } from '../entity-groups/journal-entities/journal-entities.module';
|
||||
import { ResearchEntitiesModule } from '../entity-groups/research-entities/research-entities.module';
|
||||
import { ThemedSearchPageComponent } from './themed-search-page.component';
|
||||
import { SearchModule } from '../shared/search/search.module';
|
||||
|
||||
const components = [
|
||||
SearchPageComponent,
|
||||
SearchComponent,
|
||||
SearchTrackerComponent,
|
||||
ThemedSearchPageComponent
|
||||
];
|
||||
@@ -25,6 +24,7 @@ const components = [
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
SearchModule,
|
||||
SharedModule.withEntryComponents(),
|
||||
CoreModule.forRoot(),
|
||||
StatisticsModule.forRoot(),
|
||||
|
@@ -1,15 +1,15 @@
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { Angulartics2 } from 'angulartics2';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
import { SearchComponent } from './search.component';
|
||||
import { SearchComponent } from '../shared/search/search.component';
|
||||
import { SidebarService } from '../shared/sidebar/sidebar.service';
|
||||
import { HostWindowService } from '../shared/host-window.service';
|
||||
import { SEARCH_CONFIG_SERVICE } from '../my-dspace-page/my-dspace-page.component';
|
||||
import { RouteService } from '../core/services/route.service';
|
||||
import { SearchConfigurationService } from '../core/shared/search/search-configuration.service';
|
||||
import { SearchService } from '../core/shared/search/search.service';
|
||||
import { PaginatedSearchOptions } from '../shared/search/paginated-search-options.model';
|
||||
import { SearchObjects } from '../shared/search/search-objects.model';
|
||||
import { PaginatedSearchOptions } from '../shared/search/models/paginated-search-options.model';
|
||||
import { SearchObjects } from '../shared/search/models/search-objects.model';
|
||||
import { Router } from '@angular/router';
|
||||
import { RemoteData } from '../core/data/remote-data';
|
||||
import { DSpaceObject } from '../core/shared/dspace-object.model';
|
||||
|
@@ -1,59 +0,0 @@
|
||||
<div class="container" *ngIf="(isXsOrSm$ | async)">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<ng-template *ngTemplateOutlet="searchForm"></ng-template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ds-page-with-sidebar [id]="'search-page'" [sidebarContent]="sidebarContent">
|
||||
<div class="row">
|
||||
<div class="col-12" *ngIf="!(isXsOrSm$ | async)">
|
||||
<ng-template *ngTemplateOutlet="searchForm"></ng-template>
|
||||
</div>
|
||||
<div id="search-content" class="col-12">
|
||||
<div class="d-block d-md-none search-controls clearfix">
|
||||
<ds-view-mode-switch [inPlaceSearch]="inPlaceSearch"></ds-view-mode-switch>
|
||||
<button (click)="openSidebar()" aria-controls="#search-body"
|
||||
class="btn btn-outline-primary float-right open-sidebar"><i
|
||||
class="fas fa-sliders"></i> {{"search.sidebar.open"
|
||||
| translate}}
|
||||
</button>
|
||||
</div>
|
||||
<ds-search-results [searchResults]="resultsRD$ | async"
|
||||
[searchConfig]="searchOptions$ | async"
|
||||
[configuration]="configuration$ | async"
|
||||
[disableHeader]="!searchEnabled"
|
||||
[context]="context"></ds-search-results>
|
||||
</div>
|
||||
</div>
|
||||
</ds-page-with-sidebar>
|
||||
|
||||
<ng-template #sidebarContent>
|
||||
<ds-search-sidebar id="search-sidebar" *ngIf="!(isXsOrSm$ | async)"
|
||||
[resultCount]="(resultsRD$ | async)?.payload?.totalElements"
|
||||
[searchOptions]="(searchOptions$ | async)"
|
||||
[sortOptions]="(sortOptions$ | async)"
|
||||
[inPlaceSearch]="inPlaceSearch"></ds-search-sidebar>
|
||||
<ds-search-sidebar id="search-sidebar-sm" *ngIf="(isXsOrSm$ | async)"
|
||||
[resultCount]="(resultsRD$ | async)?.payload.totalElements"
|
||||
[searchOptions]="(searchOptions$ | async)"
|
||||
[sortOptions]="(sortOptions$ | async)"
|
||||
(toggleSidebar)="closeSidebar()">
|
||||
</ds-search-sidebar>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #searchForm>
|
||||
<ds-search-form *ngIf="searchEnabled" id="search-form"
|
||||
[query]="(searchOptions$ | async)?.query"
|
||||
[scope]="(searchOptions$ | async)?.scope"
|
||||
[currentUrl]="searchLink"
|
||||
[showScopeSelector]="true"
|
||||
[inPlaceSearch]="inPlaceSearch"
|
||||
[searchPlaceholder]="'search.search-form.placeholder' | translate">
|
||||
</ds-search-form>
|
||||
<div class="row mb-3 mb-md-1">
|
||||
<div class="labels col-sm-9">
|
||||
<ds-search-labels *ngIf="searchEnabled" [inPlaceSearch]="inPlaceSearch"></ds-search-labels>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
@@ -1,206 +0,0 @@
|
||||
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { cold, hot } from 'jasmine-marbles';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model';
|
||||
import { CommunityDataService } from '../core/data/community-data.service';
|
||||
import { HostWindowService } from '../shared/host-window.service';
|
||||
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
|
||||
import { SearchComponent } from './search.component';
|
||||
import { SearchService } from '../core/shared/search/search.service';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { SidebarService } from '../shared/sidebar/sidebar.service';
|
||||
import { SearchFilterService } from '../core/shared/search/search-filter.service';
|
||||
import { SearchConfigurationService } from '../core/shared/search/search-configuration.service';
|
||||
import { SEARCH_CONFIG_SERVICE } from '../my-dspace-page/my-dspace-page.component';
|
||||
import { RouteService } from '../core/services/route.service';
|
||||
import { SearchConfigurationServiceStub } from '../shared/testing/search-configuration-service.stub';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils';
|
||||
import { PaginatedSearchOptions } from '../shared/search/paginated-search-options.model';
|
||||
import { SidebarServiceStub } from '../shared/testing/sidebar-service.stub';
|
||||
|
||||
let comp: SearchComponent;
|
||||
let fixture: ComponentFixture<SearchComponent>;
|
||||
let searchServiceObject: SearchService;
|
||||
let searchConfigurationServiceObject: SearchConfigurationService;
|
||||
const store: Store<SearchComponent> = jasmine.createSpyObj('store', {
|
||||
/* tslint:disable:no-empty */
|
||||
dispatch: {},
|
||||
/* tslint:enable:no-empty */
|
||||
select: observableOf(true)
|
||||
});
|
||||
const pagination: PaginationComponentOptions = new PaginationComponentOptions();
|
||||
pagination.id = 'search-results-pagination';
|
||||
pagination.currentPage = 1;
|
||||
pagination.pageSize = 10;
|
||||
const sortOption = { name: 'score', sortOrder: 'DESC', metadata: null };
|
||||
const sort: SortOptions = new SortOptions('score', SortDirection.DESC);
|
||||
const mockResults = createSuccessfulRemoteDataObject$(['test', 'data']);
|
||||
const searchServiceStub = jasmine.createSpyObj('SearchService', {
|
||||
search: mockResults,
|
||||
getSearchLink: '/search',
|
||||
getScopes: observableOf(['test-scope']),
|
||||
getSearchConfigurationFor: createSuccessfulRemoteDataObject$({ sortOptions: [sortOption]})
|
||||
});
|
||||
const configurationParam = 'default';
|
||||
const queryParam = 'test query';
|
||||
const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f';
|
||||
const fixedFilter = 'fixed filter';
|
||||
const paginatedSearchOptions = new PaginatedSearchOptions({
|
||||
configuration: configurationParam,
|
||||
query: queryParam,
|
||||
scope: scopeParam,
|
||||
fixedFilter: fixedFilter,
|
||||
pagination,
|
||||
sort
|
||||
});
|
||||
const activatedRouteStub = {
|
||||
snapshot: {
|
||||
queryParamMap: new Map([
|
||||
['query', queryParam],
|
||||
['scope', scopeParam]
|
||||
])
|
||||
},
|
||||
queryParams: observableOf({
|
||||
query: queryParam,
|
||||
scope: scopeParam
|
||||
})
|
||||
};
|
||||
|
||||
const routeServiceStub = {
|
||||
getRouteParameterValue: () => {
|
||||
return observableOf('');
|
||||
},
|
||||
getQueryParameterValue: () => {
|
||||
return observableOf('');
|
||||
},
|
||||
getQueryParamsWithPrefix: () => {
|
||||
return observableOf('');
|
||||
}
|
||||
};
|
||||
|
||||
export function configureSearchComponentTestingModule(compType, additionalDeclarations: any[] = []) {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NoopAnimationsModule, NgbCollapseModule],
|
||||
declarations: [compType, ...additionalDeclarations],
|
||||
providers: [
|
||||
{ provide: SearchService, useValue: searchServiceStub },
|
||||
{
|
||||
provide: CommunityDataService,
|
||||
useValue: jasmine.createSpyObj('communityService', ['findById', 'findAll'])
|
||||
},
|
||||
{ provide: ActivatedRoute, useValue: activatedRouteStub },
|
||||
{ provide: RouteService, useValue: routeServiceStub },
|
||||
{
|
||||
provide: Store, useValue: store
|
||||
},
|
||||
{
|
||||
provide: HostWindowService, useValue: jasmine.createSpyObj('hostWindowService',
|
||||
{
|
||||
isXs: observableOf(true),
|
||||
isSm: observableOf(false),
|
||||
isXsOrSm: observableOf(true)
|
||||
})
|
||||
},
|
||||
{
|
||||
provide: SidebarService,
|
||||
useValue: SidebarServiceStub
|
||||
},
|
||||
{
|
||||
provide: SearchFilterService,
|
||||
useValue: {}
|
||||
},
|
||||
{
|
||||
provide: SearchConfigurationService,
|
||||
useValue: {
|
||||
paginatedSearchOptions: hot('a', {
|
||||
a: paginatedSearchOptions
|
||||
}),
|
||||
getCurrentScope: (a) => observableOf('test-id'),
|
||||
/* tslint:disable:no-empty */
|
||||
updateFixedFilter: (newFilter) => {
|
||||
}
|
||||
/* tslint:enable:no-empty */
|
||||
}
|
||||
},
|
||||
{
|
||||
provide: SEARCH_CONFIG_SERVICE,
|
||||
useValue: new SearchConfigurationServiceStub()
|
||||
},
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).overrideComponent(compType, {
|
||||
set: { changeDetection: ChangeDetectionStrategy.Default }
|
||||
}).compileComponents();
|
||||
}
|
||||
|
||||
describe('SearchComponent', () => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
configureSearchComponentTestingModule(SearchComponent);
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SearchComponent);
|
||||
comp = fixture.componentInstance; // SearchComponent test instance
|
||||
comp.inPlaceSearch = false;
|
||||
fixture.detectChanges();
|
||||
searchServiceObject = (comp as any).service;
|
||||
searchConfigurationServiceObject = (comp as any).searchConfigService;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
comp = null;
|
||||
searchServiceObject = null;
|
||||
searchConfigurationServiceObject = null;
|
||||
});
|
||||
|
||||
it('should get the scope and query from the route parameters', () => {
|
||||
|
||||
searchConfigurationServiceObject.paginatedSearchOptions.next(paginatedSearchOptions);
|
||||
expect(comp.searchOptions$).toBeObservable(cold('b', {
|
||||
b: paginatedSearchOptions
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('when the open sidebar button is clicked in mobile view', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(comp, 'openSidebar');
|
||||
const openSidebarButton = fixture.debugElement.query(By.css('.open-sidebar'));
|
||||
openSidebarButton.triggerEventHandler('click', null);
|
||||
});
|
||||
|
||||
it('should trigger the openSidebar function', () => {
|
||||
expect(comp.openSidebar).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('when stable', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should have initialized the sortOptions$ observable', (done) => {
|
||||
|
||||
comp.sortOptions$.subscribe((sortOptions) => {
|
||||
|
||||
expect(sortOptions.length).toEqual(2);
|
||||
expect(sortOptions[0]).toEqual(new SortOptions('score', SortDirection.ASC));
|
||||
expect(sortOptions[1]).toEqual(new SortOptions('score', SortDirection.DESC));
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
@@ -1,195 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component, Inject, Input, OnInit } from '@angular/core';
|
||||
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
|
||||
import { startWith, switchMap } from 'rxjs/operators';
|
||||
import { PaginatedList } from '../core/data/paginated-list.model';
|
||||
import { RemoteData } from '../core/data/remote-data';
|
||||
import { DSpaceObject } from '../core/shared/dspace-object.model';
|
||||
import { pushInOut } from '../shared/animations/push';
|
||||
import { HostWindowService } from '../shared/host-window.service';
|
||||
import { SidebarService } from '../shared/sidebar/sidebar.service';
|
||||
import { hasValue, isEmpty } from '../shared/empty.util';
|
||||
import { getFirstCompletedRemoteData } from '../core/shared/operators';
|
||||
import { RouteService } from '../core/services/route.service';
|
||||
import { SEARCH_CONFIG_SERVICE } from '../my-dspace-page/my-dspace-page.component';
|
||||
import { PaginatedSearchOptions } from '../shared/search/paginated-search-options.model';
|
||||
import { SearchResult } from '../shared/search/search-result.model';
|
||||
import { SearchConfigurationService } from '../core/shared/search/search-configuration.service';
|
||||
import { SearchService } from '../core/shared/search/search.service';
|
||||
import { currentPath } from '../shared/utils/route.utils';
|
||||
import { Router } from '@angular/router';
|
||||
import { Context } from '../core/shared/context.model';
|
||||
import { SortOptions } from '../core/cache/models/sort-options.model';
|
||||
import { followLink } from '../shared/utils/follow-link-config.model';
|
||||
import { Item } from '../core/shared/item.model';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-search',
|
||||
styleUrls: ['./search.component.scss'],
|
||||
templateUrl: './search.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
animations: [pushInOut],
|
||||
providers: [
|
||||
{
|
||||
provide: SEARCH_CONFIG_SERVICE,
|
||||
useClass: SearchConfigurationService
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
/**
|
||||
* This component renders a sidebar, a search input bar and the search results.
|
||||
*/
|
||||
export class SearchComponent implements OnInit {
|
||||
/**
|
||||
* The current search results
|
||||
*/
|
||||
resultsRD$: BehaviorSubject<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>> = new BehaviorSubject(null);
|
||||
|
||||
/**
|
||||
* The current paginated search options
|
||||
*/
|
||||
searchOptions$: Observable<PaginatedSearchOptions>;
|
||||
|
||||
/**
|
||||
* The current available sort options
|
||||
*/
|
||||
sortOptions$: Observable<SortOptions[]>;
|
||||
|
||||
/**
|
||||
* Emits true if were on a small screen
|
||||
*/
|
||||
isXsOrSm$: Observable<boolean>;
|
||||
|
||||
/**
|
||||
* Subscription to unsubscribe from
|
||||
*/
|
||||
sub: Subscription;
|
||||
|
||||
/**
|
||||
* True when the search component should show results on the current page
|
||||
*/
|
||||
@Input() inPlaceSearch = true;
|
||||
|
||||
/**
|
||||
* Whether or not the search bar should be visible
|
||||
*/
|
||||
@Input()
|
||||
searchEnabled = true;
|
||||
|
||||
/**
|
||||
* The width of the sidebar (bootstrap columns)
|
||||
*/
|
||||
@Input()
|
||||
sideBarWidth = 3;
|
||||
|
||||
/**
|
||||
* The currently applied configuration (determines title of search)
|
||||
*/
|
||||
@Input()
|
||||
configuration$: Observable<string>;
|
||||
|
||||
/**
|
||||
* The current context
|
||||
*/
|
||||
@Input()
|
||||
context: Context;
|
||||
|
||||
/**
|
||||
* Link to the search page
|
||||
*/
|
||||
searchLink: string;
|
||||
|
||||
/**
|
||||
* Observable for whether or not the sidebar is currently collapsed
|
||||
*/
|
||||
isSidebarCollapsed$: Observable<boolean>;
|
||||
|
||||
constructor(protected service: SearchService,
|
||||
protected sidebarService: SidebarService,
|
||||
protected windowService: HostWindowService,
|
||||
@Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService,
|
||||
protected routeService: RouteService,
|
||||
protected router: Router) {
|
||||
this.isXsOrSm$ = this.windowService.isXsOrSm();
|
||||
}
|
||||
|
||||
/**
|
||||
* Listening to changes in the paginated search options
|
||||
* If something changes, update the search results
|
||||
*
|
||||
* Listen to changes in the scope
|
||||
* If something changes, update the list of scopes for the dropdown
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.isSidebarCollapsed$ = this.isSidebarCollapsed();
|
||||
this.searchLink = this.getSearchLink();
|
||||
this.searchOptions$ = this.getSearchOptions();
|
||||
this.sub = this.searchOptions$.pipe(
|
||||
switchMap((options) => this.service.search(
|
||||
options, undefined, false, true, followLink<Item>('thumbnail', { isOptional: true })
|
||||
).pipe(getFirstCompletedRemoteData(), startWith(undefined))
|
||||
)
|
||||
).subscribe((results) => {
|
||||
this.resultsRD$.next(results);
|
||||
});
|
||||
|
||||
if (isEmpty(this.configuration$)) {
|
||||
this.configuration$ = this.searchConfigService.getCurrentConfiguration('default');
|
||||
}
|
||||
|
||||
const searchConfig$ = this.searchConfigService.getConfigurationSearchConfigObservable(this.configuration$, this.service);
|
||||
|
||||
this.sortOptions$ = this.searchConfigService.getConfigurationSortOptionsObservable(searchConfig$);
|
||||
this.searchConfigService.initializeSortOptionsFromConfiguration(searchConfig$);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current paginated search options
|
||||
* @returns {Observable<PaginatedSearchOptions>}
|
||||
*/
|
||||
protected getSearchOptions(): Observable<PaginatedSearchOptions> {
|
||||
return this.searchConfigService.paginatedSearchOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sidebar to a collapsed state
|
||||
*/
|
||||
public closeSidebar(): void {
|
||||
this.sidebarService.collapse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sidebar to an expanded state
|
||||
*/
|
||||
public openSidebar(): void {
|
||||
this.sidebarService.expand();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the sidebar is collapsed
|
||||
* @returns {Observable<boolean>} emits true if the sidebar is currently collapsed, false if it is expanded
|
||||
*/
|
||||
private isSidebarCollapsed(): Observable<boolean> {
|
||||
return this.sidebarService.isCollapsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
|
||||
*/
|
||||
private getSearchLink(): string {
|
||||
if (this.inPlaceSearch) {
|
||||
return currentPath(this.router);
|
||||
}
|
||||
return this.service.getSearchLink();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from the subscription
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
if (hasValue(this.sub)) {
|
||||
this.sub.unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
@@ -55,7 +55,7 @@ export class ThemedConfigurationSearchPageComponent extends ThemedComponent<Conf
|
||||
context: Context;
|
||||
|
||||
protected inAndOutputNames: (keyof ConfigurationSearchPageComponent & keyof this)[] =
|
||||
['configuration', 'fixedFilterQuery', 'inPlaceSearch', 'searchEnabled', 'sideBarWidth', 'configuration$', 'context'];
|
||||
['context', 'configuration', 'fixedFilterQuery', 'inPlaceSearch', 'searchEnabled', 'sideBarWidth'];
|
||||
|
||||
protected getComponentName(): string {
|
||||
return 'ConfigurationSearchPageComponent';
|
||||
|
@@ -7,19 +7,19 @@ import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { DynamicFormControlModel, DynamicFormService, DynamicInputModel } from '@ng-dynamic-forms/core';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { AuthService } from '../../../core/auth/auth.service';
|
||||
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
|
||||
import { RequestService } from '../../../core/data/request.service';
|
||||
import { RestRequestMethod } from '../../../core/data/rest-request-method';
|
||||
import { Community } from '../../../core/shared/community.model';
|
||||
import { hasValue } from '../../empty.util';
|
||||
import { AuthServiceMock } from '../../mocks/auth.service.mock';
|
||||
import { NotificationsService } from '../../notifications/notifications.service';
|
||||
import { NotificationsServiceStub } from '../../testing/notifications-service.stub';
|
||||
import { VarDirective } from '../../utils/var.directive';
|
||||
import { AuthService } from '../../../../core/auth/auth.service';
|
||||
import { ObjectCacheService } from '../../../../core/cache/object-cache.service';
|
||||
import { RequestService } from '../../../../core/data/request.service';
|
||||
import { RestRequestMethod } from '../../../../core/data/rest-request-method';
|
||||
import { Community } from '../../../../core/shared/community.model';
|
||||
import { hasValue } from '../../../empty.util';
|
||||
import { AuthServiceMock } from '../../../mocks/auth.service.mock';
|
||||
import { NotificationsService } from '../../../notifications/notifications.service';
|
||||
import { NotificationsServiceStub } from '../../../testing/notifications-service.stub';
|
||||
import { VarDirective } from '../../../utils/var.directive';
|
||||
import { ComColFormComponent } from './comcol-form.component';
|
||||
import { Operation } from 'fast-json-patch';
|
||||
import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../remote-data.utils';
|
||||
import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../../remote-data.utils';
|
||||
|
||||
describe('ComColFormComponent', () => {
|
||||
let comp: ComColFormComponent<any>;
|
@@ -1,39 +1,27 @@
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import {
|
||||
DynamicFormControlModel,
|
||||
DynamicFormService,
|
||||
DynamicInputModel
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { DynamicFormControlModel, DynamicFormService, DynamicInputModel } from '@ng-dynamic-forms/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { FileUploader } from 'ng2-file-upload';
|
||||
import { BehaviorSubject, combineLatest as observableCombineLatest, Subscription } from 'rxjs';
|
||||
import { AuthService } from '../../../core/auth/auth.service';
|
||||
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
|
||||
import { ComColDataService } from '../../../core/data/comcol-data.service';
|
||||
import { RemoteData } from '../../../core/data/remote-data';
|
||||
import { RequestService } from '../../../core/data/request.service';
|
||||
import { RestRequestMethod } from '../../../core/data/rest-request-method';
|
||||
import { Bitstream } from '../../../core/shared/bitstream.model';
|
||||
import { Collection } from '../../../core/shared/collection.model';
|
||||
import { Community } from '../../../core/shared/community.model';
|
||||
import { MetadataMap, MetadataValue } from '../../../core/shared/metadata.models';
|
||||
import { ResourceType } from '../../../core/shared/resource-type';
|
||||
import { hasValue, isNotEmpty } from '../../empty.util';
|
||||
import { NotificationsService } from '../../notifications/notifications.service';
|
||||
import { UploaderOptions } from '../../uploader/uploader-options.model';
|
||||
import { UploaderComponent } from '../../uploader/uploader.component';
|
||||
import { AuthService } from '../../../../core/auth/auth.service';
|
||||
import { ObjectCacheService } from '../../../../core/cache/object-cache.service';
|
||||
import { ComColDataService } from '../../../../core/data/comcol-data.service';
|
||||
import { RemoteData } from '../../../../core/data/remote-data';
|
||||
import { RequestService } from '../../../../core/data/request.service';
|
||||
import { RestRequestMethod } from '../../../../core/data/rest-request-method';
|
||||
import { Bitstream } from '../../../../core/shared/bitstream.model';
|
||||
import { Collection } from '../../../../core/shared/collection.model';
|
||||
import { Community } from '../../../../core/shared/community.model';
|
||||
import { MetadataMap, MetadataValue } from '../../../../core/shared/metadata.models';
|
||||
import { ResourceType } from '../../../../core/shared/resource-type';
|
||||
import { hasValue, isNotEmpty } from '../../../empty.util';
|
||||
import { NotificationsService } from '../../../notifications/notifications.service';
|
||||
import { UploaderOptions } from '../../../uploader/uploader-options.model';
|
||||
import { UploaderComponent } from '../../../uploader/uploader.component';
|
||||
import { Operation } from 'fast-json-patch';
|
||||
import { NoContent } from '../../../core/shared/NoContent.model';
|
||||
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
|
||||
import { NoContent } from '../../../../core/shared/NoContent.model';
|
||||
import { getFirstCompletedRemoteData } from '../../../../core/shared/operators';
|
||||
|
||||
/**
|
||||
* A form for creating and editing Communities or Collections
|
@@ -1,20 +1,20 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { CommunityDataService } from '../../../core/data/community-data.service';
|
||||
import { RouteService } from '../../../core/services/route.service';
|
||||
import { CommunityDataService } from '../../../../core/data/community-data.service';
|
||||
import { RouteService } from '../../../../core/services/route.service';
|
||||
import { Router } from '@angular/router';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { Community } from '../../../core/shared/community.model';
|
||||
import { SharedModule } from '../../shared.module';
|
||||
import { Community } from '../../../../core/shared/community.model';
|
||||
import { SharedModule } from '../../../shared.module';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { CreateComColPageComponent } from './create-comcol-page.component';
|
||||
import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../remote-data.utils';
|
||||
import { ComColDataService } from '../../../core/data/comcol-data.service';
|
||||
import { NotificationsService } from '../../notifications/notifications.service';
|
||||
import { NotificationsServiceStub } from '../../testing/notifications-service.stub';
|
||||
import { RequestService } from '../../../core/data/request.service';
|
||||
import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../../remote-data.utils';
|
||||
import { ComColDataService } from '../../../../core/data/comcol-data.service';
|
||||
import { NotificationsService } from '../../../notifications/notifications.service';
|
||||
import { NotificationsServiceStub } from '../../../testing/notifications-service.stub';
|
||||
import { RequestService } from '../../../../core/data/request.service';
|
||||
import { getTestScheduler } from 'jasmine-marbles';
|
||||
|
||||
describe('CreateComColPageComponent', () => {
|
@@ -3,18 +3,18 @@ import { Router } from '@angular/router';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { mergeMap, take } from 'rxjs/operators';
|
||||
import { ComColDataService } from '../../../core/data/comcol-data.service';
|
||||
import { CommunityDataService } from '../../../core/data/community-data.service';
|
||||
import { RemoteData } from '../../../core/data/remote-data';
|
||||
import { RouteService } from '../../../core/services/route.service';
|
||||
import { Community } from '../../../core/shared/community.model';
|
||||
import { getFirstSucceededRemoteDataPayload, } from '../../../core/shared/operators';
|
||||
import { ResourceType } from '../../../core/shared/resource-type';
|
||||
import { hasValue, isNotEmpty, isNotUndefined } from '../../empty.util';
|
||||
import { NotificationsService } from '../../notifications/notifications.service';
|
||||
import { RequestParam } from '../../../core/cache/models/request-param.model';
|
||||
import { RequestService } from '../../../core/data/request.service';
|
||||
import { Collection } from '../../../core/shared/collection.model';
|
||||
import { ComColDataService } from '../../../../core/data/comcol-data.service';
|
||||
import { CommunityDataService } from '../../../../core/data/community-data.service';
|
||||
import { RemoteData } from '../../../../core/data/remote-data';
|
||||
import { RouteService } from '../../../../core/services/route.service';
|
||||
import { Community } from '../../../../core/shared/community.model';
|
||||
import { getFirstSucceededRemoteDataPayload, } from '../../../../core/shared/operators';
|
||||
import { ResourceType } from '../../../../core/shared/resource-type';
|
||||
import { hasValue, isNotEmpty, isNotUndefined } from '../../../empty.util';
|
||||
import { NotificationsService } from '../../../notifications/notifications.service';
|
||||
import { RequestParam } from '../../../../core/cache/models/request-param.model';
|
||||
import { RequestService } from '../../../../core/data/request.service';
|
||||
import { Collection } from '../../../../core/shared/collection.model';
|
||||
|
||||
/**
|
||||
* Component representing the create page for communities and collections
|
@@ -1,20 +1,20 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { CommunityDataService } from '../../../core/data/community-data.service';
|
||||
import { CommunityDataService } from '../../../../core/data/community-data.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { Community } from '../../../core/shared/community.model';
|
||||
import { SharedModule } from '../../shared.module';
|
||||
import { Community } from '../../../../core/shared/community.model';
|
||||
import { SharedModule } from '../../../shared.module';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { DeleteComColPageComponent } from './delete-comcol-page.component';
|
||||
import { NotificationsService } from '../../notifications/notifications.service';
|
||||
import { NotificationsServiceStub } from '../../testing/notifications-service.stub';
|
||||
import { RequestService } from '../../../core/data/request.service';
|
||||
import { NotificationsService } from '../../../notifications/notifications.service';
|
||||
import { NotificationsServiceStub } from '../../../testing/notifications-service.stub';
|
||||
import { RequestService } from '../../../../core/data/request.service';
|
||||
import { getTestScheduler } from 'jasmine-marbles';
|
||||
import { ComColDataService } from '../../../core/data/comcol-data.service';
|
||||
import { createFailedRemoteDataObject$, createNoContentRemoteDataObject$ } from '../../remote-data.utils';
|
||||
import { ComColDataService } from '../../../../core/data/comcol-data.service';
|
||||
import { createFailedRemoteDataObject$, createNoContentRemoteDataObject$ } from '../../../remote-data.utils';
|
||||
|
||||
describe('DeleteComColPageComponent', () => {
|
||||
let comp: DeleteComColPageComponent<any>;
|
@@ -1,16 +1,16 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { RemoteData } from '../../../core/data/remote-data';
|
||||
import { RemoteData } from '../../../../core/data/remote-data';
|
||||
import { first, map } from 'rxjs/operators';
|
||||
import { NotificationsService } from '../../notifications/notifications.service';
|
||||
import { NotificationsService } from '../../../notifications/notifications.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
|
||||
import { NoContent } from '../../../core/shared/NoContent.model';
|
||||
import { RequestService } from '../../../core/data/request.service';
|
||||
import { ComColDataService } from '../../../core/data/comcol-data.service';
|
||||
import { Community } from '../../../core/shared/community.model';
|
||||
import { Collection } from '../../../core/shared/collection.model';
|
||||
import { getFirstCompletedRemoteData } from '../../../../core/shared/operators';
|
||||
import { NoContent } from '../../../../core/shared/NoContent.model';
|
||||
import { RequestService } from '../../../../core/data/request.service';
|
||||
import { ComColDataService } from '../../../../core/data/comcol-data.service';
|
||||
import { Community } from '../../../../core/shared/community.model';
|
||||
import { Collection } from '../../../../core/shared/collection.model';
|
||||
|
||||
/**
|
||||
* Component representing the delete page for communities and collections
|
@@ -5,16 +5,16 @@ import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { ComColDataService } from '../../../../core/data/comcol-data.service';
|
||||
import { Community } from '../../../../core/shared/community.model';
|
||||
import { NotificationsService } from '../../../notifications/notifications.service';
|
||||
import { SharedModule } from '../../../shared.module';
|
||||
import { NotificationsServiceStub } from '../../../testing/notifications-service.stub';
|
||||
import { ComColDataService } from '../../../../../core/data/comcol-data.service';
|
||||
import { Community } from '../../../../../core/shared/community.model';
|
||||
import { NotificationsService } from '../../../../notifications/notifications.service';
|
||||
import { SharedModule } from '../../../../shared.module';
|
||||
import { NotificationsServiceStub } from '../../../../testing/notifications-service.stub';
|
||||
import {
|
||||
createFailedRemoteDataObject$,
|
||||
createSuccessfulRemoteDataObject,
|
||||
createSuccessfulRemoteDataObject$
|
||||
} from '../../../remote-data.utils';
|
||||
} from '../../../../remote-data.utils';
|
||||
import { ComcolMetadataComponent } from './comcol-metadata.component';
|
||||
|
||||
describe('ComColMetadataComponent', () => {
|
@@ -1,17 +1,17 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { DSpaceObject } from '../../../../core/shared/dspace-object.model';
|
||||
import { DSpaceObject } from '../../../../../core/shared/dspace-object.model';
|
||||
import { Observable } from 'rxjs';
|
||||
import { RemoteData } from '../../../../core/data/remote-data';
|
||||
import { RemoteData } from '../../../../../core/data/remote-data';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { first, map, take } from 'rxjs/operators';
|
||||
import { getFirstSucceededRemoteData, getFirstCompletedRemoteData } from '../../../../core/shared/operators';
|
||||
import { hasValue, isEmpty } from '../../../empty.util';
|
||||
import { ResourceType } from '../../../../core/shared/resource-type';
|
||||
import { ComColDataService } from '../../../../core/data/comcol-data.service';
|
||||
import { NotificationsService } from '../../../notifications/notifications.service';
|
||||
import { getFirstCompletedRemoteData, getFirstSucceededRemoteData } from '../../../../../core/shared/operators';
|
||||
import { hasValue, isEmpty } from '../../../../empty.util';
|
||||
import { ResourceType } from '../../../../../core/shared/resource-type';
|
||||
import { ComColDataService } from '../../../../../core/data/comcol-data.service';
|
||||
import { NotificationsService } from '../../../../notifications/notifications.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Community } from '../../../../core/shared/community.model';
|
||||
import { Collection } from '../../../../core/shared/collection.model';
|
||||
import { Community } from '../../../../../core/shared/community.model';
|
||||
import { Collection } from '../../../../../core/shared/collection.model';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-comcol-metadata',
|
@@ -1,15 +1,15 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { ComcolRoleComponent } from './comcol-role.component';
|
||||
import { GroupDataService } from '../../../../core/eperson/group-data.service';
|
||||
import { GroupDataService } from '../../../../../core/eperson/group-data.service';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { SharedModule } from '../../../shared.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { RequestService } from '../../../../core/data/request.service';
|
||||
import { RequestService } from '../../../../../core/data/request.service';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../../remote-data.utils';
|
||||
import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../../../remote-data.utils';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { ComcolModule } from '../../../comcol.module';
|
||||
|
||||
describe('ComcolRoleComponent', () => {
|
||||
|
||||
@@ -32,7 +32,7 @@ describe('ComcolRoleComponent', () => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
SharedModule,
|
||||
ComcolModule,
|
||||
RouterTestingModule.withRoutes([]),
|
||||
TranslateModule.forRoot(),
|
||||
NoopAnimationsModule
|
@@ -1,17 +1,17 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Group } from '../../../../core/eperson/models/group.model';
|
||||
import { Community } from '../../../../core/shared/community.model';
|
||||
import { Group } from '../../../../../core/eperson/models/group.model';
|
||||
import { Community } from '../../../../../core/shared/community.model';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { GroupDataService } from '../../../../core/eperson/group-data.service';
|
||||
import { Collection } from '../../../../core/shared/collection.model';
|
||||
import { GroupDataService } from '../../../../../core/eperson/group-data.service';
|
||||
import { Collection } from '../../../../../core/shared/collection.model';
|
||||
import { filter, map, switchMap } from 'rxjs/operators';
|
||||
import { getAllCompletedRemoteData, getFirstCompletedRemoteData } from '../../../../core/shared/operators';
|
||||
import { RequestService } from '../../../../core/data/request.service';
|
||||
import { RemoteData } from '../../../../core/data/remote-data';
|
||||
import { HALLink } from '../../../../core/shared/hal-link.model';
|
||||
import { getGroupEditRoute } from '../../../../access-control/access-control-routing-paths';
|
||||
import { hasNoValue, hasValue } from '../../../empty.util';
|
||||
import { NoContent } from '../../../../core/shared/NoContent.model';
|
||||
import { getAllCompletedRemoteData, getFirstCompletedRemoteData } from '../../../../../core/shared/operators';
|
||||
import { RequestService } from '../../../../../core/data/request.service';
|
||||
import { RemoteData } from '../../../../../core/data/remote-data';
|
||||
import { HALLink } from '../../../../../core/shared/hal-link.model';
|
||||
import { getGroupEditRoute } from '../../../../../access-control/access-control-routing-paths';
|
||||
import { hasNoValue, hasValue } from '../../../../empty.util';
|
||||
import { NoContent } from '../../../../../core/shared/NoContent.model';
|
||||
|
||||
/**
|
||||
* Component for managing a community or collection role.
|
@@ -2,12 +2,12 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { Community } from '../../../core/shared/community.model';
|
||||
import { SharedModule } from '../../shared.module';
|
||||
import { Community } from '../../../../core/shared/community.model';
|
||||
import { SharedModule } from '../../../shared.module';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||
import { DSpaceObject } from '../../../../core/shared/dspace-object.model';
|
||||
import { EditComColPageComponent } from './edit-comcol-page.component';
|
||||
|
||||
describe('EditComColPageComponent', () => {
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user