Merge pull request #1478 from 4Science/CST-4633-search-refactoring

MyDSpace Search component refactoring
This commit is contained in:
Tim Donohue
2022-01-20 11:41:06 -06:00
committed by GitHub
224 changed files with 2138 additions and 1951 deletions

View File

@@ -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');

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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()

View File

@@ -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: [

View File

@@ -24,7 +24,7 @@ const ENTRY_COMPONENTS = [
AccessControlModule,
AdminSearchModule.withEntryComponents(),
AdminWorkflowModuleModule.withEntryComponents(),
SharedModule,
SharedModule
],
declarations: [
AdminCurationTasksComponent,

View File

@@ -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,

View File

@@ -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: [

View File

@@ -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 {
/**

View File

@@ -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: [

View File

@@ -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,

View File

@@ -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';

View File

@@ -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';

View File

@@ -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,

View File

@@ -2,7 +2,7 @@ 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';

View File

@@ -1,6 +1,6 @@
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';

View File

@@ -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';

View File

@@ -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(),

View File

@@ -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';

View File

@@ -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,

View File

@@ -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> {
/**

View File

@@ -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: [

View File

@@ -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

View File

@@ -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';

View File

@@ -2,7 +2,7 @@ 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';

View File

@@ -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';

View File

@@ -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(),

View File

@@ -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';

View File

@@ -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,

View File

@@ -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';

View File

@@ -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';

View File

@@ -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 {

View File

@@ -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()

View File

@@ -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';

View File

@@ -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';

View File

@@ -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';

View File

@@ -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';

View File

@@ -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';

View File

@@ -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';

View File

@@ -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';

View File

@@ -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';

View File

@@ -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 = [];
}
/**

View File

@@ -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';

View File

@@ -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';

View File

@@ -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;
}

View File

@@ -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';

View File

@@ -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))

View File

@@ -3,8 +3,8 @@
*/
export enum ViewMode {
ListElement = 'listElement',
GridElement = 'gridElement',
DetailedListElement = 'detailedListElement',
StandalonePage = 'standalonePage',
ListElement = 'list',
GridElement = 'grid',
DetailedListElement = 'detailed',
StandalonePage = 'standalone',
}

View File

@@ -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: [

View File

@@ -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,

View File

@@ -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,

View File

@@ -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';

View File

@@ -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';

View File

@@ -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';

View File

@@ -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';

View File

@@ -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';

View 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 { }

View File

@@ -1,7 +1,6 @@
<ds-configuration-search-page
[fixedFilterQuery]="fixedFilter"
[configuration]="configuration"
[configuration$]="configuration$"
[searchEnabled]="searchEnabled"
[sideBarWidth]="sideBarWidth">
</ds-configuration-search-page>

View File

@@ -38,10 +38,4 @@ describe('RelatedEntitiesSearchComponent', () => {
expect(comp.fixedFilter).toEqual(mockFilter);
});
it('should create a configuration$', () => {
comp.configuration$.subscribe((configuration) => {
expect(configuration).toEqual(mockConfiguration);
});
});
});

View File

@@ -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);
}
}
}

View File

@@ -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
}
]
}));

View File

@@ -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;
})

View File

@@ -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';

View File

@@ -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"
</div>
<ds-search *ngIf="configuration && context"
[configuration]="configuration"
[configurationList]="(configurationList$ | async)"
[resultCount]="(resultsRD$ | async)?.payload?.totalElements"
[context]="context"
[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>

View File

@@ -1 +1 @@
@import '../search-page/search.component.scss';
@import '../shared/search/search.component';

View File

@@ -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();
});
});
});
});

View File

@@ -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();
}
}

View File

@@ -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()
],

View File

@@ -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>

View File

@@ -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();
});
});

View File

@@ -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';
}
}

View File

@@ -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,

View File

@@ -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);
});
});
});

View File

@@ -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'
});
}
}

View File

@@ -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';

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -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(),

View File

@@ -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';

View File

@@ -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>

View File

@@ -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();
});
});
});
});

View File

@@ -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();
}
}
}

View File

@@ -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';

View File

@@ -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>;

View File

@@ -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

View File

@@ -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', () => {

View File

@@ -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

View File

@@ -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>;

View File

@@ -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

View File

@@ -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', () => {

View File

@@ -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',

View File

@@ -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

View File

@@ -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.

View File

@@ -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