Merge remote-tracking branch 'dspace-main/main' into w2p-96062_theme-collection-dropdown-component

# Conflicts:
#	src/app/shared/shared.module.ts
This commit is contained in:
Jens Vannerum
2022-12-15 17:58:28 +01:00
157 changed files with 6495 additions and 547 deletions

View File

@@ -10,6 +10,16 @@ import { MembersListComponent } from './group-registry/group-form/members-list/m
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';
import { DYNAMIC_ERROR_MESSAGES_MATCHER, DynamicErrorMessagesMatcher } from '@ng-dynamic-forms/core';
import { AbstractControl } from '@angular/forms';
/**
* Condition for displaying error messages on email form field
*/
export const ValidateEmailErrorStateMatcher: DynamicErrorMessagesMatcher =
(control: AbstractControl, model: any, hasFocus: boolean) => {
return (control.touched && !hasFocus) || (control.errors?.emailTaken && hasFocus);
};
@NgModule({
imports: [
@@ -26,6 +36,12 @@ import { FormModule } from '../shared/form/form.module';
GroupFormComponent,
SubgroupsListComponent,
MembersListComponent
],
providers: [
{
provide: DYNAMIC_ERROR_MESSAGES_MATCHER,
useValue: ValidateEmailErrorStateMatcher
},
]
})
/**

View File

@@ -1,12 +1,8 @@
import { Location } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { Observable } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { AuthService } from '../../core/auth/auth.service';
import { METADATA_IMPORT_SCRIPT_NAME, ScriptDataService } from '../../core/data/processes/script-data.service';
import { EPerson } from '../../core/eperson/models/eperson.model';
import { ProcessParameter } from '../../process-page/processes/process-parameter.model';
import { isNotEmpty } from '../../shared/empty.util';
import { NotificationsService } from '../../shared/notifications/notifications.service';

View File

@@ -1,12 +1,11 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import {combineLatest, combineLatest as observableCombineLatest, Observable, of as observableOf, zip} from 'rxjs';
import { combineLatest as observableCombineLatest, Observable} from 'rxjs';
import { RemoteData } from '../../../core/data/remote-data';
import { PaginatedList } from '../../../core/data/paginated-list.model';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
import { BitstreamFormat } from '../../../core/shared/bitstream-format.model';
import { BitstreamFormatDataService } from '../../../core/data/bitstream-format-data.service';
import { map, mergeMap, switchMap, take, toArray } from 'rxjs/operators';
import { hasValue } from '../../../shared/empty.util';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';

View File

@@ -19,10 +19,7 @@ import { RestResponse } from '../../../core/cache/response.models';
import { MetadataSchema } from '../../../core/metadata/metadata-schema.model';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { PaginationService } from '../../../core/pagination/pagination.service';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model';
import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub';
import { FindListOptions } from '../../../core/data/find-list-options.model';
describe('MetadataRegistryComponent', () => {
let comp: MetadataRegistryComponent;

View File

@@ -23,11 +23,8 @@ import { MetadataSchema } from '../../../core/metadata/metadata-schema.model';
import { MetadataField } from '../../../core/metadata/metadata-field.model';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { VarDirective } from '../../../shared/utils/var.directive';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model';
import { PaginationService } from '../../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub';
import { FindListOptions } from '../../../core/data/find-list-options.model';
describe('MetadataSchemaComponent', () => {
let comp: MetadataSchemaComponent;

View File

@@ -16,7 +16,6 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { RouterTestingModule } from '@angular/router/testing';
import { ActivatedRoute } from '@angular/router';
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
import createSpy = jasmine.createSpy;
import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils';
import { Item } from '../../core/shared/item.model';

View File

@@ -10,6 +10,7 @@ import { AdminSearchModule } from './admin-search-page/admin-search.module';
import { AdminSidebarSectionComponent } from './admin-sidebar/admin-sidebar-section/admin-sidebar-section.component';
import { ExpandableAdminSidebarSectionComponent } from './admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component';
import { BatchImportPageComponent } from './admin-import-batch-page/batch-import-page.component';
import { UploadModule } from '../shared/upload/upload.module';
const ENTRY_COMPONENTS = [
// put only entry components that use custom decorator
@@ -25,7 +26,8 @@ const ENTRY_COMPONENTS = [
AccessControlModule,
AdminSearchModule.withEntryComponents(),
AdminWorkflowModuleModule.withEntryComponents(),
SharedModule
SharedModule,
UploadModule,
],
declarations: [
AdminCurationTasksComponent,

View File

@@ -31,7 +31,6 @@ import { models } from './core/core.module';
import { ThemeService } from './shared/theme-support/theme.service';
import { IdleModalComponent } from './shared/idle-modal/idle-modal.component';
import { distinctNext } from './core/shared/distinct-next';
import { ModalBeforeDismiss } from './shared/interfaces/modal-before-dismiss.interface';
@Component({
selector: 'ds-app',

View File

@@ -1,14 +1,12 @@
import { APP_BASE_HREF, CommonModule, DOCUMENT } from '@angular/common';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { AbstractControl } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { EffectsModule } from '@ngrx/effects';
import { RouterStateSerializer, StoreRouterConnectingModule } from '@ngrx/router-store';
import { MetaReducer, StoreModule, USER_PROVIDED_META_REDUCERS } from '@ngrx/store';
import { DYNAMIC_ERROR_MESSAGES_MATCHER, DYNAMIC_MATCHER_PROVIDERS, DynamicErrorMessagesMatcher } from '@ng-dynamic-forms/core';
import { TranslateModule } from '@ngx-translate/core';
import { ScrollToModule } from '@nicky-lenaers/ngx-scroll-to';
import { AppRoutingModule } from './app-routing.module';
@@ -28,7 +26,6 @@ import { XsrfInterceptor } from './core/xsrf/xsrf.interceptor';
import { LogInterceptor } from './core/log/log.interceptor';
import { EagerThemesModule } from '../themes/eager-themes.module';
import { APP_CONFIG, AppConfig } from '../config/app-config.interface';
import { NgxMaskModule } from 'ngx-mask';
import { StoreDevModules } from '../config/store/devtools';
import { RootModule } from './root.module';
@@ -46,14 +43,6 @@ export function getMetaReducers(appConfig: AppConfig): MetaReducer<AppState>[] {
return appConfig.debug ? [...appMetaReducers, ...debugMetaReducers] : appMetaReducers;
}
/**
* Condition for displaying error messages on email form field
*/
export const ValidateEmailErrorStateMatcher: DynamicErrorMessagesMatcher =
(control: AbstractControl, model: any, hasFocus: boolean) => {
return (control.touched && !hasFocus) || (control.errors?.emailTaken && hasFocus);
};
const IMPORTS = [
CommonModule,
SharedModule,
@@ -64,7 +53,6 @@ const IMPORTS = [
ScrollToModule.forRoot(),
NgbModule,
TranslateModule.forRoot(),
NgxMaskModule.forRoot(),
EffectsModule.forRoot(appEffects),
StoreModule.forRoot(appReducers, storeModuleConfig),
StoreRouterConnectingModule.forRoot(),
@@ -113,11 +101,6 @@ const PROVIDERS = [
useClass: LogInterceptor,
multi: true
},
{
provide: DYNAMIC_ERROR_MESSAGES_MATCHER,
useValue: ValidateEmailErrorStateMatcher
},
...DYNAMIC_MATCHER_PROVIDERS,
];
const DECLARATIONS = [

View File

@@ -1,5 +1,5 @@
import { LegacyBitstreamUrlResolver } from './legacy-bitstream-url.resolver';
import { of as observableOf, EMPTY } from 'rxjs';
import { EMPTY } from 'rxjs';
import { BitstreamDataService } from '../core/data/bitstream-data.service';
import { RemoteData } from '../core/data/remote-data';
import { TestScheduler } from 'rxjs/testing';

View File

@@ -1,7 +1,6 @@
import { first } from 'rxjs/operators';
import { BrowseByGuard } from './browse-by-guard';
import { of as observableOf } from 'rxjs';
import { BrowseDefinitionDataService } from '../core/browse/browse-definition-data.service';
import { createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils';
import { BrowseDefinition } from '../core/shared/browse-definition.model';
import { BrowseByDataType } from './browse-by-switcher/browse-by-decorator';

View File

@@ -16,7 +16,7 @@ import { Collection } from '../../core/shared/collection.model';
import { RemoteData } from '../../core/data/remote-data';
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
import { ChangeDetectionStrategy, EventEmitter } from '@angular/core';
import { EventEmitter } from '@angular/core';
import { HostWindowService } from '../../shared/host-window.service';
import { HostWindowServiceStub } from '../../shared/testing/host-window-service.stub';
import { By } from '@angular/platform-browser';
@@ -41,7 +41,7 @@ import {
} from '../../shared/remote-data.utils';
import { createPaginatedList } from '../../shared/testing/utils.test';
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
import { MyDSpacePageComponent, SEARCH_CONFIG_SERVICE } from '../../my-dspace-page/my-dspace-page.component';
import { SEARCH_CONFIG_SERVICE } from '../../my-dspace-page/my-dspace-page.component';
import { SearchConfigurationServiceStub } from '../../shared/testing/search-configuration-service.stub';
import { GroupDataService } from '../../core/eperson/group-data.service';
import { LinkHeadService } from '../../core/services/link-head.service';

View File

@@ -25,7 +25,7 @@ import { ComcolModule } from '../shared/comcol/comcol.module';
StatisticsModule.forRoot(),
EditItemPageModule,
CollectionFormModule,
ComcolModule
ComcolModule,
],
declarations: [
CollectionPageComponent,
@@ -38,7 +38,7 @@ import { ComcolModule } from '../shared/comcol/comcol.module';
],
providers: [
SearchService,
]
],
})
export class CollectionPageModule {

View File

@@ -8,8 +8,7 @@ import {
DynamicInputModel,
DynamicOptionControlModel,
DynamicRadioGroupModel,
DynamicSelectModel,
DynamicTextAreaModel
DynamicSelectModel
} from '@ng-dynamic-forms/core';
import { Location } from '@angular/common';
import { TranslateService } from '@ngx-translate/core';

View File

@@ -25,7 +25,7 @@ import { ComcolModule } from '../../shared/comcol/comcol.module';
CollectionFormModule,
ResourcePoliciesModule,
FormModule,
ComcolModule
ComcolModule,
],
declarations: [
EditCollectionPageComponent,

View File

@@ -36,7 +36,7 @@ const DECLARATIONS = [CommunityPageComponent,
CommunityPageRoutingModule,
StatisticsModule.forRoot(),
CommunityFormModule,
ComcolModule
ComcolModule,
],
declarations: [
...DECLARATIONS

View File

@@ -21,7 +21,7 @@ import { ComcolModule } from '../../shared/comcol/comcol.module';
EditCommunityPageRoutingModule,
CommunityFormModule,
ComcolModule,
ResourcePoliciesModule
ResourcePoliciesModule,
],
declarations: [
EditCommunityPageComponent,

View File

@@ -17,9 +17,6 @@ import { PageInfo } from '../../core/shared/page-info.model';
import { HostWindowService } from '../../shared/host-window.service';
import { HostWindowServiceStub } from '../../shared/testing/host-window-service.stub';
import { SelectableListService } from '../../shared/object-list/selectable-list/selectable-list.service';
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 { getMockThemeService } from '../../shared/mocks/theme-service.mock';
import { ThemeService } from '../../shared/theme-support/theme.service';
@@ -29,7 +26,6 @@ import { GroupDataService } from '../../core/eperson/group-data.service';
import { LinkHeadService } from '../../core/services/link-head.service';
import { ConfigurationDataService } from '../../core/data/configuration-data.service';
import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service';
import { SearchServiceStub } from '../../shared/testing/search-service.stub';
import { ConfigurationProperty } from '../../core/shared/configuration-property.model';
import { createPaginatedList } from '../../shared/testing/utils.test';
import { SearchConfigurationServiceStub } from '../../shared/testing/search-configuration-service.stub';

View File

@@ -17,9 +17,6 @@ import { HostWindowService } from '../../shared/host-window.service';
import { HostWindowServiceStub } from '../../shared/testing/host-window-service.stub';
import { CommunityDataService } from '../../core/data/community-data.service';
import { SelectableListService } from '../../shared/object-list/selectable-list/selectable-list.service';
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 { getMockThemeService } from '../../shared/mocks/theme-service.mock';
import { ThemeService } from '../../shared/theme-support/theme.service';

View File

@@ -7,7 +7,6 @@ import { createSelector } from '@ngrx/store';
* notation packages up all of the exports into a single object.
*/
import { AuthState } from './auth.reducer';
import { AppState } from '../../app.reducer';
import { CoreState } from '../core-state.model';
import { coreSelector } from '../core.selectors';

View File

@@ -2,15 +2,12 @@ import { CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';
import { DynamicFormLayoutService, DynamicFormService, DynamicFormValidationService } from '@ng-dynamic-forms/core';
import { EffectsModule } from '@ngrx/effects';
import { Action, StoreConfig, StoreModule } from '@ngrx/store';
import { MyDSpaceGuard } from '../my-dspace-page/my-dspace.guard';
import { isNotEmpty } from '../shared/empty.util';
import { FormBuilderService } from '../shared/form/builder/form-builder.service';
import { FormService } from '../shared/form/form.service';
import { HostWindowService } from '../shared/host-window.service';
import { MenuService } from '../shared/menu/menu.service';
import { EndpointMockingRestService } from '../shared/mocks/dspace-rest/endpoint-mocking-rest.service';
@@ -24,8 +21,6 @@ import { SelectableListService } from '../shared/object-list/selectable-list/sel
import { ObjectSelectService } from '../shared/object-select/object-select.service';
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
import { SidebarService } from '../shared/sidebar/sidebar.service';
import { UploaderService } from '../shared/uploader/uploader.service';
import { SectionFormOperationsService } from '../submission/sections/form/section-form-operations.service';
import { AuthenticatedGuard } from './auth/authenticated.guard';
import { AuthStatus } from './auth/models/auth-status.model';
import { BrowseService } from './browse/browse.service';
@@ -137,9 +132,6 @@ import {
import { Registration } from './shared/registration.model';
import { MetadataSchemaDataService } from './data/metadata-schema-data.service';
import { MetadataFieldDataService } from './data/metadata-field-data.service';
import {
DsDynamicTypeBindRelationService
} from '../shared/form/builder/ds-dynamic-form-ui/ds-dynamic-type-bind-relation.service';
import { TokenResponseParsingService } from './auth/token-response-parsing.service';
import { SubmissionCcLicenseDataService } from './submission/submission-cc-license-data.service';
import { SubmissionCcLicence } from './submission/models/submission-cc-license.model';
@@ -149,7 +141,6 @@ import { VocabularyEntry } from './submission/vocabularies/models/vocabulary-ent
import { Vocabulary } from './submission/vocabularies/models/vocabulary.model';
import { VocabularyEntryDetail } from './submission/vocabularies/models/vocabulary-entry-detail.model';
import { VocabularyService } from './submission/vocabularies/vocabulary.service';
import { VocabularyTreeviewService } from '../shared/vocabulary-treeview/vocabulary-treeview.service';
import { ConfigurationDataService } from './data/configuration-data.service';
import { ConfigurationProperty } from './shared/configuration-property.model';
import { ReloadGuard } from './reload/reload.guard';
@@ -210,12 +201,6 @@ const PROVIDERS = [
DSOResponseParsingService,
{ provide: MOCK_RESPONSE_MAP, useValue: mockResponseMap },
{ provide: DspaceRestService, useFactory: restServiceFactory, deps: [MOCK_RESPONSE_MAP, HttpClient] },
DynamicFormLayoutService,
DynamicFormService,
DynamicFormValidationService,
FormBuilderService,
SectionFormOperationsService,
FormService,
EPersonDataService,
LinkHeadService,
HALEndpointService,
@@ -244,12 +229,10 @@ const PROVIDERS = [
SubmissionResponseParsingService,
SubmissionJsonPatchOperationsService,
JsonPatchOperationsBuilder,
UploaderService,
UUIDService,
NotificationsService,
WorkspaceitemDataService,
WorkflowItemDataService,
UploaderService,
DSpaceObjectDataService,
ConfigurationDataService,
DSOChangeAnalyzer,
@@ -266,7 +249,6 @@ const PROVIDERS = [
ClaimedTaskDataService,
PoolTaskDataService,
BitstreamDataService,
DsDynamicTypeBindRelationService,
EntityTypeDataService,
ContentSourceResponseParsingService,
ItemTemplateDataService,
@@ -302,7 +284,6 @@ const PROVIDERS = [
VocabularyService,
VocabularyDataService,
VocabularyEntryDetailsDataService,
VocabularyTreeviewService,
SequenceService,
GroupDataService,
FeedbackDataService,

View File

@@ -1,7 +1,17 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
import { Injectable } from '@angular/core';
@Injectable()
export class UploaderService {
@Injectable({
providedIn: 'root'
})
export class DragService {
private _overrideDragOverPage = false;
public overrideDragOverPage() {

View File

@@ -3,7 +3,7 @@ import { getMockRequestService } from '../../shared/mocks/request.service.mock';
import { RequestService } from '../data/request.service';
import { HALEndpointService } from './hal-endpoint.service';
import { EndpointMapRequest } from '../data/request.models';
import { combineLatest as observableCombineLatest, Observable, of as observableOf } from 'rxjs';
import { combineLatest as observableCombineLatest, of as observableOf } from 'rxjs';
import { environment } from '../../../environments/environment';
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';

View File

@@ -3,7 +3,6 @@ import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
import { Injectable, OnDestroy } from '@angular/core';
import { map, switchMap, take } from 'rxjs/operators';
import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
import { PaginatedList } from '../../data/paginated-list.model';
import { ResponseParsingService } from '../../data/parsing.service';
import { RemoteData } from '../../data/remote-data';
import { GetRequest } from '../../data/request.models';

View File

@@ -1,7 +1,7 @@
import { CorrelationIdService } from './correlation-id.service';
import { CookieServiceMock } from '../shared/mocks/cookie.service.mock';
import { UUIDService } from '../core/shared/uuid.service';
import { MockStore, provideMockStore } from '@ngrx/store/testing';
import { MockStore } from '@ngrx/store/testing';
import { TestBed } from '@angular/core/testing';
import { Store, StoreModule } from '@ngrx/store';
import { appReducers, AppState, storeModuleConfig } from '../app.reducer';

View File

@@ -5,7 +5,7 @@ import { getFirstCompletedRemoteData } from '../core/shared/operators';
import { find, map } from 'rxjs/operators';
import { NotificationsService } from '../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
import { hasValue, isEmpty, isNotEmpty, hasNoValue } from '../shared/empty.util';
import { hasValue, isEmpty, isNotEmpty } from '../shared/empty.util';
import { RemoteData } from '../core/data/remote-data';
import { Router } from '@angular/router';
import { ProcessDataService } from '../core/data/processes/process-data.service';

View File

@@ -17,9 +17,6 @@ import { HostWindowService } from '../../shared/host-window.service';
import { HostWindowServiceStub } from '../../shared/testing/host-window-service.stub';
import { CommunityDataService } from '../../core/data/community-data.service';
import { SelectableListService } from '../../shared/object-list/selectable-list/selectable-list.service';
import { of as observableOf } from 'rxjs';
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
import { PaginationService } from '../../core/pagination/pagination.service';
import { getMockThemeService } from '../../shared/mocks/theme-service.mock';
import { ThemeService } from '../../shared/theme-support/theme.service';

View File

@@ -4,7 +4,7 @@ import { RemoteData } from '../../../core/data/remote-data';
import { Item } from '../../../core/shared/item.model';
import { map, take, switchMap } from 'rxjs/operators';
import { ActivatedRoute, Router } from '@angular/router';
import { UploaderOptions } from '../../../shared/uploader/uploader-options.model';
import { UploaderOptions } from '../../../shared/upload/uploader/uploader-options.model';
import { hasValue, isEmpty, isNotEmpty } from '../../../shared/empty.util';
import { ItemDataService } from '../../../core/data/item-data.service';
import { AuthService } from '../../../core/auth/auth.service';
@@ -14,7 +14,7 @@ import { PaginatedList } from '../../../core/data/paginated-list.model';
import { Bundle } from '../../../core/shared/bundle.model';
import { BundleDataService } from '../../../core/data/bundle-data.service';
import { getFirstSucceededRemoteDataPayload, getFirstCompletedRemoteData } from '../../../core/shared/operators';
import { UploaderComponent } from '../../../shared/uploader/uploader.component';
import { UploaderComponent } from '../../../shared/upload/uploader/uploader.component';
import { RequestService } from '../../../core/data/request.service';
import { getBitstreamModuleRoute } from '../../../app-routing-paths';
import { getEntityEditRoute } from '../../item-page-routing-paths';

View File

@@ -1,12 +1,11 @@
import { Observable } from 'rxjs/internal/Observable';
import { waitForAsync, ComponentFixture, inject, TestBed } from '@angular/core/testing';
import { Component, NO_ERRORS_SCHEMA } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { of as observableOf, of } from 'rxjs';
import { of as observableOf } from 'rxjs';
import { TranslateModule } from '@ngx-translate/core';
import { cold } from 'jasmine-marbles';
import { ItemAuthorizationsComponent, BitstreamMapValue } from './item-authorizations.component';
import { ItemAuthorizationsComponent } from './item-authorizations.component';
import { Bitstream } from '../../../core/shared/bitstream.model';
import { Bundle } from '../../../core/shared/bundle.model';
import { Item } from '../../../core/shared/item.model';
@@ -14,8 +13,6 @@ import { LinkService } from '../../../core/cache/builders/link.service';
import { getMockLinkService } from '../../../shared/mocks/link-service.mock';
import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { createPaginatedList, createTestComponent } from '../../../shared/testing/utils.test';
import { PaginatedList, buildPaginatedList } from '../../../core/data/paginated-list.model';
import { PageInfo } from '../../../core/shared/page-info.model';
describe('ItemAuthorizationsComponent test suite', () => {
let comp: ItemAuthorizationsComponent;

View File

@@ -17,10 +17,7 @@ import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote-
import { createPaginatedList } from '../../../../../shared/testing/utils.test';
import { RequestService } from '../../../../../core/data/request.service';
import { PaginationService } from '../../../../../core/pagination/pagination.service';
import { PaginationComponentOptions } from '../../../../../shared/pagination/pagination-component-options.model';
import { SortDirection, SortOptions } from '../../../../../core/cache/models/sort-options.model';
import { PaginationServiceStub } from '../../../../../shared/testing/pagination-service.stub';
import { FindListOptions } from '../../../../../core/data/find-list-options.model';
describe('PaginatedDragAndDropBitstreamListComponent', () => {
let comp: PaginatedDragAndDropBitstreamListComponent;

View File

@@ -16,11 +16,10 @@ import { MockBitstreamFormat1 } from '../../../../shared/mocks/item.mock';
import { By } from '@angular/platform-browser';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
import { PaginationComponentOptions } from '../../../../shared/pagination/pagination-component-options.model';
import { SortDirection, SortOptions } from '../../../../core/cache/models/sort-options.model';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../../../shared/testing/pagination-service.stub';
import { FindListOptions } from '../../../../core/data/find-list-options.model';
import { APP_CONFIG } from 'src/config/app-config.interface';
import { environment } from 'src/environments/environment';
describe('FullFileSectionComponent', () => {
let comp: FullFileSectionComponent;
@@ -72,7 +71,8 @@ describe('FullFileSectionComponent', () => {
providers: [
{ provide: BitstreamDataService, useValue: bitstreamDataService },
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
{ provide: PaginationService, useValue: paginationService }
{ provide: PaginationService, useValue: paginationService },
{ provide: APP_CONFIG, useValue: environment },
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, Inject, Input, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
@@ -14,6 +14,7 @@ import { NotificationsService } from '../../../../shared/notifications/notificat
import { TranslateService } from '@ngx-translate/core';
import { hasValue, isEmpty } from '../../../../shared/empty.util';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { AppConfig, APP_CONFIG } from 'src/config/app-config.interface';
/**
* This component renders the file section of the item
@@ -34,26 +35,26 @@ export class FullFileSectionComponent extends FileSectionComponent implements On
originals$: Observable<RemoteData<PaginatedList<Bitstream>>>;
licenses$: Observable<RemoteData<PaginatedList<Bitstream>>>;
pageSize = 5;
originalOptions = Object.assign(new PaginationComponentOptions(), {
id: 'obo',
currentPage: 1,
pageSize: this.pageSize
pageSize: this.appConfig.item.bitstream.pageSize
});
licenseOptions = Object.assign(new PaginationComponentOptions(), {
id: 'lbo',
currentPage: 1,
pageSize: this.pageSize
pageSize: this.appConfig.item.bitstream.pageSize
});
constructor(
bitstreamDataService: BitstreamDataService,
protected notificationsService: NotificationsService,
protected translateService: TranslateService,
protected paginationService: PaginationService
protected paginationService: PaginationService,
@Inject(APP_CONFIG) protected appConfig: AppConfig
) {
super(bitstreamDataService, notificationsService, translateService);
super(bitstreamDataService, notificationsService, translateService, appConfig);
}
ngOnInit(): void {

View File

@@ -46,6 +46,7 @@ import { OrcidPageComponent } from './orcid-page/orcid-page.component';
import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap';
import { OrcidSyncSettingsComponent } from './orcid-page/orcid-sync-settings/orcid-sync-settings.component';
import { OrcidQueueComponent } from './orcid-page/orcid-queue/orcid-queue.component';
import { UploadModule } from '../shared/upload/upload.module';
const ENTRY_COMPONENTS = [
@@ -94,7 +95,8 @@ const DECLARATIONS = [
JournalEntitiesModule.withEntryComponents(),
ResearchEntitiesModule.withEntryComponents(),
NgxGalleryModule,
NgbAccordionModule
NgbAccordionModule,
UploadModule,
],
declarations: [
...DECLARATIONS,

View File

@@ -17,6 +17,8 @@ import { MetadataFieldWrapperComponent } from '../../../field-components/metadat
import { createPaginatedList } from '../../../../shared/testing/utils.test';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
import { APP_CONFIG } from 'src/config/app-config.interface';
import { environment } from 'src/environments/environment';
describe('FileSectionComponent', () => {
let comp: FileSectionComponent;
@@ -65,7 +67,8 @@ describe('FileSectionComponent', () => {
declarations: [FileSectionComponent, VarDirective, FileSizePipe, MetadataFieldWrapperComponent],
providers: [
{ provide: BitstreamDataService, useValue: bitstreamDataService },
{ provide: NotificationsService, useValue: new NotificationsServiceStub() }
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
{ provide: APP_CONFIG, useValue: environment }
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, Inject, Input, OnInit } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
@@ -10,6 +10,7 @@ import { PaginatedList } from '../../../../core/data/paginated-list.model';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
import { getFirstCompletedRemoteData } from '../../../../core/shared/operators';
import { AppConfig, APP_CONFIG } from 'src/config/app-config.interface';
/**
* This component renders the file section of the item
@@ -35,13 +36,15 @@ export class FileSectionComponent implements OnInit {
isLastPage: boolean;
pageSize = 5;
pageSize: number;
constructor(
protected bitstreamDataService: BitstreamDataService,
protected notificationsService: NotificationsService,
protected translateService: TranslateService
protected translateService: TranslateService,
@Inject(APP_CONFIG) protected appConfig: AppConfig
) {
this.pageSize = this.appConfig.item.bitstream.pageSize;
}
ngOnInit(): void {

View File

@@ -28,7 +28,6 @@ import { TruncatableService } from '../../../../shared/truncatable/truncatable.s
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { GenericItemPageFieldComponent } from '../../field-components/specific-field/generic/generic-item-page-field.component';
import { compareArraysUsing, compareArraysUsingIds } from './item-relationships-utils';
import { ItemComponent } from './item.component';
import { createPaginatedList } from '../../../../shared/testing/utils.test';
import { RouteService } from '../../../../core/services/route.service';
import { MetadataValue } from '../../../../core/shared/metadata.models';

View File

@@ -11,10 +11,6 @@ import { cold, hot } from 'jasmine-marbles';
import { MyDSpaceConfigurationValueType } from './my-dspace-configuration-value-type';
import { PaginationServiceStub } from '../shared/testing/pagination-service.stub';
import { Context } from '../core/shared/context.model';
import { LinkService } from '../core/cache/builders/link.service';
import { HALEndpointService } from '../core/shared/hal-endpoint.service';
import { RequestService } from '../core/data/request.service';
import { RemoteDataBuildService } from '../core/cache/builders/remote-data-build.service';
import { HALEndpointServiceStub } from '../shared/testing/hal-endpoint-service.stub';
import { getMockRemoteDataBuildService } from '../shared/mocks/remote-data-build.service.mock';

View File

@@ -16,10 +16,10 @@ import { TranslateLoaderMock } from '../../shared/mocks/translate-loader.mock';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
import { getMockScrollToService } from '../../shared/mocks/scroll-to-service.mock';
import { UploaderService } from '../../shared/uploader/uploader.service';
import { DragService } from '../../core/drag.service';
import { HostWindowService } from '../../shared/host-window.service';
import { HostWindowServiceStub } from '../../shared/testing/host-window-service.stub';
import { UploaderComponent } from '../../shared/uploader/uploader.component';
import { UploaderComponent } from '../../shared/upload/uploader/uploader.component';
import { HttpXsrfTokenExtractor } from '@angular/common/http';
import { CookieService } from '../../core/services/cookie.service';
import { CookieServiceMock } from '../../shared/mocks/cookie.service.mock';
@@ -59,7 +59,7 @@ describe('MyDSpaceNewSubmissionComponent test', () => {
NgbModal,
ChangeDetectorRef,
MyDSpaceNewSubmissionComponent,
UploaderService,
DragService,
{ provide: HttpXsrfTokenExtractor, useValue: new HttpXsrfTokenExtractorMock('mock-token') },
{ provide: CookieService, useValue: new CookieServiceMock() },
{ provide: HostWindowService, useValue: new HostWindowServiceStub(800) },

View File

@@ -8,13 +8,13 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { AuthService } from '../../core/auth/auth.service';
import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { UploaderOptions } from '../../shared/uploader/uploader-options.model';
import { UploaderOptions } from '../../shared/upload/uploader/uploader-options.model';
import { HALEndpointService } from '../../core/shared/hal-endpoint.service';
import { hasValue } from '../../shared/empty.util';
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';
import { UploaderComponent } from '../../shared/upload/uploader/uploader.component';
import { UploaderError } from '../../shared/upload/uploader/uploader-error.model';
import { Router } from '@angular/router';
/**

View File

@@ -14,6 +14,7 @@ import { MyDSpaceNewSubmissionDropdownComponent } from './my-dspace-new-submissi
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';
import { UploadModule } from '../shared/upload/upload.module';
const DECLARATIONS = [
MyDSpacePageComponent,
@@ -30,7 +31,8 @@ const DECLARATIONS = [
SharedModule,
SearchModule,
MyDspacePageRoutingModule,
MyDspaceSearchModule.withEntryComponents()
MyDspaceSearchModule.withEntryComponents(),
UploadModule,
],
declarations: DECLARATIONS,
providers: [

View File

@@ -21,6 +21,7 @@ const effects = [
const ENTRY_COMPONENTS = [
// put only entry components that use custom decorator
NavbarSectionComponent,
ExpandableNavbarSectionComponent,
ThemedExpandableNavbarSectionComponent,
];
@@ -34,11 +35,9 @@ const ENTRY_COMPONENTS = [
CoreModule.forRoot()
],
declarations: [
...ENTRY_COMPONENTS,
NavbarComponent,
ThemedNavbarComponent,
NavbarSectionComponent,
ExpandableNavbarSectionComponent,
ThemedExpandableNavbarSectionComponent,
],
providers: [],
exports: [

View File

@@ -15,7 +15,6 @@ import {
} from '@angular/core/testing';
import { VarDirective } from '../../shared/utils/var.directive';
import { TranslateModule } from '@ngx-translate/core';
import { RouterTestingModule } from '@angular/router/testing';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ProcessDetailFieldComponent } from './process-detail-field/process-detail-field.component';
import { Process } from '../processes/process.model';

View File

@@ -95,6 +95,10 @@ describe('RegisterEmailComponent', () => {
comp.form.patchValue({email: 'valid@email.org'});
expect(comp.form.invalid).toBeFalse();
});
it('should be valid when uppercase letters are used', () => {
comp.form.patchValue({email: 'VALID@email.org'});
expect(comp.form.invalid).toBeFalse();
});
});
describe('register', () => {
it('should send a registration to the service and on success display a message and return to home', () => {

View File

@@ -79,7 +79,9 @@ export class RegisterEmailFormComponent implements OnInit {
this.form = this.formBuilder.group({
email: new FormControl('', {
validators: [Validators.required,
Validators.pattern('^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$')
// Regex pattern borrowed from HTML5 specs for a valid email address:
// https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address
Validators.pattern('^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$')
],
})
});

View File

@@ -2,7 +2,6 @@ import { RegistrationGuard } from './registration.guard';
import { EpersonRegistrationService } from '../core/data/eperson-registration.service';
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
import { AuthService } from '../core/auth/auth.service';
import { Location } from '@angular/common';
import {
createFailedRemoteDataObject$,
createSuccessfulRemoteDataObject,

View File

@@ -17,8 +17,8 @@ import { MetadataMap, MetadataValue } from '../../../../core/shared/metadata.mod
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 { UploaderOptions } from '../../../upload/uploader/uploader-options.model';
import { UploaderComponent } from '../../../upload/uploader/uploader.component';
import { Operation } from 'fast-json-patch';
import { NoContent } from '../../../../core/shared/NoContent.model';
import { getFirstCompletedRemoteData } from '../../../../core/shared/operators';

View File

@@ -11,7 +11,6 @@ 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 { getTestScheduler } from 'jasmine-marbles';
import { ComColDataService } from '../../../../core/data/comcol-data.service';
import { createFailedRemoteDataObject$, createNoContentRemoteDataObject$ } from '../../../remote-data.utils';

View File

@@ -15,6 +15,7 @@ import { ThemedComcolPageBrowseByComponent } from './comcol-page-browse-by/theme
import { ComcolRoleComponent } from './comcol-forms/edit-comcol-page/comcol-role/comcol-role.component';
import { SharedModule } from '../shared.module';
import { FormModule } from '../form/form.module';
import { UploadModule } from '../upload/upload.module';
const COMPONENTS = [
ComcolPageContentComponent,
@@ -28,9 +29,7 @@ const COMPONENTS = [
ComcolPageBrowseByComponent,
ThemedComcolPageBrowseByComponent,
ComcolRoleComponent,
ThemedComcolPageHandleComponent
];
@NgModule({
@@ -40,10 +39,12 @@ const COMPONENTS = [
imports: [
CommonModule,
FormModule,
SharedModule
SharedModule,
UploadModule,
],
exports: [
...COMPONENTS
...COMPONENTS,
UploadModule,
]
})
export class ComcolModule { }

View File

@@ -1,5 +1,4 @@
import { Injectable } from '@angular/core';
import { setup, show } from 'klaro/dist/klaro-no-translations';
import { Inject, Injectable, InjectionToken } from '@angular/core';
import { combineLatest as observableCombineLatest, Observable, of as observableOf } from 'rxjs';
import { AuthService } from '../../core/auth/auth.service';
import { TranslateService } from '@ngx-translate/core';
@@ -43,6 +42,17 @@ const cookiePurposeMessagePrefix = 'cookies.consent.purpose.';
*/
const updateDebounce = 300;
/**
* By using this injection token instead of importing directly we can keep Klaro out of the main bundle
*/
const LAZY_KLARO = new InjectionToken<Promise<any>>(
'Lazily loaded Klaro',
{
providedIn: 'root',
factory: async () => (await import('klaro')),
}
);
/**
* Browser implementation for the KlaroService, representing a service for handling Klaro consent preferences and UI
*/
@@ -65,7 +75,9 @@ export class BrowserKlaroService extends KlaroService {
private authService: AuthService,
private ePersonService: EPersonDataService,
private configService: ConfigurationDataService,
private cookieService: CookieService) {
private cookieService: CookieService,
@Inject(LAZY_KLARO) private lazyKlaro: Promise<any>,
) {
super();
}
@@ -135,8 +147,7 @@ export class BrowserKlaroService extends KlaroService {
this.translateConfiguration();
this.klaroConfig.services = this.filterConfigServices(servicesToHide);
setup(this.klaroConfig);
this.lazyKlaro.then(({ setup }) => setup(this.klaroConfig));
});
}
@@ -220,7 +231,7 @@ export class BrowserKlaroService extends KlaroService {
* Show the cookie consent form
*/
showSettings() {
show(this.klaroConfig);
this.lazyKlaro.then(({show}) => show(this.klaroConfig));
}
/**

View File

@@ -22,7 +22,7 @@ describe('Date Utils', () => {
});
it('should convert NgbDateStruct to YYYY-MM-DDThh:mm:ssZ string', () => {
// NOTE: month is zero indexed which is why it increases by one
const date = new Date(2022, 5, 3);
const date = new Date(Date.UTC(2022, 5, 3));
expect(dateToISOFormat(dateToNgbDateStruct(date))).toEqual('2022-06-03T00:00:00Z');
});
});
@@ -30,22 +30,22 @@ describe('Date Utils', () => {
describe('dateToString', () => {
it('should convert Date to YYYY-MM-DD string', () => {
// NOTE: month is zero indexed which is why it increases by one
expect(dateToString(new Date(2022, 5, 3))).toEqual('2022-06-03');
expect(dateToString(new Date(Date.UTC(2022, 5, 3)))).toEqual('2022-06-03');
});
it('should convert Date with time to YYYY-MM-DD string', () => {
// NOTE: month is zero indexed which is why it increases by one
expect(dateToString(new Date(2022, 5, 3, 3, 24, 0))).toEqual('2022-06-03');
expect(dateToString(new Date(Date.UTC(2022, 5, 3, 3, 24, 0)))).toEqual('2022-06-03');
});
it('should convert Month only to YYYY-MM-DD string', () => {
// NOTE: month is zero indexed which is why it increases by one
expect(dateToString(new Date(2022, 5))).toEqual('2022-06-01');
expect(dateToString(new Date(Date.UTC(2022, 5)))).toEqual('2022-06-01');
});
it('should convert ISO Date to YYYY-MM-DD string', () => {
expect(dateToString(new Date('2022-06-03T03:24:00Z'))).toEqual('2022-06-03');
});
it('should convert NgbDateStruct to YYYY-MM-DD string', () => {
// NOTE: month is zero indexed which is why it increases by one
const date = new Date(2022, 5, 3);
const date = new Date(Date.UTC(2022, 5, 3));
expect(dateToString(dateToNgbDateStruct(date))).toEqual('2022-06-03');
});
});

View File

@@ -53,8 +53,9 @@ export class AuthorizedCollectionSelectorComponent extends DSOSelectorComponent
* Perform a search for authorized collections with the current query and page
* @param query Query to search objects for
* @param page Page to retrieve
* @param useCache Whether or not to use the cache
*/
search(query: string, page: number): Observable<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>> {
search(query: string, page: number, useCache: boolean = true): Observable<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>> {
let searchListService$: Observable<RemoteData<PaginatedList<Collection>>> = null;
const findOptions: FindListOptions = {
currentPage: page,
@@ -69,7 +70,7 @@ export class AuthorizedCollectionSelectorComponent extends DSOSelectorComponent
findOptions);
} else {
searchListService$ = this.collectionDataService
.getAuthorizedCollection(query, findOptions, true, false, followLink('parentCommunity'));
.getAuthorizedCollection(query, findOptions, useCache, false, followLink('parentCommunity'));
}
return searchListService$.pipe(
getFirstCompletedRemoteData(),

View File

@@ -21,12 +21,12 @@
</button>
<button *ngFor="let listEntry of (listEntries$ | async)"
class="list-group-item list-group-item-action border-0 list-entry"
[ngClass]="{'bg-primary': listEntry.indexableObject.id === currentDSOId}"
[ngClass]="{'bg-primary': listEntry['id'] === currentDSOId}"
title="{{ getName(listEntry) }}"
dsHoverClass="ds-hover"
(click)="onSelect.emit(listEntry.indexableObject)" #listEntryElement>
(click)="onClick(listEntry)" #listEntryElement>
<ds-listable-object-component-loader [object]="listEntry" [viewMode]="viewMode"
[linkType]=linkTypes.None [context]="getContext(listEntry.indexableObject.id)"></ds-listable-object-component-loader>
[linkType]=linkTypes.None [context]="getContext(listEntry['id'])"></ds-listable-object-component-loader>
</button>
</ng-container>
<button *ngIf="loading"

View File

@@ -35,6 +35,14 @@ import { RemoteData } from '../../../core/data/remote-data';
import { NotificationsService } from '../../notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
import {
ListableNotificationObject
} from '../../object-list/listable-notification-object/listable-notification-object.model';
import { ListableObject } from '../../object-collection/shared/listable-object.model';
import { NotificationType } from '../../notifications/models/notification-type';
import {
LISTABLE_NOTIFICATION_OBJECT
} from '../../object-list/listable-notification-object/listable-notification-object.resource-type';
@Component({
selector: 'ds-dso-selector',
@@ -82,7 +90,7 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
/**
* List with search results of DSpace objects for the current query
*/
listEntries$: BehaviorSubject<SearchResult<DSpaceObject>[]> = new BehaviorSubject(null);
listEntries$: BehaviorSubject<ListableObject[]> = new BehaviorSubject(null);
/**
* The current page to load
@@ -116,11 +124,6 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
*/
linkTypes = CollectionElementLinkType;
/**
* Track whether the element has the mouse over it
*/
isMouseOver = false;
/**
* Array to track all subscriptions and unsubscribe them onDestroy
* @type {Array}
@@ -182,24 +185,28 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
})
);
})
).subscribe((rd) => {
this.loading = false;
if (rd.hasSucceeded) {
const currentEntries = this.listEntries$.getValue();
if (hasNoValue(currentEntries)) {
this.listEntries$.next(rd.payload.page);
} else {
this.listEntries$.next([...currentEntries, ...rd.payload.page]);
}
// Check if there are more pages available after the current one
this.hasNextPage = rd.payload.totalElements > this.listEntries$.getValue().length;
} else {
this.listEntries$.next(null);
this.hasNextPage = false;
}
).subscribe((rd: RemoteData<PaginatedList<SearchResult<DSpaceObject>>>) => {
this.updateList(rd);
}));
}
updateList(rd: RemoteData<PaginatedList<SearchResult<DSpaceObject>>>) {
this.loading = false;
const currentEntries = this.listEntries$.getValue();
if (rd.hasSucceeded) {
if (hasNoValue(currentEntries)) {
this.listEntries$.next(rd.payload.page);
} else {
this.listEntries$.next([...currentEntries, ...rd.payload.page]);
}
// Check if there are more pages available after the current one
this.hasNextPage = rd.payload.totalElements > this.listEntries$.getValue().length;
} else {
this.listEntries$.next([...(hasNoValue(currentEntries) ? [] : this.listEntries$.getValue()), new ListableNotificationObject(NotificationType.Error, 'dso-selector.results-could-not-be-retrieved', LISTABLE_NOTIFICATION_OBJECT.value)]);
this.hasNextPage = false;
}
}
/**
* Get a query to send for retrieving the current DSO
*/
@@ -211,8 +218,9 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
* Perform a search for the current query and page
* @param query Query to search objects for
* @param page Page to retrieve
* @param useCache Whether or not to use the cache
*/
search(query: string, page: number): Observable<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>> {
search(query: string, page: number, useCache: boolean = true): Observable<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>> {
return this.searchService.search(
new PaginatedSearchOptions({
query: query,
@@ -220,7 +228,9 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
pagination: Object.assign({}, this.defaultPagination, {
currentPage: page
})
})
}),
null,
useCache,
).pipe(
getFirstCompletedRemoteData()
);
@@ -262,7 +272,28 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe());
}
getName(searchResult: SearchResult<DSpaceObject>): string {
return this.dsoNameService.getName(searchResult.indexableObject);
/**
* Handles the user clicks on the {@link ListableObject}s. When the {@link listableObject} is a
* {@link ListableObject} it will retry the error when the user clicks it. Otherwise it will emit the {@link onSelect}.
*
* @param listableObject The {@link ListableObject} to evaluate
*/
onClick(listableObject: ListableObject): void {
if (hasValue((listableObject as SearchResult<DSpaceObject>).indexableObject)) {
this.onSelect.emit((listableObject as SearchResult<DSpaceObject>).indexableObject);
} else {
this.listEntries$.value.pop();
this.hasNextPage = true;
this.search(this.input.value ? this.input.value : '', this.currentPage$.value, false).pipe(
getFirstCompletedRemoteData(),
).subscribe((rd: RemoteData<PaginatedList<SearchResult<DSpaceObject>>>) => {
this.updateList(rd);
});
}
}
getName(listableObject: ListableObject): string {
return hasValue((listableObject as SearchResult<DSpaceObject>).indexableObject) ?
this.dsoNameService.getName((listableObject as SearchResult<DSpaceObject>).indexableObject) : null;
}
}

View File

@@ -9,7 +9,7 @@
<h3 class="position-relative py-1 my-3 font-weight-normal">
<hr>
<div id="create-community-or-separator" class="text-center position-absolute w-100">
<span class="px-4 bg-white">or</span>
<span class="px-4 bg-white">{{'dso-selector.create.community.or-divider' | translate}}</span>
</div>
</h3>

View File

@@ -10,7 +10,7 @@ import {
} from '@ng-dynamic-forms/core';
import {
mockInputWithTypeBindModel, MockRelationModel, mockDcTypeInputModel
mockInputWithTypeBindModel, MockRelationModel
} from '../../../mocks/form-models.mock';
import {DsDynamicTypeBindRelationService} from './ds-dynamic-type-bind-relation.service';
import {FormFieldMetadataValueObject} from '../models/form-field-metadata-value.model';

View File

@@ -20,7 +20,7 @@ import { FormFieldMetadataValueObject } from '../../../models/form-field-metadat
import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { createTestComponent } from '../../../../../testing/utils.test';
import { DynamicLookupNameModel } from './dynamic-lookup-name.model';
import { AuthorityConfidenceStateDirective } from '../../../../../authority-confidence/authority-confidence-state.directive';
import { AuthorityConfidenceStateDirective } from '../../../../directives/authority-confidence-state.directive';
import { ObjNgFor } from '../../../../../utils/object-ngfor.pipe';
import {
mockDynamicFormLayoutService,

View File

@@ -21,11 +21,11 @@ import { DsDynamicOneboxComponent } from './dynamic-onebox.component';
import { DynamicOneboxModel } from './dynamic-onebox.model';
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
import { createTestComponent } from '../../../../../testing/utils.test';
import { AuthorityConfidenceStateDirective } from '../../../../../authority-confidence/authority-confidence-state.directive';
import { AuthorityConfidenceStateDirective } from '../../../../directives/authority-confidence-state.directive';
import { ObjNgFor } from '../../../../../utils/object-ngfor.pipe';
import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { createSuccessfulRemoteDataObject$ } from '../../../../../remote-data.utils';
import { VocabularyTreeviewComponent } from '../../../../../vocabulary-treeview/vocabulary-treeview.component';
import { VocabularyTreeviewComponent } from '../../../../vocabulary-treeview/vocabulary-treeview.component';
import {
mockDynamicFormLayoutService,
mockDynamicFormValidationService

View File

@@ -30,7 +30,7 @@ import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/
import { PageInfo } from '../../../../../../core/shared/page-info.model';
import { DsDynamicVocabularyComponent } from '../dynamic-vocabulary.component';
import { Vocabulary } from '../../../../../../core/submission/vocabularies/models/vocabulary.model';
import { VocabularyTreeviewComponent } from '../../../../../vocabulary-treeview/vocabulary-treeview.component';
import { VocabularyTreeviewComponent } from '../../../../vocabulary-treeview/vocabulary-treeview.component';
import { VocabularyEntryDetail } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
/**

View File

@@ -16,7 +16,7 @@ import { FormFieldModel } from '../../../models/form-field.model';
import { FormBuilderService } from '../../../form-builder.service';
import { FormService } from '../../../../form.service';
import { FormComponent } from '../../../../form.component';
import { Chips } from '../../../../../chips/models/chips.model';
import { Chips } from '../../../../chips/models/chips.model';
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
import { DsDynamicInputModel } from '../ds-dynamic-input.model';
import { createTestComponent } from '../../../../../testing/utils.test';

View File

@@ -19,10 +19,10 @@ import { FormBuilderService } from '../../../form-builder.service';
import { SubmissionFormsModel } from '../../../../../../core/config/models/config-submission-forms.model';
import { FormService } from '../../../../form.service';
import { FormComponent } from '../../../../form.component';
import { Chips } from '../../../../../chips/models/chips.model';
import { Chips } from '../../../../chips/models/chips.model';
import { hasValue, isEmpty, isNotEmpty, isNotNull } from '../../../../../empty.util';
import { shrinkInOut } from '../../../../../animations/shrink';
import { ChipsItem } from '../../../../../chips/models/chips-item.model';
import { ChipsItem } from '../../../../chips/models/chips-item.model';
import { hasOnlyEmptyProperties } from '../../../../../object.util';
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';

View File

@@ -13,7 +13,7 @@ import { VocabularyService } from '../../../../../../core/submission/vocabularie
import { VocabularyServiceStub } from '../../../../../testing/vocabulary-service.stub';
import { DsDynamicTagComponent } from './dynamic-tag.component';
import { DynamicTagModel } from './dynamic-tag.model';
import { Chips } from '../../../../../chips/models/chips.model';
import { Chips } from '../../../../chips/models/chips.model';
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { createTestComponent } from '../../../../../testing/utils.test';

View File

@@ -9,7 +9,7 @@ import isEqual from 'lodash/isEqual';
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
import { DynamicTagModel } from './dynamic-tag.model';
import { Chips } from '../../../../../chips/models/chips.model';
import { Chips } from '../../../../chips/models/chips.model';
import { hasValue, isNotEmpty } from '../../../../../empty.util';
import { environment } from '../../../../../../../environments/environment';
import { getFirstSucceededRemoteDataPayload } from '../../../../../../core/shared/operators';

View File

@@ -3,17 +3,16 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/c
import { ComponentFixture, fakeAsync, inject, TestBed, tick, waitForAsync, } from '@angular/core/testing';
import { Chips } from './models/chips.model';
import { UploaderService } from '../uploader/uploader.service';
import { ChipsComponent } from './chips.component';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { By } from '@angular/platform-browser';
import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-metadata-value.model';
import { createTestComponent } from '../testing/utils.test';
import { AuthorityConfidenceStateDirective } from '../authority-confidence/authority-confidence-state.directive';
import { FormFieldMetadataValueObject } from '../builder/models/form-field-metadata-value.model';
import { createTestComponent } from '../../testing/utils.test';
import { AuthorityConfidenceStateDirective } from '../directives/authority-confidence-state.directive';
import { TranslateModule } from '@ngx-translate/core';
import { ConfidenceType } from '../../core/shared/confidence-type';
import { ConfidenceType } from '../../../core/shared/confidence-type';
import { SortablejsModule } from 'ngx-sortablejs';
import { environment } from '../../../environments/environment';
import { environment } from '../../../../environments/environment';
describe('ChipsComponent test suite', () => {
@@ -41,7 +40,6 @@ describe('ChipsComponent test suite', () => {
providers: [
ChangeDetectorRef,
ChipsComponent,
UploaderService
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});

View File

@@ -5,7 +5,7 @@ import isObject from 'lodash/isObject';
import { Chips } from './models/chips.model';
import { ChipsItem } from './models/chips-item.model';
import { UploaderService } from '../uploader/uploader.service';
import { DragService } from '../../../core/drag.service';
import { TranslateService } from '@ngx-translate/core';
import { Options } from 'sortablejs';
import { BehaviorSubject } from 'rxjs';
@@ -33,7 +33,7 @@ export class ChipsComponent implements OnChanges {
constructor(
private cdr: ChangeDetectorRef,
private uploaderService: UploaderService,
private dragService: DragService,
private translate: TranslateService) {
this.options = {
@@ -76,12 +76,12 @@ export class ChipsComponent implements OnChanges {
onDragStart(index) {
this.isDragging.next(true);
this.uploaderService.overrideDragOverPage();
this.dragService.overrideDragOverPage();
this.dragged = index;
}
onDragEnd(event) {
this.uploaderService.allowDragOverPage();
this.dragService.allowDragOverPage();
this.dragged = -1;
this.chips.updateOrder();
this.isDragging.next(false);

View File

@@ -1,5 +1,5 @@
import { ChipsItem, ChipsItemIcon } from './chips-item.model';
import { FormFieldMetadataValueObject } from '../../form/builder/models/form-field-metadata-value.model';
import { FormFieldMetadataValueObject } from '../../builder/models/form-field-metadata-value.model';
describe('ChipsItem model test suite', () => {
let item: ChipsItem;

View File

@@ -1,9 +1,9 @@
import isObject from 'lodash/isObject';
import uniqueId from 'lodash/uniqueId';
import { hasValue, isNotEmpty } from '../../empty.util';
import { FormFieldMetadataValueObject } from '../../form/builder/models/form-field-metadata-value.model';
import { ConfidenceType } from '../../../core/shared/confidence-type';
import { PLACEHOLDER_PARENT_METADATA } from '../../form/builder/ds-dynamic-form-ui/ds-dynamic-form-constants';
import { hasValue, isNotEmpty } from '../../../empty.util';
import { FormFieldMetadataValueObject } from '../../builder/models/form-field-metadata-value.model';
import { ConfidenceType } from '../../../../core/shared/confidence-type';
import { PLACEHOLDER_PARENT_METADATA } from '../../builder/ds-dynamic-form-ui/ds-dynamic-form-constants';
export interface ChipsItemIcon {
metadata: string;

View File

@@ -1,6 +1,6 @@
import { Chips } from './chips.model';
import { ChipsItem } from './chips-item.model';
import { FormFieldMetadataValueObject } from '../../form/builder/models/form-field-metadata-value.model';
import { FormFieldMetadataValueObject } from '../../builder/models/form-field-metadata-value.model';
describe('Chips model test suite', () => {
let items: any[];

View File

@@ -3,11 +3,11 @@ import isEqual from 'lodash/isEqual';
import isObject from 'lodash/isObject';
import { BehaviorSubject } from 'rxjs';
import { ChipsItem, ChipsItemIcon } from './chips-item.model';
import { hasValue, isNotEmpty } from '../../empty.util';
import { MetadataIconConfig } from '../../../../config/submission-config.interface';
import { FormFieldMetadataValueObject } from '../../form/builder/models/form-field-metadata-value.model';
import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { PLACEHOLDER_PARENT_METADATA } from '../../form/builder/ds-dynamic-form-ui/ds-dynamic-form-constants';
import { hasValue, isNotEmpty } from '../../../empty.util';
import { MetadataIconConfig } from '../../../../../config/submission-config.interface';
import { FormFieldMetadataValueObject } from '../../builder/models/form-field-metadata-value.model';
import { VocabularyEntry } from '../../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { PLACEHOLDER_PARENT_METADATA } from '../../builder/ds-dynamic-form-ui/ds-dynamic-form-constants';
export class Chips {
chipsItems: BehaviorSubject<ChipsItem[]>;

View File

@@ -1,3 +1,11 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
import {
AfterViewInit,
Directive,
@@ -13,13 +21,13 @@ import {
import findIndex from 'lodash/findIndex';
import { VocabularyEntry } from '../../core/submission/vocabularies/models/vocabulary-entry.model';
import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-metadata-value.model';
import { ConfidenceType } from '../../core/shared/confidence-type';
import { isNotEmpty, isNull } from '../empty.util';
import { ConfidenceIconConfig } from '../../../config/submission-config.interface';
import { environment } from '../../../environments/environment';
import { VocabularyEntryDetail } from '../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { FormFieldMetadataValueObject } from '../builder/models/form-field-metadata-value.model';
import { ConfidenceType } from '../../../core/shared/confidence-type';
import { isNotEmpty, isNull } from '../../empty.util';
import { ConfidenceIconConfig } from '../../../../config/submission-config.interface';
import { environment } from '../../../../environments/environment';
import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
/**
* Directive to add to the element a bootstrap utility class based on metadata confidence value

View File

@@ -2,10 +2,7 @@ import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormComponent } from './form.component';
import { DsDynamicFormComponent } from './builder/ds-dynamic-form-ui/ds-dynamic-form.component';
import {
DsDynamicFormControlContainerComponent,
dsDynamicFormControlMapFn
} from './builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component';
import { DsDynamicFormControlContainerComponent, dsDynamicFormControlMapFn } from './builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component';
import { DsDynamicListComponent } from './builder/ds-dynamic-form-ui/models/list/dynamic-list.component';
import { DsDynamicLookupComponent } from './builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component';
import { DsDynamicDisabledComponent } from './builder/ds-dynamic-form-ui/models/disabled/dynamic-disabled.component';
@@ -24,12 +21,22 @@ import { DsDynamicLookupRelationExternalSourceTabComponent } from './builder/ds-
import { SharedModule } from '../shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { SearchModule } from '../search/search.module';
import { DYNAMIC_FORM_CONTROL_MAP_FN, DynamicFormsCoreModule } from '@ng-dynamic-forms/core';
import { DYNAMIC_FORM_CONTROL_MAP_FN, DYNAMIC_MATCHER_PROVIDERS, DynamicFormLayoutService, DynamicFormsCoreModule, DynamicFormService, DynamicFormValidationService } from '@ng-dynamic-forms/core';
import { ExistingMetadataListElementComponent } from './builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component';
import { ExistingRelationListElementComponent } from './builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component';
import { ExternalSourceEntryImportModalComponent } from './builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component';
import { CustomSwitchComponent } from './builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.component';
import { DynamicFormsNGBootstrapUIModule } from '@ng-dynamic-forms/ui-ng-bootstrap';
import { ChipsComponent } from './chips/chips.component';
import { NumberPickerComponent } from './number-picker/number-picker.component';
import { AuthorityConfidenceStateDirective } from './directives/authority-confidence-state.directive';
import { SortablejsModule } from 'ngx-sortablejs';
import { VocabularyTreeviewComponent } from './vocabulary-treeview/vocabulary-treeview.component';
import { VocabularyTreeviewService } from './vocabulary-treeview/vocabulary-treeview.service';
import { FormBuilderService } from './builder/form-builder.service';
import { DsDynamicTypeBindRelationService } from './builder/ds-dynamic-form-ui/ds-dynamic-type-bind-relation.service';
import { FormService } from './form.service';
import { NgxMaskModule } from 'ngx-mask';
const COMPONENTS = [
CustomSwitchComponent,
@@ -53,12 +60,20 @@ const COMPONENTS = [
ExistingMetadataListElementComponent,
ExistingRelationListElementComponent,
ExternalSourceEntryImportModalComponent,
FormComponent
FormComponent,
ChipsComponent,
NumberPickerComponent,
VocabularyTreeviewComponent,
];
const DIRECTIVES = [
AuthorityConfidenceStateDirective,
];
@NgModule({
declarations: [
...COMPONENTS
...COMPONENTS,
...DIRECTIVES,
],
imports: [
CommonModule,
@@ -66,16 +81,27 @@ const COMPONENTS = [
DynamicFormsNGBootstrapUIModule,
SearchModule,
SharedModule,
TranslateModule
TranslateModule,
SortablejsModule,
NgxMaskModule.forRoot(),
],
exports: [
...COMPONENTS
...COMPONENTS,
...DIRECTIVES,
],
providers: [
{
provide: DYNAMIC_FORM_CONTROL_MAP_FN,
useValue: dsDynamicFormControlMapFn
}
},
...DYNAMIC_MATCHER_PROVIDERS,
VocabularyTreeviewService,
DynamicFormLayoutService,
DynamicFormService,
DynamicFormValidationService,
FormBuilderService,
DsDynamicTypeBindRelationService,
FormService,
]
})
export class FormModule {

View File

@@ -2,12 +2,11 @@
import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, inject, TestBed, waitForAsync, } from '@angular/core/testing';
import { UploaderService } from '../uploader/uploader.service';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { By } from '@angular/platform-browser';
import { NumberPickerComponent } from './number-picker.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { createTestComponent } from '../testing/utils.test';
import { createTestComponent } from '../../testing/utils.test';
describe('NumberPickerComponent test suite', () => {
@@ -33,7 +32,6 @@ describe('NumberPickerComponent test suite', () => {
providers: [
ChangeDetectorRef,
NumberPickerComponent,
UploaderService
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});

View File

@@ -1,6 +1,6 @@
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, SimpleChanges, } from '@angular/core';
import { ControlValueAccessor, FormBuilder, NG_VALUE_ACCESSOR } from '@angular/forms';
import { isEmpty } from '../empty.util';
import { isEmpty } from '../../empty.util';
@Component({
selector: 'ds-number-picker',

View File

@@ -1,7 +1,7 @@
/* eslint-disable max-classes-per-file */
import { BehaviorSubject } from 'rxjs';
import { VocabularyEntryDetail } from '../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
import { PageInfo } from '../../core/shared/page-info.model';
import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
import { PageInfo } from '../../../core/shared/page-info.model';
export const LOAD_MORE = 'LOAD_MORE';
export const LOAD_MORE_ROOT = 'LOAD_MORE_ROOT';

View File

@@ -8,18 +8,18 @@ import { TranslateModule } from '@ngx-translate/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { provideMockStore } from '@ngrx/store/testing';
import { createTestComponent } from '../testing/utils.test';
import { createTestComponent } from '../../testing/utils.test';
import { VocabularyTreeviewComponent } from './vocabulary-treeview.component';
import { VocabularyTreeviewService } from './vocabulary-treeview.service';
import { VocabularyEntryDetail } from '../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
import { TreeviewFlatNode } from './vocabulary-treeview-node.model';
import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-metadata-value.model';
import { VocabularyOptions } from '../../core/submission/vocabularies/models/vocabulary-options.model';
import { PageInfo } from '../../core/shared/page-info.model';
import { VocabularyEntry } from '../../core/submission/vocabularies/models/vocabulary-entry.model';
import { AuthTokenInfo } from '../../core/auth/models/auth-token-info.model';
import { authReducer } from '../../core/auth/auth.reducer';
import { storeModuleConfig } from '../../app.reducer';
import { FormFieldMetadataValueObject } from '../builder/models/form-field-metadata-value.model';
import { VocabularyOptions } from '../../../core/submission/vocabularies/models/vocabulary-options.model';
import { PageInfo } from '../../../core/shared/page-info.model';
import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { AuthTokenInfo } from '../../../core/auth/models/auth-token-info.model';
import { authReducer } from '../../../core/auth/auth.reducer';
import { storeModuleConfig } from '../../../app.reducer';
describe('VocabularyTreeviewComponent test suite', () => {

View File

@@ -7,17 +7,17 @@ import { Observable, Subscription } from 'rxjs';
import { select, Store } from '@ngrx/store';
import { TranslateService } from '@ngx-translate/core';
import { VocabularyEntryDetail } from '../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
import { hasValue, isEmpty, isNotEmpty } from '../empty.util';
import { isAuthenticated } from '../../core/auth/selectors';
import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
import { hasValue, isEmpty, isNotEmpty } from '../../empty.util';
import { isAuthenticated } from '../../../core/auth/selectors';
import { VocabularyTreeviewService } from './vocabulary-treeview.service';
import { LOAD_MORE, LOAD_MORE_ROOT, TreeviewFlatNode, TreeviewNode } from './vocabulary-treeview-node.model';
import { VocabularyOptions } from '../../core/submission/vocabularies/models/vocabulary-options.model';
import { PageInfo } from '../../core/shared/page-info.model';
import { VocabularyEntry } from '../../core/submission/vocabularies/models/vocabulary-entry.model';
import { VocabularyOptions } from '../../../core/submission/vocabularies/models/vocabulary-options.model';
import { PageInfo } from '../../../core/shared/page-info.model';
import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { VocabularyTreeFlattener } from './vocabulary-tree-flattener';
import { VocabularyTreeFlatDataSource } from './vocabulary-tree-flat-data-source';
import { CoreState } from '../../core/core-state.model';
import { CoreState } from '../../../core/core-state.model';
/**
* Component that show a hierarchical vocabulary in a tree view

View File

@@ -5,15 +5,15 @@ import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-transla
import { cold, getTestScheduler, hot } from 'jasmine-marbles';
import { VocabularyTreeviewService } from './vocabulary-treeview.service';
import { VocabularyService } from '../../core/submission/vocabularies/vocabulary.service';
import { TranslateLoaderMock } from '../mocks/translate-loader.mock';
import { VocabularyOptions } from '../../core/submission/vocabularies/models/vocabulary-options.model';
import { VocabularyService } from '../../../core/submission/vocabularies/vocabulary.service';
import { TranslateLoaderMock } from '../../mocks/translate-loader.mock';
import { VocabularyOptions } from '../../../core/submission/vocabularies/models/vocabulary-options.model';
import { LOAD_MORE_NODE, LOAD_MORE_ROOT_NODE, TreeviewFlatNode, TreeviewNode } from './vocabulary-treeview-node.model';
import { PageInfo } from '../../core/shared/page-info.model';
import { VocabularyEntryDetail } from '../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
import { buildPaginatedList } from '../../core/data/paginated-list.model';
import { createSuccessfulRemoteDataObject } from '../remote-data.utils';
import { VocabularyEntry } from '../../core/submission/vocabularies/models/vocabulary-entry.model';
import { PageInfo } from '../../../core/shared/page-info.model';
import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
import { buildPaginatedList } from '../../../core/data/paginated-list.model';
import { createSuccessfulRemoteDataObject } from '../../remote-data.utils';
import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { expand, map, switchMap } from 'rxjs/operators';
import { from as observableFrom } from 'rxjs';

View File

@@ -10,17 +10,17 @@ import {
TreeviewFlatNode,
TreeviewNode
} from './vocabulary-treeview-node.model';
import { VocabularyEntry } from '../../core/submission/vocabularies/models/vocabulary-entry.model';
import { VocabularyService } from '../../core/submission/vocabularies/vocabulary.service';
import { PageInfo } from '../../core/shared/page-info.model';
import { isEmpty, isNotEmpty } from '../empty.util';
import { VocabularyOptions } from '../../core/submission/vocabularies/models/vocabulary-options.model';
import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { VocabularyService } from '../../../core/submission/vocabularies/vocabulary.service';
import { PageInfo } from '../../../core/shared/page-info.model';
import { isEmpty, isNotEmpty } from '../../empty.util';
import { VocabularyOptions } from '../../../core/submission/vocabularies/models/vocabulary-options.model';
import {
getFirstSucceededRemoteDataPayload,
getFirstSucceededRemoteListPayload
} from '../../core/shared/operators';
import { PaginatedList } from '../../core/data/paginated-list.model';
import { VocabularyEntryDetail } from '../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
} from '../../../core/shared/operators';
import { PaginatedList } from '../../../core/data/paginated-list.model';
import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
/**
* A service that provides methods to deal with vocabulary tree

View File

@@ -1,4 +1,3 @@
import { NgbModalConfig, NgbModal } from '@ng-bootstrap/ng-bootstrap';
/**
* If a component implementing this interface is used to create a modal (i.e. it is passed to {@link NgbModal#open}),

View File

@@ -1,4 +1,4 @@
import { Component, Inject, Input, OnInit } from '@angular/core';
import { Component, Inject, OnInit } from '@angular/core';
import { LinkMenuItemModel } from './models/link.model';
import { rendersMenuItemForType } from '../menu-item.decorator';
import { isNotEmpty } from '../../empty.util';

View File

@@ -1,4 +1,4 @@
import { Component, Inject, Input } from '@angular/core';
import { Component, Inject } from '@angular/core';
import { TextMenuItemModel } from './models/text.model';
import { rendersMenuItemForType } from '../menu-item.decorator';
import { MenuItemType } from '../menu-item-type.model';

View File

@@ -12,8 +12,11 @@ import { ExternalLinkMenuItemComponent } from './menu-item/external-link-menu-it
const COMPONENTS = [
MenuSectionComponent,
MenuComponent,
LinkMenuItemComponent,
];
const ENTRY_COMPONENTS = [
TextMenuItemComponent,
LinkMenuItemComponent,
OnClickMenuItemComponent,
ExternalLinkMenuItemComponent,
];
@@ -32,10 +35,12 @@ const PROVIDERS = [
...MODULES
],
declarations: [
...COMPONENTS
...COMPONENTS,
...ENTRY_COMPONENTS,
],
providers: [
...PROVIDERS
...PROVIDERS,
...ENTRY_COMPONENTS,
],
exports: [
...COMPONENTS

View File

@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, Injector, NO_ERRORS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { of, of as observableOf } from 'rxjs';

View File

@@ -1,5 +1,4 @@
/* eslint-disable max-classes-per-file */
import { Item } from '../../../../core/shared/item.model';
import { ViewMode } from '../../../../core/shared/view-mode.model';
import { DEFAULT_VIEW_MODE, getListableObjectComponent, listableObjectComponent } from './listable-object.decorator';
import { Context } from '../../../../core/shared/context.model';

View File

@@ -0,0 +1 @@
<div class="alert d-block {{ object?.notificationType }} m-0">{{ object?.message | translate }}</div>

View File

@@ -0,0 +1,43 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ListableNotificationObjectComponent } from './listable-notification-object.component';
import { NotificationType } from '../../notifications/models/notification-type';
import { ListableNotificationObject } from './listable-notification-object.model';
import { By } from '@angular/platform-browser';
import { TranslateModule } from '@ngx-translate/core';
describe('ListableNotificationObjectComponent', () => {
let component: ListableNotificationObjectComponent;
let fixture: ComponentFixture<ListableNotificationObjectComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
],
declarations: [
ListableNotificationObjectComponent,
],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ListableNotificationObjectComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
describe('ui', () => {
it('should display the given error message', () => {
component.object = new ListableNotificationObject(NotificationType.Error, 'test error message');
fixture.detectChanges();
const listableNotificationObject: Element = fixture.debugElement.query(By.css('.alert')).nativeElement;
expect(listableNotificationObject.className).toContain(NotificationType.Error);
expect(listableNotificationObject.innerHTML).toBe('test error message');
});
});
afterEach(() => {
fixture.debugElement.nativeElement.remove();
});
});

View File

@@ -0,0 +1,21 @@
import { Component } from '@angular/core';
import {
AbstractListableElementComponent
} from '../../object-collection/shared/object-collection-element/abstract-listable-element.component';
import { ListableNotificationObject } from './listable-notification-object.model';
import { listableObjectComponent } from '../../object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../core/shared/view-mode.model';
import { LISTABLE_NOTIFICATION_OBJECT } from './listable-notification-object.resource-type';
/**
* The component for displaying a notifications inside an object list
*/
@listableObjectComponent(ListableNotificationObject, ViewMode.ListElement)
@listableObjectComponent(LISTABLE_NOTIFICATION_OBJECT.value, ViewMode.ListElement)
@Component({
selector: 'ds-listable-notification-object',
templateUrl: './listable-notification-object.component.html',
styleUrls: ['./listable-notification-object.component.scss'],
})
export class ListableNotificationObjectComponent extends AbstractListableElementComponent<ListableNotificationObject> {
}

View File

@@ -0,0 +1,36 @@
import { ListableObject } from '../../object-collection/shared/listable-object.model';
import { typedObject } from '../../../core/cache/builders/build-decorators';
import { TypedObject } from '../../../core/cache/typed-object.model';
import { LISTABLE_NOTIFICATION_OBJECT } from './listable-notification-object.resource-type';
import { GenericConstructor } from '../../../core/shared/generic-constructor';
import { NotificationType } from '../../notifications/models/notification-type';
import { ResourceType } from '../../../core/shared/resource-type';
/**
* Object representing a notification message inside a list of objects
*/
@typedObject
export class ListableNotificationObject extends ListableObject implements TypedObject {
static type: ResourceType = LISTABLE_NOTIFICATION_OBJECT;
type: ResourceType = LISTABLE_NOTIFICATION_OBJECT;
protected renderTypes: string[];
constructor(
public notificationType: NotificationType = NotificationType.Error,
public message: string = 'listable-notification-object.default-message',
...renderTypes: string[]
) {
super();
this.renderTypes = renderTypes;
}
/**
* Method that returns as which type of object this object should be rendered.
*/
getRenderTypes(): (string | GenericConstructor<ListableObject>)[] {
return [...this.renderTypes, this.constructor as GenericConstructor<ListableObject>];
}
}

View File

@@ -0,0 +1,9 @@
import { ResourceType } from '../../../core/shared/resource-type';
/**
* The resource type for {@link ListableNotificationObject}
*
* Needs to be in a separate file to prevent circular
* dependencies in webpack.
*/
export const LISTABLE_NOTIFICATION_OBJECT = new ResourceType('listable-notification-object');

View File

@@ -11,7 +11,6 @@ import { createSuccessfulRemoteDataObject$ } from '../../remote-data.utils';
import { HALResource } from '../../../core/shared/hal-resource.model';
import { ChildHALResource } from '../../../core/shared/child-hal-resource.model';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../mocks/dso-name.service.mock';
export function createSidebarSearchListElementTests(
componentClass: any,

View File

@@ -11,8 +11,6 @@ import { createSuccessfulRemoteDataObject } from '../remote-data.utils';
import { createPaginatedList } from '../testing/utils.test';
import { ObjectValuesPipe } from '../utils/object-values-pipe';
import { PaginationService } from '../../core/pagination/pagination.service';
import { PaginationComponentOptions } from '../pagination/pagination-component-options.model';
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
import { PaginationServiceStub } from '../testing/pagination-service.stub';
import { FieldUpdates } from '../../core/data/object-updates/field-updates.model';

View File

@@ -32,8 +32,7 @@ import { SortDirection, SortOptions } from '../../core/cache/models/sort-options
import { createTestComponent } from '../testing/utils.test';
import { storeModuleConfig } from '../../app.reducer';
import { PaginationService } from '../../core/pagination/pagination.service';
import { BehaviorSubject, of as observableOf } from 'rxjs';
import { PaginationServiceStub } from '../testing/pagination-service.stub';
import { BehaviorSubject } from 'rxjs';
import { FindListOptions } from '../../core/data/find-list-options.model';
function expectPages(fixture: ComponentFixture<any>, pagesDef: string[]): void {

Some files were not shown because too many files have changed in this diff Show More