mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-17 15:03:07 +00:00
Merge remote-tracking branch 'origin/main' into w2p-96252_Reduce-main-bundle-size_Reorganize-shared-module_REBASE-ON-7.4
This commit is contained in:
@@ -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';
|
||||
|
@@ -13,32 +13,34 @@
|
||||
[paginationOptions]="pageConfig"
|
||||
[pageInfoState]="(bitstreamFormats | async)?.payload"
|
||||
[collectionSize]="(bitstreamFormats | async)?.payload?.totalElements"
|
||||
[hideGear]="true"
|
||||
[hideGear]="false"
|
||||
[hidePagerWhenSinglePage]="true">
|
||||
<div class="table-responsive">
|
||||
<table id="formats" class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"></th>
|
||||
<th scope="col">{{'admin.registries.bitstream-formats.table.name' | translate}}</th>
|
||||
<th scope="col">{{'admin.registries.bitstream-formats.table.mimetype' | translate}}</th>
|
||||
<th scope="col">{{'admin.registries.bitstream-formats.table.supportLevel.head' | translate}}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="col"></th>
|
||||
<th scope="col">{{'admin.registries.bitstream-formats.table.id' | translate}}</th>
|
||||
<th scope="col">{{'admin.registries.bitstream-formats.table.name' | translate}}</th>
|
||||
<th scope="col">{{'admin.registries.bitstream-formats.table.mimetype' | translate}}</th>
|
||||
<th scope="col">{{'admin.registries.bitstream-formats.table.supportLevel.head' | translate}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let bitstreamFormat of (bitstreamFormats | async)?.payload?.page">
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
[checked]="isSelected(bitstreamFormat) | async"
|
||||
(change)="selectBitStreamFormat(bitstreamFormat, $event)"
|
||||
>
|
||||
</label>
|
||||
</td>
|
||||
<td><a [routerLink]="['/admin/registries/bitstream-formats', bitstreamFormat.id, 'edit']">{{bitstreamFormat.shortDescription}}</a></td>
|
||||
<td><a [routerLink]="['/admin/registries/bitstream-formats', bitstreamFormat.id, 'edit']">{{bitstreamFormat.mimetype}} <span *ngIf="bitstreamFormat.internal">({{'admin.registries.bitstream-formats.table.internal' | translate}})</span></a></td>
|
||||
<td><a [routerLink]="['/admin/registries/bitstream-formats', bitstreamFormat.id, 'edit']">{{'admin.registries.bitstream-formats.table.supportLevel.'+bitstreamFormat.supportLevel | translate}}</a></td>
|
||||
</tr>
|
||||
<tr *ngFor="let bitstreamFormat of (bitstreamFormats | async)?.payload?.page">
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
[checked]="isSelected(bitstreamFormat) | async"
|
||||
(change)="selectBitStreamFormat(bitstreamFormat, $event)"
|
||||
>
|
||||
</label>
|
||||
</td>
|
||||
<td><a [routerLink]="['/admin/registries/bitstream-formats', bitstreamFormat.id, 'edit']">{{bitstreamFormat.id}}</a></td>
|
||||
<td><a [routerLink]="['/admin/registries/bitstream-formats', bitstreamFormat.id, 'edit']">{{bitstreamFormat.shortDescription}}</a></td>
|
||||
<td><a [routerLink]="['/admin/registries/bitstream-formats', bitstreamFormat.id, 'edit']">{{bitstreamFormat.mimetype}} <span *ngIf="bitstreamFormat.internal">({{'admin.registries.bitstream-formats.table.internal' | translate}})</span></a></td>
|
||||
<td><a [routerLink]="['/admin/registries/bitstream-formats', bitstreamFormat.id, 'edit']">{{'admin.registries.bitstream-formats.table.supportLevel.'+bitstreamFormat.supportLevel | translate}}</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@@ -129,16 +129,19 @@ describe('BitstreamFormatsComponent', () => {
|
||||
});
|
||||
|
||||
it('should contain the correct formats', () => {
|
||||
const unknownName: HTMLElement = fixture.debugElement.query(By.css('#formats tr:nth-child(1) td:nth-child(2)')).nativeElement;
|
||||
const unknownName: HTMLElement = fixture.debugElement.query(By.css('#formats tr:nth-child(1) td:nth-child(3)')).nativeElement;
|
||||
expect(unknownName.textContent).toBe('Unknown');
|
||||
|
||||
const licenseName: HTMLElement = fixture.debugElement.query(By.css('#formats tr:nth-child(2) td:nth-child(2)')).nativeElement;
|
||||
const UUID: HTMLElement = fixture.debugElement.query(By.css('#formats tr:nth-child(1) td:nth-child(2)')).nativeElement;
|
||||
expect(UUID.textContent).toBe('test-uuid-1');
|
||||
|
||||
const licenseName: HTMLElement = fixture.debugElement.query(By.css('#formats tr:nth-child(2) td:nth-child(3)')).nativeElement;
|
||||
expect(licenseName.textContent).toBe('License');
|
||||
|
||||
const ccLicenseName: HTMLElement = fixture.debugElement.query(By.css('#formats tr:nth-child(3) td:nth-child(2)')).nativeElement;
|
||||
const ccLicenseName: HTMLElement = fixture.debugElement.query(By.css('#formats tr:nth-child(3) td:nth-child(3)')).nativeElement;
|
||||
expect(ccLicenseName.textContent).toBe('CC License');
|
||||
|
||||
const adobeName: HTMLElement = fixture.debugElement.query(By.css('#formats tr:nth-child(4) td:nth-child(2)')).nativeElement;
|
||||
const adobeName: HTMLElement = fixture.debugElement.query(By.css('#formats tr:nth-child(4) td:nth-child(3)')).nativeElement;
|
||||
expect(adobeName.textContent).toBe('Adobe PDF');
|
||||
});
|
||||
});
|
||||
|
@@ -1,12 +1,11 @@
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { combineLatest as observableCombineLatest, Observable, 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';
|
||||
@@ -29,21 +28,14 @@ export class BitstreamFormatsComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
bitstreamFormats: Observable<RemoteData<PaginatedList<BitstreamFormat>>>;
|
||||
|
||||
/**
|
||||
* The current pagination configuration for the page used by the FindAll method
|
||||
* Currently simply renders all bitstream formats
|
||||
*/
|
||||
config: FindListOptions = Object.assign(new FindListOptions(), {
|
||||
elementsPerPage: 20
|
||||
});
|
||||
|
||||
/**
|
||||
* The current pagination configuration for the page
|
||||
* Currently simply renders all bitstream formats
|
||||
*/
|
||||
pageConfig: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
|
||||
id: 'rbp',
|
||||
pageSize: 20
|
||||
pageSize: 20,
|
||||
pageSizeOptions: [20, 40, 60, 80, 100]
|
||||
});
|
||||
|
||||
constructor(private notificationsService: NotificationsService,
|
||||
@@ -51,7 +43,7 @@ export class BitstreamFormatsComponent implements OnInit, OnDestroy {
|
||||
private translateService: TranslateService,
|
||||
private bitstreamFormatService: BitstreamFormatDataService,
|
||||
private paginationService: PaginationService,
|
||||
) {
|
||||
) {
|
||||
}
|
||||
|
||||
|
||||
@@ -149,7 +141,7 @@ export class BitstreamFormatsComponent implements OnInit, OnDestroy {
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
this.bitstreamFormats = this.paginationService.getFindListOptions(this.pageConfig.id, this.config).pipe(
|
||||
this.bitstreamFormats = this.paginationService.getFindListOptions(this.pageConfig.id, this.pageConfig).pipe(
|
||||
switchMap((findListOptions: FindListOptions) => {
|
||||
return this.bitstreamFormatService.findAll(findListOptions);
|
||||
})
|
||||
|
@@ -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;
|
||||
|
@@ -25,6 +25,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th scope="col">{{'admin.registries.schema.fields.table.id' | translate}}</th>
|
||||
<th scope="col">{{'admin.registries.schema.fields.table.field' | translate}}</th>
|
||||
<th scope="col">{{'admin.registries.schema.fields.table.scopenote' | translate}}</th>
|
||||
</tr>
|
||||
@@ -39,6 +40,7 @@
|
||||
(change)="selectMetadataField(field, $event)">
|
||||
</label>
|
||||
</td>
|
||||
<td class="selectable-row" (click)="editField(field)">{{field.id}}</td>
|
||||
<td class="selectable-row" (click)="editField(field)">{{schema?.prefix}}.{{field.element}}<label *ngIf="field.qualifier">.</label>{{field.qualifier}}</td>
|
||||
<td class="selectable-row" (click)="editField(field)">{{field.scopeNote}}</td>
|
||||
</tr>
|
||||
|
@@ -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;
|
||||
@@ -169,10 +166,10 @@ describe('MetadataSchemaComponent', () => {
|
||||
});
|
||||
|
||||
it('should contain the correct fields', () => {
|
||||
const editorField: HTMLElement = fixture.debugElement.query(By.css('#metadata-fields tr:nth-child(1) td:nth-child(2)')).nativeElement;
|
||||
const editorField: HTMLElement = fixture.debugElement.query(By.css('#metadata-fields tr:nth-child(1) td:nth-child(3)')).nativeElement;
|
||||
expect(editorField.textContent).toBe('mock.contributor.editor');
|
||||
|
||||
const illustratorField: HTMLElement = fixture.debugElement.query(By.css('#metadata-fields tr:nth-child(2) td:nth-child(2)')).nativeElement;
|
||||
const illustratorField: HTMLElement = fixture.debugElement.query(By.css('#metadata-fields tr:nth-child(2) td:nth-child(3)')).nativeElement;
|
||||
expect(illustratorField.textContent).toBe('mock.contributor.illustrator');
|
||||
});
|
||||
|
||||
|
@@ -2,7 +2,7 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { MenuService } from '../../../shared/menu/menu.service';
|
||||
import { MenuServiceStub } from '../../../shared/testing/menu-service.stub';
|
||||
import { CSSVariableService } from '../../../shared/sass-helper/sass-helper.service';
|
||||
import { CSSVariableService } from '../../../shared/sass-helper/css-variable.service';
|
||||
import { CSSVariableServiceStub } from '../../../shared/testing/css-variable-service.stub';
|
||||
import { Component } from '@angular/core';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
@@ -6,7 +6,7 @@ import { ScriptDataService } from '../../core/data/processes/script-data.service
|
||||
import { AdminSidebarComponent } from './admin-sidebar.component';
|
||||
import { MenuService } from '../../shared/menu/menu.service';
|
||||
import { MenuServiceStub } from '../../shared/testing/menu-service.stub';
|
||||
import { CSSVariableService } from '../../shared/sass-helper/sass-helper.service';
|
||||
import { CSSVariableService } from '../../shared/sass-helper/css-variable.service';
|
||||
import { CSSVariableServiceStub } from '../../shared/testing/css-variable-service.stub';
|
||||
import { AuthServiceStub } from '../../shared/testing/auth-service.stub';
|
||||
import { AuthService } from '../../core/auth/auth.service';
|
||||
@@ -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';
|
||||
|
@@ -5,7 +5,7 @@ import { AuthService } from '../../core/auth/auth.service';
|
||||
import { slideSidebar } from '../../shared/animations/slide';
|
||||
import { MenuComponent } from '../../shared/menu/menu.component';
|
||||
import { MenuService } from '../../shared/menu/menu.service';
|
||||
import { CSSVariableService } from '../../shared/sass-helper/sass-helper.service';
|
||||
import { CSSVariableService } from '../../shared/sass-helper/css-variable.service';
|
||||
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
|
||||
import { MenuID } from '../../shared/menu/menu-id.model';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
@@ -69,7 +69,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
super.ngOnInit();
|
||||
this.sidebarWidth = this.variableService.getVariable('sidebarItemsWidth');
|
||||
this.sidebarWidth = this.variableService.getVariable('--ds-sidebar-items-width');
|
||||
this.authService.isAuthenticated()
|
||||
.subscribe((loggedIn: boolean) => {
|
||||
if (loggedIn) {
|
||||
|
@@ -3,7 +3,7 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { ExpandableAdminSidebarSectionComponent } from './expandable-admin-sidebar-section.component';
|
||||
import { MenuService } from '../../../shared/menu/menu.service';
|
||||
import { MenuServiceStub } from '../../../shared/testing/menu-service.stub';
|
||||
import { CSSVariableService } from '../../../shared/sass-helper/sass-helper.service';
|
||||
import { CSSVariableService } from '../../../shared/sass-helper/css-variable.service';
|
||||
import { CSSVariableServiceStub } from '../../../shared/testing/css-variable-service.stub';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { Component } from '@angular/core';
|
||||
|
@@ -2,7 +2,7 @@ import { Component, Inject, Injector, OnInit } from '@angular/core';
|
||||
import { rotate } from '../../../shared/animations/rotate';
|
||||
import { AdminSidebarSectionComponent } from '../admin-sidebar-section/admin-sidebar-section.component';
|
||||
import { slide } from '../../../shared/animations/slide';
|
||||
import { CSSVariableService } from '../../../shared/sass-helper/sass-helper.service';
|
||||
import { CSSVariableService } from '../../../shared/sass-helper/css-variable.service';
|
||||
import { bgColor } from '../../../shared/animations/bgColor';
|
||||
import { MenuService } from '../../../shared/menu/menu.service';
|
||||
import { combineLatest as combineLatestObservable, Observable } from 'rxjs';
|
||||
@@ -65,7 +65,7 @@ export class ExpandableAdminSidebarSectionComponent extends AdminSidebarSectionC
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
super.ngOnInit();
|
||||
this.sidebarActiveBg = this.variableService.getVariable('adminSidebarActiveBg');
|
||||
this.sidebarActiveBg = this.variableService.getVariable('--ds-admin-sidebar-active-bg');
|
||||
this.sidebarCollapsed = this.menuService.isMenuCollapsed(this.menuID);
|
||||
this.sidebarPreviewCollapsed = this.menuService.isMenuPreviewCollapsed(this.menuID);
|
||||
this.expanded = combineLatestObservable(this.active, this.sidebarCollapsed, this.sidebarPreviewCollapsed)
|
||||
|
@@ -18,7 +18,7 @@ import { AngularticsProviderMock } from './shared/mocks/angulartics-provider.ser
|
||||
import { AuthServiceMock } from './shared/mocks/auth.service.mock';
|
||||
import { AuthService } from './core/auth/auth.service';
|
||||
import { MenuService } from './shared/menu/menu.service';
|
||||
import { CSSVariableService } from './shared/sass-helper/sass-helper.service';
|
||||
import { CSSVariableService } from './shared/sass-helper/css-variable.service';
|
||||
import { CSSVariableServiceStub } from './shared/testing/css-variable-service.stub';
|
||||
import { MenuServiceStub } from './shared/testing/menu-service.stub';
|
||||
import { HostWindowService } from './shared/host-window.service';
|
||||
|
@@ -25,13 +25,12 @@ import { HostWindowState } from './shared/search/host-window.reducer';
|
||||
import { NativeWindowRef, NativeWindowService } from './core/services/window.service';
|
||||
import { isAuthenticationBlocking } from './core/auth/selectors';
|
||||
import { AuthService } from './core/auth/auth.service';
|
||||
import { CSSVariableService } from './shared/sass-helper/sass-helper.service';
|
||||
import { CSSVariableService } from './shared/sass-helper/css-variable.service';
|
||||
import { environment } from '../environments/environment';
|
||||
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',
|
||||
@@ -110,18 +109,8 @@ export class AppComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
|
||||
private storeCSSVariables() {
|
||||
this.cssService.addCSSVariable('xlMin', '1200px');
|
||||
this.cssService.addCSSVariable('mdMin', '768px');
|
||||
this.cssService.addCSSVariable('lgMin', '576px');
|
||||
this.cssService.addCSSVariable('smMin', '0');
|
||||
this.cssService.addCSSVariable('adminSidebarActiveBg', '#0f1b28');
|
||||
this.cssService.addCSSVariable('sidebarItemsWidth', '250px');
|
||||
this.cssService.addCSSVariable('collapsedSidebarWidth', '53.234px');
|
||||
this.cssService.addCSSVariable('totalSidebarWidth', '303.234px');
|
||||
// const vars = variables.locals || {};
|
||||
// Object.keys(vars).forEach((name: string) => {
|
||||
// this.cssService.addCSSVariable(name, vars[name]);
|
||||
// })
|
||||
this.cssService.clearCSSVariables();
|
||||
this.cssService.addCSSVariables(this.cssService.getCSSVariablesFromStylesheets(this.document));
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import * as fromRouter from '@ngrx/router-store';
|
||||
import { routerReducer, RouterReducerState } from '@ngrx/router-store';
|
||||
import { ActionReducerMap, createSelector, MemoizedSelector } from '@ngrx/store';
|
||||
import {
|
||||
ePeopleRegistryReducer,
|
||||
@@ -35,7 +35,7 @@ import {
|
||||
ObjectSelectionListState,
|
||||
objectSelectionReducer
|
||||
} from './shared/object-select/object-select.reducer';
|
||||
import { cssVariablesReducer, CSSVariablesState } from './shared/sass-helper/sass-helper.reducer';
|
||||
import { cssVariablesReducer, CSSVariablesState } from './shared/sass-helper/css-variable.reducer';
|
||||
|
||||
import { hostWindowReducer, HostWindowState } from './shared/search/host-window.reducer';
|
||||
import {
|
||||
@@ -53,7 +53,7 @@ import { MenusState } from './shared/menu/menus-state.model';
|
||||
import { correlationIdReducer } from './correlation-id/correlation-id.reducer';
|
||||
|
||||
export interface AppState {
|
||||
router: fromRouter.RouterReducerState;
|
||||
router: RouterReducerState;
|
||||
hostWindow: HostWindowState;
|
||||
forms: FormState;
|
||||
metadataRegistry: MetadataRegistryState;
|
||||
@@ -75,7 +75,7 @@ export interface AppState {
|
||||
}
|
||||
|
||||
export const appReducers: ActionReducerMap<AppState> = {
|
||||
router: fromRouter.routerReducer,
|
||||
router: routerReducer,
|
||||
hostWindow: hostWindowReducer,
|
||||
forms: formReducer,
|
||||
metadataRegistry: metadataRegistryReducer,
|
||||
|
@@ -26,7 +26,7 @@ import {
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { DynamicCustomSwitchModel } from '../../shared/form/builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.model';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { BitstreamDataService } from '../../core/data/bitstream-data.service';
|
||||
import {
|
||||
getAllSucceededRemoteDataPayload,
|
||||
|
@@ -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';
|
||||
|
@@ -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';
|
||||
|
@@ -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';
|
||||
|
@@ -11,11 +11,11 @@
|
||||
</div>
|
||||
<div>
|
||||
<span class="font-weight-bold">{{'collection.source.controls.harvest.last' | translate}}</span>
|
||||
<span>{{contentSource?.message ? contentSource?.message : 'collection.source.controls.harvest.no-information'|translate }}</span>
|
||||
<span>{{contentSource?.lastHarvested ? contentSource?.lastHarvested : 'collection.source.controls.harvest.no-information'|translate }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="font-weight-bold">{{'collection.source.controls.harvest.message' | translate}}</span>
|
||||
<span>{{contentSource?.lastHarvested ? contentSource?.lastHarvested : 'collection.source.controls.harvest.no-information'|translate }}</span>
|
||||
<span>{{contentSource?.message ? contentSource?.message: 'collection.source.controls.harvest.no-information'|translate }}</span>
|
||||
</div>
|
||||
|
||||
<button *ngIf="!(testConfigRunning$ |async)" class="btn btn-secondary"
|
||||
|
@@ -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';
|
||||
@@ -23,7 +22,7 @@ import { RemoteData } from '../../../core/data/remote-data';
|
||||
import { Collection } from '../../../core/shared/collection.model';
|
||||
import { first, map, switchMap, take } from 'rxjs/operators';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { CollectionDataService } from '../../../core/data/collection-data.service';
|
||||
import { getFirstSucceededRemoteData, getFirstCompletedRemoteData } from '../../../core/shared/operators';
|
||||
import { MetadataConfig } from '../../../core/shared/metadata-config.model';
|
||||
|
@@ -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';
|
||||
|
@@ -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';
|
||||
|
@@ -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';
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line import/no-namespace
|
||||
import * as deepFreeze from 'deep-freeze';
|
||||
import { Operation } from 'fast-json-patch';
|
||||
import { Item } from '../shared/item.model';
|
||||
|
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line import/no-namespace
|
||||
import * as deepFreeze from 'deep-freeze';
|
||||
import { RemoveFromObjectCacheAction } from './object-cache.actions';
|
||||
import { serverSyncBufferReducer } from './server-sync-buffer.reducer';
|
||||
|
@@ -20,7 +20,6 @@ import { NotificationsService } from '../shared/notifications/notifications.serv
|
||||
import { SelectableListService } from '../shared/object-list/selectable-list/selectable-list.service';
|
||||
import { ObjectSelectService } from '../shared/object-select/object-select.service';
|
||||
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
|
||||
import { CSSVariableService } from '../shared/sass-helper/sass-helper.service';
|
||||
import { SidebarService } from '../shared/sidebar/sidebar.service';
|
||||
import { AuthenticatedGuard } from './auth/authenticated.guard';
|
||||
import { AuthStatus } from './auth/models/auth-status.model';
|
||||
@@ -240,7 +239,6 @@ const PROVIDERS = [
|
||||
DefaultChangeAnalyzer,
|
||||
ArrayMoveChangeAnalyzer,
|
||||
ObjectSelectService,
|
||||
CSSVariableService,
|
||||
MenuService,
|
||||
ObjectUpdatesService,
|
||||
SearchService,
|
||||
|
@@ -10,6 +10,7 @@ import { ResourceType } from '../../shared/resource-type';
|
||||
import { BaseDataService } from './base-data.service';
|
||||
import { HALDataService } from './hal-data-service.interface';
|
||||
import { dataService, getDataServiceFor } from './data-service.decorator';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
class TestService extends BaseDataService<any> {
|
||||
}
|
||||
@@ -28,7 +29,7 @@ let testType;
|
||||
|
||||
describe('@dataService/getDataServiceFor', () => {
|
||||
beforeEach(() => {
|
||||
testType = new ResourceType('testType-' + new Date().getTime());
|
||||
testType = new ResourceType(`testType-${uuidv4()}`);
|
||||
});
|
||||
|
||||
it('should register a resourcetype for a dataservice', () => {
|
||||
|
@@ -3,7 +3,7 @@ import { ChangeAnalyzer } from './change-analyzer';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DSpaceObject } from '../shared/dspace-object.model';
|
||||
import { MetadataMap } from '../shared/metadata.models';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
|
||||
/**
|
||||
* A class to determine what differs between two
|
||||
|
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line import/no-namespace
|
||||
import * as deepFreeze from 'deep-freeze';
|
||||
import {
|
||||
AddFieldUpdateAction,
|
||||
|
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line import/no-namespace
|
||||
import * as deepFreeze from 'deep-freeze';
|
||||
import {
|
||||
RequestConfigureAction,
|
||||
|
@@ -4,7 +4,7 @@ import { HttpHeaders } from '@angular/common/http';
|
||||
import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { filter, map, take, tap } from 'rxjs/operators';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { hasValue, isEmpty, isNotEmpty, hasNoValue } from '../../shared/empty.util';
|
||||
import { ObjectCacheEntry } from '../cache/object-cache.reducer';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
|
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line import/no-namespace
|
||||
import * as deepFreeze from 'deep-freeze';
|
||||
|
||||
import { indexReducer, MetaIndexState } from './index.reducer';
|
||||
|
@@ -3,7 +3,6 @@ import { hasValue, isNotEmpty } from '../../shared/empty.util';
|
||||
import { coreSelector } from '../core.selectors';
|
||||
import { URLCombiner } from '../url-combiner/url-combiner';
|
||||
import { IndexState, MetaIndexState } from './index.reducer';
|
||||
import * as parse from 'url-parse';
|
||||
import { IndexName } from './index-name.model';
|
||||
import { CoreState } from '../core-state.model';
|
||||
|
||||
@@ -21,17 +20,21 @@ import { CoreState } from '../core-state.model';
|
||||
*/
|
||||
export const getUrlWithoutEmbedParams = (url: string): string => {
|
||||
if (isNotEmpty(url)) {
|
||||
const parsed = parse(url);
|
||||
if (isNotEmpty(parsed.query)) {
|
||||
const parts = parsed.query.split(/[?|&]/)
|
||||
.filter((part: string) => isNotEmpty(part))
|
||||
.filter((part: string) => !(part.startsWith('embed=') || part.startsWith('embed.size=')));
|
||||
let args = '';
|
||||
if (isNotEmpty(parts)) {
|
||||
args = `?${parts.join('&')}`;
|
||||
try {
|
||||
const parsed = new URL(url);
|
||||
if (isNotEmpty(parsed.search)) {
|
||||
const parts = parsed.search.split(/[?|&]/)
|
||||
.filter((part: string) => isNotEmpty(part))
|
||||
.filter((part: string) => !(part.startsWith('embed=') || part.startsWith('embed.size=')));
|
||||
let args = '';
|
||||
if (isNotEmpty(parts)) {
|
||||
args = `?${parts.join('&')}`;
|
||||
}
|
||||
url = new URLCombiner(parsed.origin, parsed.pathname, args).toString();
|
||||
return url;
|
||||
}
|
||||
url = new URLCombiner(parsed.origin, parsed.pathname, args).toString();
|
||||
return url;
|
||||
} catch (e) {
|
||||
// Ignore parsing errors. By default, we return the original string below.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,15 +47,19 @@ export const getUrlWithoutEmbedParams = (url: string): string => {
|
||||
*/
|
||||
export const getEmbedSizeParams = (url: string): { name: string, size: number }[] => {
|
||||
if (isNotEmpty(url)) {
|
||||
const parsed = parse(url);
|
||||
if (isNotEmpty(parsed.query)) {
|
||||
return parsed.query.split(/[?|&]/)
|
||||
.filter((part: string) => isNotEmpty(part))
|
||||
.map((part: string) => part.match(/^embed.size=([^=]+)=(\d+)$/))
|
||||
.filter((matches: RegExpMatchArray) => hasValue(matches) && hasValue(matches[1]) && hasValue(matches[2]))
|
||||
.map((matches: RegExpMatchArray) => {
|
||||
return { name: matches[1], size: Number(matches[2]) };
|
||||
});
|
||||
try {
|
||||
const parsed = new URL(url);
|
||||
if (isNotEmpty(parsed.search)) {
|
||||
return parsed.search.split(/[?|&]/)
|
||||
.filter((part: string) => isNotEmpty(part))
|
||||
.map((part: string) => part.match(/^embed.size=([^=]+)=(\d+)$/))
|
||||
.filter((matches: RegExpMatchArray) => hasValue(matches) && hasValue(matches[1]) && hasValue(matches[2]))
|
||||
.map((matches: RegExpMatchArray) => {
|
||||
return { name: matches[1], size: Number(matches[2]) };
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// Ignore parsing errors. By default, we return an empty result below.
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line import/no-namespace
|
||||
import * as deepFreeze from 'deep-freeze';
|
||||
|
||||
import {
|
||||
|
@@ -1,8 +1,7 @@
|
||||
import { filter, map, pairwise } from 'rxjs/operators';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Actions, createEffect, ofType } from '@ngrx/effects';
|
||||
import * as fromRouter from '@ngrx/router-store';
|
||||
import { RouterNavigationAction } from '@ngrx/router-store';
|
||||
import { RouterNavigationAction, ROUTER_NAVIGATION } from '@ngrx/router-store';
|
||||
import { Router } from '@angular/router';
|
||||
import { RouteUpdateAction } from './router.actions';
|
||||
|
||||
@@ -14,7 +13,7 @@ export class RouterEffects {
|
||||
*/
|
||||
routeChange$ = createEffect(() => this.actions$
|
||||
.pipe(
|
||||
ofType(fromRouter.ROUTER_NAVIGATION),
|
||||
ofType(ROUTER_NAVIGATION),
|
||||
pairwise(),
|
||||
map((actions: RouterNavigationAction[]) =>
|
||||
actions.map((navigateAction) => {
|
||||
|
@@ -4,7 +4,7 @@ import { ActivatedRoute, NavigationEnd, Params, Router, RouterStateSnapshot, } f
|
||||
|
||||
import { combineLatest, Observable } from 'rxjs';
|
||||
import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store';
|
||||
import { isEqual } from 'lodash';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
|
||||
import { AddParameterAction, SetParameterAction, SetParametersAction, SetQueryParameterAction, SetQueryParametersAction } from './route.actions';
|
||||
import { coreSelector } from '../core.selectors';
|
||||
|
@@ -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';
|
||||
|
@@ -5,7 +5,8 @@ import {
|
||||
MetadataValueFilter,
|
||||
MetadatumViewModel
|
||||
} from './metadata.models';
|
||||
import { groupBy, sortBy } from 'lodash';
|
||||
import groupBy from 'lodash/groupBy';
|
||||
import sortBy from 'lodash/sortBy';
|
||||
|
||||
/**
|
||||
* Utility class for working with DSpace object metadata.
|
||||
|
@@ -26,6 +26,8 @@ import { SearchConfigurationService } from './search-configuration.service';
|
||||
import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub';
|
||||
import { RequestEntry } from '../../data/request-entry.model';
|
||||
import { Angulartics2 } from 'angulartics2';
|
||||
import { SearchFilterConfig } from '../../../shared/search/models/search-filter-config.model';
|
||||
import anything = jasmine.anything;
|
||||
|
||||
@Component({ template: '' })
|
||||
class DummyComponent {
|
||||
@@ -36,7 +38,7 @@ describe('SearchService', () => {
|
||||
let searchService: SearchService;
|
||||
const router = new RouterStub();
|
||||
const route = new ActivatedRouteStub();
|
||||
const searchConfigService = {paginationID: 'page-id'};
|
||||
const searchConfigService = { paginationID: 'page-id' };
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
@@ -103,7 +105,8 @@ describe('SearchService', () => {
|
||||
};
|
||||
|
||||
const paginationService = new PaginationServiceStub();
|
||||
const searchConfigService = {paginationID: 'page-id'};
|
||||
const searchConfigService = { paginationID: 'page-id' };
|
||||
const requestService = getMockRequestService();
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -119,7 +122,7 @@ describe('SearchService', () => {
|
||||
providers: [
|
||||
{ provide: Router, useValue: router },
|
||||
{ provide: RouteService, useValue: routeServiceStub },
|
||||
{ provide: RequestService, useValue: getMockRequestService() },
|
||||
{ provide: RequestService, useValue: requestService },
|
||||
{ provide: RemoteDataBuildService, useValue: remoteDataBuildService },
|
||||
{ provide: HALEndpointService, useValue: halService },
|
||||
{ provide: CommunityDataService, useValue: {} },
|
||||
@@ -138,13 +141,13 @@ describe('SearchService', () => {
|
||||
|
||||
it('should call the navigate method on the Router with view mode list parameter as a parameter when setViewMode is called', () => {
|
||||
searchService.setViewMode(ViewMode.ListElement);
|
||||
expect(paginationService.updateRouteWithUrl).toHaveBeenCalledWith('page-id', ['/search'], {page: 1}, { view: ViewMode.ListElement }
|
||||
expect(paginationService.updateRouteWithUrl).toHaveBeenCalledWith('page-id', ['/search'], { page: 1 }, { view: ViewMode.ListElement }
|
||||
);
|
||||
});
|
||||
|
||||
it('should call the navigate method on the Router with view mode grid parameter as a parameter when setViewMode is called', () => {
|
||||
searchService.setViewMode(ViewMode.GridElement);
|
||||
expect(paginationService.updateRouteWithUrl).toHaveBeenCalledWith('page-id', ['/search'], {page: 1}, { view: ViewMode.GridElement }
|
||||
expect(paginationService.updateRouteWithUrl).toHaveBeenCalledWith('page-id', ['/search'], { page: 1 }, { view: ViewMode.GridElement }
|
||||
);
|
||||
});
|
||||
|
||||
@@ -191,5 +194,23 @@ describe('SearchService', () => {
|
||||
expect((searchService as any).rdb.buildFromHref).toHaveBeenCalledWith(endPoint);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when getFacetValuesFor is called with a filterQuery', () => {
|
||||
it('should add the encoded filterQuery to the args list', () => {
|
||||
jasmine.getEnv().allowRespy(true);
|
||||
const spyRequest = spyOn((searchService as any), 'request').and.stub();
|
||||
spyOn(requestService, 'send').and.returnValue(true);
|
||||
const searchFilterConfig = new SearchFilterConfig();
|
||||
searchFilterConfig._links = {
|
||||
self: {
|
||||
href: 'https://demo.dspace.org/',
|
||||
},
|
||||
};
|
||||
|
||||
searchService.getFacetValuesFor(searchFilterConfig, 1, undefined, 'filter&Query');
|
||||
|
||||
expect(spyRequest).toHaveBeenCalledWith(anything(), 'https://demo.dspace.org?page=0&size=5&prefix=filter%26Query');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -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';
|
||||
@@ -271,7 +270,7 @@ export class SearchService implements OnDestroy {
|
||||
let href;
|
||||
let args: string[] = [];
|
||||
if (hasValue(filterQuery)) {
|
||||
args.push(`prefix=${filterQuery}`);
|
||||
args.push(`prefix=${encodeURIComponent(filterQuery)}`);
|
||||
}
|
||||
if (hasValue(searchOptions)) {
|
||||
searchOptions = Object.assign(new PaginatedSearchOptions({}), searchOptions, {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { EquatableObject, excludeFromEquals, fieldsForEquals } from './equals.decorators';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
|
||||
class Dog extends EquatableObject<Dog> {
|
||||
public name: string;
|
||||
|
@@ -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';
|
||||
|
@@ -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';
|
||||
|
@@ -6,8 +6,7 @@
|
||||
<ds-listable-object-component-loader [object]="item" [viewMode]="viewMode" class="pb-4">
|
||||
</ds-listable-object-component-loader>
|
||||
</div>
|
||||
<button (click)="onLoadMore()" class="btn btn-primary search-button mt-4 float-left ng-tns-c290-40">Load
|
||||
more...</button>
|
||||
<button (click)="onLoadMore()" class="btn btn-primary search-button mt-4 float-left ng-tns-c290-40"> {{'vocabulary-treeview.load-more' | translate }} ...</button>
|
||||
</div>
|
||||
<ds-error *ngIf="itemRD?.hasFailed" message="{{'error.recent-submissions' | translate}}"></ds-error>
|
||||
<ds-loading *ngIf="!itemRD || itemRD.isLoading" message="{{'loading.recent-submissions' | translate}}">
|
||||
|
@@ -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';
|
||||
|
@@ -13,7 +13,7 @@ import { makeStateKey, TransferState } from '@angular/platform-browser';
|
||||
import { APP_CONFIG, AppConfig } from '../config/app-config.interface';
|
||||
import { environment } from '../environments/environment';
|
||||
import { AppState } from './app.reducer';
|
||||
import { isEqual } from 'lodash';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { LocaleService } from './core/locale/locale.service';
|
||||
import { Angulartics2DSpace } from './statistics/angulartics/dspace-provider';
|
||||
|
@@ -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;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { isEqual } from 'lodash';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
@@ -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;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild, ViewContainerRef } from '@angular/core';
|
||||
import { Bitstream } from '../../../../core/shared/bitstream.model';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
|
||||
|
@@ -5,7 +5,7 @@ import {
|
||||
} from '../../../../core/shared/operators';
|
||||
import { hasValue, isNotEmpty } from '../../../../shared/empty.util';
|
||||
import { RegistryService } from '../../../../core/registry/registry.service';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service';
|
||||
|
@@ -3,7 +3,7 @@ import { Item } from '../../../core/shared/item.model';
|
||||
import { ItemDataService } from '../../../core/data/item-data.service';
|
||||
import { ObjectUpdatesService } from '../../../core/data/object-updates/object-updates.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { first, switchMap } from 'rxjs/operators';
|
||||
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
|
||||
import { RemoteData } from '../../../core/data/remote-data';
|
||||
|
@@ -1,18 +1,16 @@
|
||||
<ds-metadata-field-wrapper [label]="label | translate">
|
||||
<ng-container *ngFor="let mdValue of mdValues; let last=last;">
|
||||
<ng-container *ngTemplateOutlet="(renderMarkdown ? markdown : simple); context: {value: mdValue.value, classes: 'dont-break-out preserve-line-breaks'}">
|
||||
<ng-container *ngTemplateOutlet="(renderMarkdown ? markdown : simple); context: {value: mdValue.value}">
|
||||
</ng-container>
|
||||
<span class="separator" *ngIf="!last" [innerHTML]="separator"></span>
|
||||
</ng-container>
|
||||
</ds-metadata-field-wrapper>
|
||||
|
||||
<ng-template #markdown let-value="value" let-classes="classes">
|
||||
<span class="{{classes}}" [innerHTML]="value | dsMarkdown | async">
|
||||
<ng-template #markdown let-value="value">
|
||||
<span class="dont-break-out" [innerHTML]="value | dsMarkdown | async">
|
||||
</span>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #simple let-value="value" let-classes="classes">
|
||||
<span class="{{classes}}">
|
||||
{{value}}
|
||||
</span>
|
||||
<ng-template #simple let-value="value">
|
||||
<span class="dont-break-out preserve-line-breaks">{{value}}</span>
|
||||
</ng-template>
|
||||
|
@@ -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]
|
||||
|
@@ -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 {
|
||||
|
@@ -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]
|
||||
|
@@ -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 {
|
||||
|
@@ -35,4 +35,10 @@ export class GenericItemPageFieldComponent extends ItemPageFieldComponent {
|
||||
*/
|
||||
@Input() label: string;
|
||||
|
||||
/**
|
||||
* Whether the {@link MarkdownPipe} should be used to render this metadata.
|
||||
*/
|
||||
@Input() enableMarkdown = false;
|
||||
|
||||
|
||||
}
|
||||
|
@@ -76,7 +76,7 @@
|
||||
|
||||
<ds-generic-item-page-field [item]="object"
|
||||
[fields]="['dc.subject']"
|
||||
[separator]="','"
|
||||
[separator]="', '"
|
||||
[label]="'item.page.subject'">
|
||||
</ds-generic-item-page-field>
|
||||
<ds-generic-item-page-field [item]="object"
|
||||
|
@@ -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';
|
||||
|
@@ -61,7 +61,7 @@
|
||||
|
||||
<ds-generic-item-page-field [item]="object"
|
||||
[fields]="['dc.subject']"
|
||||
[separator]="','"
|
||||
[separator]="', '"
|
||||
[label]="'item.page.subject'">
|
||||
</ds-generic-item-page-field>
|
||||
<ds-generic-item-page-field [item]="object"
|
||||
|
@@ -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';
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<div class="nav-item dropdown expandable-navbar-section"
|
||||
<div class="nav-item dropdown expandable-navbar-section text-md-center"
|
||||
*ngVar="(active | async) as isActive"
|
||||
(keyup.enter)="isActive ? deactivateSection($event) : activateSection($event)"
|
||||
(keyup.space)="isActive ? deactivateSection($event) : activateSection($event)"
|
||||
|
@@ -1,3 +1,10 @@
|
||||
.expandable-navbar-section {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
overflow: hidden;
|
||||
min-width: 100%;
|
||||
|
@@ -1,3 +1,3 @@
|
||||
<div class="nav-item navbar-section">
|
||||
<div class="nav-item navbar-section text-md-center">
|
||||
<ng-container *ngComponentOutlet="(sectionMap$ | async).get(section.id).component; injector: (sectionMap$ | async).get(section.id).injector;"></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -0,0 +1,5 @@
|
||||
.navbar-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
@@ -1,10 +1,13 @@
|
||||
<nav [ngClass]="{'open': !(menuCollapsed | async)}" [@slideMobileNav]="!(windowService.isXsOrSm() | async) ? 'default' : ((menuCollapsed | async) ? 'collapsed' : 'expanded')"
|
||||
class="navbar navbar-light navbar-expand-md p-md-0 navbar-container" role="navigation" [attr.aria-label]="'nav.main.description' | translate">
|
||||
<!-- TODO remove navbar-container class when https://github.com/twbs/bootstrap/issues/24726 is fixed -->
|
||||
<div class="container">
|
||||
<div class="navbar-inner-container w-100" [class.container]="!(isXsOrSm$ | async)">
|
||||
<div class="reset-padding-md w-100">
|
||||
<div id="collapsingNav">
|
||||
<ul class="navbar-nav navbar-navigation mr-auto shadow-none">
|
||||
<li *ngIf="(isXsOrSm$ | async) && (isAuthenticated$ | async)">
|
||||
<ds-user-menu [inExpandableNavbar]="true"></ds-user-menu>
|
||||
</li>
|
||||
<ng-container *ngFor="let section of (sections | async)">
|
||||
<ng-container *ngComponentOutlet="(sectionMap$ | async).get(section.id)?.component; injector: (sectionMap$ | async).get(section.id)?.injector;"></ng-container>
|
||||
</ng-container>
|
||||
|
@@ -6,13 +6,14 @@ nav.navbar {
|
||||
/** Mobile menu styling **/
|
||||
@media screen and (max-width: map-get($grid-breakpoints, md)-0.02) {
|
||||
.navbar {
|
||||
width: 100vw;
|
||||
width: 100%;
|
||||
background-color: var(--bs-white);
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
height: 0;
|
||||
&.open {
|
||||
height: 100vh; //doesn't matter because wrapper is sticky
|
||||
height: auto;
|
||||
min-height: 100vh; //doesn't matter because wrapper is sticky
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +28,7 @@ nav.navbar {
|
||||
/* TODO remove when https://github.com/twbs/bootstrap/issues/24726 is fixed */
|
||||
.navbar-expand-md.navbar-container {
|
||||
@media screen and (max-width: map-get($grid-breakpoints, md)-0.02) {
|
||||
> .container {
|
||||
> .navbar-inner-container {
|
||||
padding: 0 var(--bs-spacer);
|
||||
}
|
||||
padding: 0;
|
||||
|
@@ -22,9 +22,17 @@ import { Item } from '../core/shared/item.model';
|
||||
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
|
||||
import { ThemeService } from '../shared/theme-support/theme.service';
|
||||
import { getMockThemeService } from '../shared/mocks/theme-service.mock';
|
||||
import { Store, StoreModule } from '@ngrx/store';
|
||||
import { AppState, storeModuleConfig } from '../app.reducer';
|
||||
import { authReducer } from '../core/auth/auth.reducer';
|
||||
import { provideMockStore } from '@ngrx/store/testing';
|
||||
import { AuthTokenInfo } from '../core/auth/models/auth-token-info.model';
|
||||
import { EPersonMock } from '../shared/testing/eperson.mock';
|
||||
|
||||
let comp: NavbarComponent;
|
||||
let fixture: ComponentFixture<NavbarComponent>;
|
||||
let store: Store<AppState>;
|
||||
let initialState: any;
|
||||
|
||||
const authorizationService = jasmine.createSpyObj('authorizationService', {
|
||||
isAuthorized: observableOf(true)
|
||||
@@ -83,10 +91,24 @@ describe('NavbarComponent', () => {
|
||||
}
|
||||
),
|
||||
];
|
||||
initialState = {
|
||||
core: {
|
||||
auth: {
|
||||
authenticated: true,
|
||||
loaded: true,
|
||||
blocking: false,
|
||||
loading: false,
|
||||
authToken: new AuthTokenInfo('test_token'),
|
||||
userId: EPersonMock.id,
|
||||
authMethods: []
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
StoreModule.forRoot({ auth: authReducer }, storeModuleConfig),
|
||||
NoopAnimationsModule,
|
||||
ReactiveFormsModule,
|
||||
RouterTestingModule],
|
||||
@@ -99,6 +121,7 @@ describe('NavbarComponent', () => {
|
||||
{ provide: ActivatedRoute, useValue: routeStub },
|
||||
{ provide: BrowseService, useValue: { getBrowseDefinitions: createSuccessfulRemoteDataObject$(buildPaginatedList(undefined, browseDefinitions)) } },
|
||||
{ provide: AuthorizationDataService, useValue: authorizationService },
|
||||
provideMockStore({ initialState }),
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
})
|
||||
@@ -107,7 +130,7 @@ describe('NavbarComponent', () => {
|
||||
|
||||
// synchronous beforeEach
|
||||
beforeEach(() => {
|
||||
|
||||
store = TestBed.inject(Store);
|
||||
fixture = TestBed.createComponent(NavbarComponent);
|
||||
|
||||
comp = fixture.componentInstance;
|
||||
|
@@ -8,6 +8,10 @@ import { ActivatedRoute } from '@angular/router';
|
||||
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
|
||||
import { MenuID } from '../shared/menu/menu-id.model';
|
||||
import { ThemeService } from '../shared/theme-support/theme.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { select, Store } from '@ngrx/store';
|
||||
import { AppState } from '../app.reducer';
|
||||
import { isAuthenticated } from '../core/auth/selectors';
|
||||
|
||||
/**
|
||||
* Component representing the public navbar
|
||||
@@ -25,18 +29,29 @@ export class NavbarComponent extends MenuComponent {
|
||||
*/
|
||||
menuID = MenuID.PUBLIC;
|
||||
|
||||
/**
|
||||
* Whether user is authenticated.
|
||||
* @type {Observable<string>}
|
||||
*/
|
||||
public isAuthenticated$: Observable<boolean>;
|
||||
|
||||
public isXsOrSm$: Observable<boolean>;
|
||||
|
||||
constructor(protected menuService: MenuService,
|
||||
protected injector: Injector,
|
||||
public windowService: HostWindowService,
|
||||
public browseService: BrowseService,
|
||||
public authorizationService: AuthorizationDataService,
|
||||
public route: ActivatedRoute,
|
||||
protected themeService: ThemeService
|
||||
protected themeService: ThemeService,
|
||||
private store: Store<AppState>,
|
||||
) {
|
||||
super(menuService, injector, authorizationService, route, themeService);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
super.ngOnInit();
|
||||
this.isXsOrSm$ = this.windowService.isXsOrSm();
|
||||
this.isAuthenticated$ = this.store.pipe(select(isAuthenticated));
|
||||
}
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@ import { HostWindowResizeAction } from '../shared/host-window.actions';
|
||||
import { Observable } from 'rxjs';
|
||||
import { provideMockActions } from '@ngrx/effects/testing';
|
||||
import { cold, hot } from 'jasmine-marbles';
|
||||
import * as fromRouter from '@ngrx/router-store';
|
||||
import { ROUTER_NAVIGATION } from '@ngrx/router-store';
|
||||
import { CollapseMenuAction } from '../shared/menu/menu.actions';
|
||||
import { MenuService } from '../shared/menu/menu.service';
|
||||
import { MenuServiceStub } from '../shared/testing/menu-service.stub';
|
||||
@@ -43,7 +43,7 @@ describe('NavbarEffects', () => {
|
||||
describe('routeChange$', () => {
|
||||
|
||||
it('should return a COLLAPSE action in response to an UPDATE_LOCATION action', () => {
|
||||
actions = hot('--a-', { a: { type: fromRouter.ROUTER_NAVIGATION } });
|
||||
actions = hot('--a-', { a: { type: ROUTER_NAVIGATION } });
|
||||
|
||||
const expected = cold('--b-', { b: new CollapseMenuAction(MenuID.PUBLIC) });
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { first, map, switchMap } from 'rxjs/operators';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Actions, createEffect, ofType } from '@ngrx/effects';
|
||||
import * as fromRouter from '@ngrx/router-store';
|
||||
import { ROUTER_NAVIGATION } from '@ngrx/router-store';
|
||||
|
||||
import { HostWindowActionTypes } from '../shared/host-window.actions';
|
||||
import {
|
||||
@@ -33,7 +33,7 @@ export class NavbarEffects {
|
||||
*/
|
||||
routeChange$ = createEffect(() => this.actions$
|
||||
.pipe(
|
||||
ofType(fromRouter.ROUTER_NAVIGATION),
|
||||
ofType(ROUTER_NAVIGATION),
|
||||
map(() => new CollapseMenuAction(this.menuID))
|
||||
));
|
||||
/**
|
||||
|
@@ -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: [
|
||||
|
@@ -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';
|
||||
|
@@ -8,7 +8,7 @@ import { EPerson } from '../../core/eperson/models/eperson.model';
|
||||
import { FormBuilderService } from '../../shared/form/builder/form-builder.service';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { EPersonDataService } from '../../core/eperson/eperson-data.service';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
|
||||
|
||||
describe('ProfilePageMetadataFormComponent', () => {
|
||||
|
@@ -11,7 +11,7 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { hasValue, isNotEmpty } from '../../shared/empty.util';
|
||||
import { LangConfig } from '../../../config/lang-config.interface';
|
||||
import { EPersonDataService } from '../../core/eperson/eperson-data.service';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { getRemoteDataPayload, getFirstSucceededRemoteData } from '../../core/shared/operators';
|
||||
import { FormBuilderService } from '../../shared/form/builder/form-builder.service';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
|
@@ -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,
|
||||
|
@@ -1,9 +1,9 @@
|
||||
<div class="outer-wrapper" [class.d-none]="shouldShowFullscreenLoader">
|
||||
<ds-themed-admin-sidebar></ds-themed-admin-sidebar>
|
||||
<div class="inner-wrapper" [@slideSidebarPadding]="{
|
||||
<div class="outer-wrapper" [class.d-none]="shouldShowFullscreenLoader" [@slideSidebarPadding]="{
|
||||
value: (!(sidebarVisible | async) ? 'hidden' : (slideSidebarOver | async) ? 'shown' : 'expanded'),
|
||||
params: {collapsedSidebarWidth: (collapsedSidebarWidth | async), totalSidebarWidth: (totalSidebarWidth | async)}
|
||||
}">
|
||||
<ds-themed-admin-sidebar></ds-themed-admin-sidebar>
|
||||
<div class="inner-wrapper">
|
||||
<ds-themed-header-navbar-wrapper></ds-themed-header-navbar-wrapper>
|
||||
<main class="main-content">
|
||||
<ds-themed-breadcrumbs></ds-themed-breadcrumbs>
|
||||
|
@@ -17,7 +17,7 @@ import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { RouterMock } from '../shared/mocks/router.mock';
|
||||
import { MockActivatedRoute } from '../shared/mocks/active-router.mock';
|
||||
import { MenuService } from '../shared/menu/menu.service';
|
||||
import { CSSVariableService } from '../shared/sass-helper/sass-helper.service';
|
||||
import { CSSVariableService } from '../shared/sass-helper/css-variable.service';
|
||||
import { CSSVariableServiceStub } from '../shared/testing/css-variable-service.stub';
|
||||
import { HostWindowService } from '../shared/host-window.service';
|
||||
import { HostWindowServiceStub } from '../shared/testing/host-window-service.stub';
|
||||
|
@@ -10,7 +10,7 @@ import { MetadataService } from '../core/metadata/metadata.service';
|
||||
import { HostWindowState } from '../shared/search/host-window.reducer';
|
||||
import { NativeWindowRef, NativeWindowService } from '../core/services/window.service';
|
||||
import { AuthService } from '../core/auth/auth.service';
|
||||
import { CSSVariableService } from '../shared/sass-helper/sass-helper.service';
|
||||
import { CSSVariableService } from '../shared/sass-helper/css-variable.service';
|
||||
import { MenuService } from '../shared/menu/menu.service';
|
||||
import { HostWindowService } from '../shared/host-window.service';
|
||||
import { ThemeConfig } from '../../config/theme.model';
|
||||
@@ -63,8 +63,8 @@ export class RootComponent implements OnInit {
|
||||
ngOnInit() {
|
||||
this.sidebarVisible = this.menuService.isMenuVisible(MenuID.ADMIN);
|
||||
|
||||
this.collapsedSidebarWidth = this.cssService.getVariable('collapsedSidebarWidth');
|
||||
this.totalSidebarWidth = this.cssService.getVariable('totalSidebarWidth');
|
||||
this.collapsedSidebarWidth = this.cssService.getVariable('--ds-collapsed-sidebar-width');
|
||||
this.totalSidebarWidth = this.cssService.getVariable('--ds-total-sidebar-width');
|
||||
|
||||
const sidebarCollapsed = this.menuService.isMenuCollapsed(MenuID.ADMIN);
|
||||
this.slideSidebarOver = combineLatestObservable([sidebarCollapsed, this.windowService.isXsOrSm()])
|
||||
|
@@ -12,7 +12,7 @@ export const slide = trigger('slide', [
|
||||
|
||||
export const slideMobileNav = trigger('slideMobileNav', [
|
||||
|
||||
state('expanded', style({ height: '100vh' })),
|
||||
state('expanded', style({ height: 'auto', 'min-height': '100vh' })),
|
||||
|
||||
state('collapsed', style({ height: 0 })),
|
||||
|
||||
|
@@ -2,11 +2,11 @@
|
||||
<li *ngIf="!(isAuthenticated | async) && !(isXsOrSm$ | async) && (showAuth | async)" class="nav-item"
|
||||
(click)="$event.stopPropagation();">
|
||||
<div ngbDropdown #loginDrop display="dynamic" placement="bottom-right" class="d-inline-block" @fadeInOut>
|
||||
<a href="javascript:void(0);" class="dropdownLogin px-1 " [attr.aria-label]="'nav.login' |translate" (click)="$event.preventDefault()" [attr.data-test]="'login-menu' | dsBrowserOnly" ngbDropdownToggle>
|
||||
{{ 'nav.login' | translate }}
|
||||
</a>
|
||||
<a href="javascript:void(0);" class="dropdownLogin px-1" [attr.aria-label]="'nav.login' |translate"
|
||||
(click)="$event.preventDefault()" [attr.data-test]="'login-menu' | dsBrowserOnly"
|
||||
ngbDropdownToggle>{{ 'nav.login' | translate }}</a>
|
||||
<div class="loginDropdownMenu" [ngClass]="{'pl-3 pr-3': (loading | async)}" ngbDropdownMenu
|
||||
[attr.aria-label]="'nav.login' |translate">
|
||||
[attr.aria-label]="'nav.login' | translate">
|
||||
<ds-log-in
|
||||
[isStandalonePage]="false"></ds-log-in>
|
||||
</div>
|
||||
@@ -19,16 +19,16 @@
|
||||
</li>
|
||||
<li *ngIf="(isAuthenticated | async) && !(isXsOrSm$ | async) && (showAuth | async)" class="nav-item">
|
||||
<div ngbDropdown display="dynamic" placement="bottom-right" class="d-inline-block" @fadeInOut>
|
||||
<a href="javascript:void(0);" role="button" [attr.aria-label]="'nav.logout' |translate" (click)="$event.preventDefault()" [title]="'nav.logout' | translate" class="px-1" [attr.data-test]="'user-menu' | dsBrowserOnly" ngbDropdownToggle>
|
||||
<a href="javascript:void(0);" role="button" [attr.aria-label]="'nav.user-profile-menu-and-logout' |translate" (click)="$event.preventDefault()" [title]="'nav.user-profile-menu-and-logout' | translate" class="px-1" [attr.data-test]="'user-menu' | dsBrowserOnly" ngbDropdownToggle>
|
||||
<i class="fas fa-user-circle fa-lg fa-fw"></i></a>
|
||||
<div class="logoutDropdownMenu" ngbDropdownMenu [attr.aria-label]="'nav.logout' |translate">
|
||||
<div class="logoutDropdownMenu" ngbDropdownMenu [attr.aria-label]="'nav.user-profile-menu-and-logout' |translate">
|
||||
<ds-user-menu></ds-user-menu>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li *ngIf="(isAuthenticated | async) && (isXsOrSm$ | async)" class="nav-item">
|
||||
<a id="logoutLink" role="button" [attr.aria-label]="'nav.logout' |translate" [title]="'nav.logout' | translate" routerLink="/logout" routerLinkActive="active" class="px-1">
|
||||
<i class="fas fa-user-circle fa-lg fa-fw"></i>
|
||||
<i class="fas fa-sign-out-alt fa-lg fa-fw"></i>
|
||||
<span class="sr-only">(current)</span>
|
||||
</a>
|
||||
</li>
|
||||
|
@@ -1,10 +1,13 @@
|
||||
<ds-themed-loading *ngIf="(loading$ | async)"></ds-themed-loading>
|
||||
<div *ngIf="!(loading$ | async)">
|
||||
<span class="dropdown-item-text">{{(user$ | async)?.name}} ({{(user$ | async)?.email}})</span>
|
||||
<a class="dropdown-item" [routerLink]="[profileRoute]" routerLinkActive="active">{{'nav.profile' | translate}}</a>
|
||||
<a class="dropdown-item" [routerLink]="[mydspaceRoute]" routerLinkActive="active">{{'nav.mydspace' | translate}}</a>
|
||||
<span class="dropdown-item-text" [class.pl-0]="inExpandableNavbar">
|
||||
{{(user$ | async)?.name}}<br>
|
||||
<span class="text-muted">{{(user$ | async)?.email}}</span>
|
||||
</span>
|
||||
<a [ngClass]="inExpandableNavbar ? 'nav-item nav-link' : 'dropdown-item'" [routerLink]="[profileRoute]" routerLinkActive="active">{{'nav.profile' | translate}}</a>
|
||||
<a [ngClass]="inExpandableNavbar ? 'nav-item nav-link' : 'dropdown-item'" [routerLink]="[mydspaceRoute]" routerLinkActive="active">{{'nav.mydspace' | translate}}</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<ds-log-out></ds-log-out>
|
||||
<ds-log-out *ngIf="!inExpandableNavbar" data-test="log-out-component"></ds-log-out>
|
||||
</div>
|
||||
|
||||
|
||||
|
@@ -162,10 +162,24 @@ describe('UserMenuComponent', () => {
|
||||
});
|
||||
|
||||
it('should display user name and email', () => {
|
||||
const user = 'User Test (test@test.com)';
|
||||
const username = 'User Test';
|
||||
const email = 'test@test.com';
|
||||
const span = deUserMenu.query(By.css('.dropdown-item-text'));
|
||||
expect(span).toBeDefined();
|
||||
expect(span.nativeElement.innerHTML).toBe(user);
|
||||
expect(span.nativeElement.innerHTML).toContain(username);
|
||||
expect(span.nativeElement.innerHTML).toContain(email);
|
||||
});
|
||||
|
||||
it('should create logout component', () => {
|
||||
const components = fixture.debugElement.query(By.css('[data-test="log-out-component"]'));
|
||||
expect(components).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not create logout component', () => {
|
||||
component.inExpandableNavbar = true;
|
||||
fixture.detectChanges();
|
||||
const components = fixture.debugElement.query(By.css('[data-test="log-out-component"]'));
|
||||
expect(components).toBeFalsy();
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { select, Store } from '@ngrx/store';
|
||||
@@ -20,6 +20,11 @@ import { getProfileModuleRoute } from '../../../app-routing-paths';
|
||||
})
|
||||
export class UserMenuComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* The input flag to show user details in navbar expandable menu
|
||||
*/
|
||||
@Input() inExpandableNavbar = false;
|
||||
|
||||
/**
|
||||
* True if the authentication is loading.
|
||||
* @type {Observable<boolean>}
|
||||
|
@@ -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';
|
||||
|
@@ -10,7 +10,8 @@ import { AuthService } from '../../core/auth/auth.service';
|
||||
import { CookieService } from '../../core/services/cookie.service';
|
||||
import { getTestScheduler } from 'jasmine-marbles';
|
||||
import { MetadataValue } from '../../core/shared/metadata.models';
|
||||
import { clone, cloneDeep } from 'lodash';
|
||||
import clone from 'lodash/clone';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { ConfigurationDataService } from '../../core/data/configuration-data.service';
|
||||
import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../remote-data.utils';
|
||||
import { ConfigurationProperty } from '../../core/shared/configuration-property.model';
|
||||
@@ -100,7 +101,7 @@ describe('BrowserKlaroService', () => {
|
||||
|
||||
mockConfig = {
|
||||
translations: {
|
||||
en: {
|
||||
zz: {
|
||||
purposes: {},
|
||||
test: {
|
||||
testeritis: testKey
|
||||
@@ -158,8 +159,8 @@ describe('BrowserKlaroService', () => {
|
||||
|
||||
it('addAppMessages', () => {
|
||||
service.addAppMessages();
|
||||
expect(mockConfig.translations.en[appName]).toBeDefined();
|
||||
expect(mockConfig.translations.en.purposes[purpose]).toBeDefined();
|
||||
expect(mockConfig.translations.zz[appName]).toBeDefined();
|
||||
expect(mockConfig.translations.zz.purposes[purpose]).toBeDefined();
|
||||
});
|
||||
|
||||
it('translateConfiguration', () => {
|
||||
|
@@ -9,7 +9,8 @@ import { KlaroService } from './klaro.service';
|
||||
import { hasValue, isEmpty, isNotEmpty } from '../empty.util';
|
||||
import { CookieService } from '../../core/services/cookie.service';
|
||||
import { EPersonDataService } from '../../core/eperson/eperson-data.service';
|
||||
import { cloneDeep, debounce } from 'lodash';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { ANONYMOUS_STORAGE_NAME_KLARO, klaroConfiguration } from './klaro-configuration';
|
||||
import { Operation } from 'fast-json-patch';
|
||||
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
|
||||
@@ -90,7 +91,7 @@ export class BrowserKlaroService extends KlaroService {
|
||||
initialize() {
|
||||
if (!environment.info.enablePrivacyStatement) {
|
||||
delete this.klaroConfig.privacyPolicy;
|
||||
this.klaroConfig.translations.en.consentNotice.description = 'cookies.consent.content-notice.description.no-privacy';
|
||||
this.klaroConfig.translations.zz.consentNotice.description = 'cookies.consent.content-notice.description.no-privacy';
|
||||
}
|
||||
|
||||
const hideGoogleAnalytics$ = this.configService.findByPropertyName(this.GOOGLE_ANALYTICS_KEY).pipe(
|
||||
@@ -238,12 +239,12 @@ export class BrowserKlaroService extends KlaroService {
|
||||
*/
|
||||
addAppMessages() {
|
||||
this.klaroConfig.services.forEach((app) => {
|
||||
this.klaroConfig.translations.en[app.name] = {
|
||||
this.klaroConfig.translations.zz[app.name] = {
|
||||
title: this.getTitleTranslation(app.name),
|
||||
description: this.getDescriptionTranslation(app.name)
|
||||
};
|
||||
app.purposes.forEach((purpose) => {
|
||||
this.klaroConfig.translations.en.purposes[purpose] = this.getPurposeTranslation(purpose);
|
||||
this.klaroConfig.translations.zz.purposes[purpose] = this.getPurposeTranslation(purpose);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -257,7 +258,7 @@ export class BrowserKlaroService extends KlaroService {
|
||||
*/
|
||||
this.translateService.setDefaultLang(environment.defaultLanguage);
|
||||
|
||||
this.translate(this.klaroConfig.translations.en);
|
||||
this.translate(this.klaroConfig.translations.zz);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -54,10 +54,46 @@ export const klaroConfiguration: any = {
|
||||
https://github.com/KIProtect/klaro/tree/master/src/translations
|
||||
*/
|
||||
translations: {
|
||||
en: {
|
||||
/*
|
||||
The `zz` key contains default translations that will be used as fallback values.
|
||||
This can e.g. be useful for defining a fallback privacy policy URL.
|
||||
FOR DSPACE: We use 'zz' to map to our own i18n translations for klaro, see
|
||||
translateConfiguration() in browser-klaro.service.ts. All the below i18n keys are specified
|
||||
in your /src/assets/i18n/*.json5 translation pack.
|
||||
*/
|
||||
zz: {
|
||||
acceptAll: 'cookies.consent.accept-all',
|
||||
acceptSelected: 'cookies.consent.accept-selected',
|
||||
app: {
|
||||
close: 'cookies.consent.close',
|
||||
consentModal: {
|
||||
title: 'cookies.consent.content-modal.title',
|
||||
description: 'cookies.consent.content-modal.description'
|
||||
},
|
||||
consentNotice: {
|
||||
changeDescription: 'cookies.consent.update',
|
||||
title: 'cookies.consent.content-notice.title',
|
||||
description: 'cookies.consent.content-notice.description',
|
||||
learnMore: 'cookies.consent.content-notice.learnMore',
|
||||
},
|
||||
decline: 'cookies.consent.decline',
|
||||
ok: 'cookies.consent.ok',
|
||||
poweredBy: 'Powered by Klaro!',
|
||||
privacyPolicy: {
|
||||
name: 'cookies.consent.content-modal.privacy-policy.name',
|
||||
text: 'cookies.consent.content-modal.privacy-policy.text'
|
||||
},
|
||||
purposeItem: {
|
||||
service: 'cookies.consent.content-modal.service',
|
||||
services: 'cookies.consent.content-modal.services'
|
||||
},
|
||||
purposes: {
|
||||
},
|
||||
save: 'cookies.consent.save',
|
||||
service: {
|
||||
disableAll: {
|
||||
description: 'cookies.consent.app.disable-all.description',
|
||||
title: 'cookies.consent.app.disable-all.title'
|
||||
},
|
||||
optOut: {
|
||||
description: 'cookies.consent.app.opt-out.description',
|
||||
title: 'cookies.consent.app.opt-out.title'
|
||||
@@ -65,26 +101,10 @@ export const klaroConfiguration: any = {
|
||||
purpose: 'cookies.consent.app.purpose',
|
||||
purposes: 'cookies.consent.app.purposes',
|
||||
required: {
|
||||
description: 'cookies.consent.app.required.description',
|
||||
title: 'cookies.consent.app.required.title'
|
||||
title: 'cookies.consent.app.required.title',
|
||||
description: 'cookies.consent.app.required.description'
|
||||
}
|
||||
},
|
||||
close: 'cookies.consent.close',
|
||||
decline: 'cookies.consent.decline',
|
||||
changeDescription: 'cookies.consent.update',
|
||||
consentNotice: {
|
||||
description: 'cookies.consent.content-notice.description',
|
||||
learnMore: 'cookies.consent.content-notice.learnMore'
|
||||
},
|
||||
consentModal: {
|
||||
description: 'cookies.consent.content-modal.description',
|
||||
privacyPolicy: {
|
||||
name: 'cookies.consent.content-modal.privacy-policy.name',
|
||||
text: 'cookies.consent.content-modal.privacy-policy.text'
|
||||
},
|
||||
title: 'cookies.consent.content-modal.title'
|
||||
},
|
||||
purposes: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
services: [
|
||||
|
107
src/app/shared/date.util.spec.ts
Normal file
107
src/app/shared/date.util.spec.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import { dateToString, dateToNgbDateStruct, dateToISOFormat, isValidDate, yearFromString } from './date.util';
|
||||
|
||||
describe('Date Utils', () => {
|
||||
|
||||
describe('dateToISOFormat', () => {
|
||||
it('should convert Date to YYYY-MM-DDThh:mm:ssZ string', () => {
|
||||
// NOTE: month is zero indexed which is why it increases by one
|
||||
expect(dateToISOFormat(new Date(Date.UTC(2022, 5, 3)))).toEqual('2022-06-03T00:00:00Z');
|
||||
});
|
||||
it('should convert Date string to YYYY-MM-DDThh:mm:ssZ string', () => {
|
||||
expect(dateToISOFormat('2022-06-03')).toEqual('2022-06-03T00:00:00Z');
|
||||
});
|
||||
it('should convert Month string to YYYY-MM-DDThh:mm:ssZ string', () => {
|
||||
expect(dateToISOFormat('2022-06')).toEqual('2022-06-01T00:00:00Z');
|
||||
});
|
||||
it('should convert Year string to YYYY-MM-DDThh:mm:ssZ string', () => {
|
||||
expect(dateToISOFormat('2022')).toEqual('2022-01-01T00:00:00Z');
|
||||
});
|
||||
it('should convert ISO Date string to YYYY-MM-DDThh:mm:ssZ string', () => {
|
||||
// NOTE: Time is always zeroed out as proven by this test.
|
||||
expect(dateToISOFormat('2022-06-03T03:24:04Z')).toEqual('2022-06-03T00:00:00Z');
|
||||
});
|
||||
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(Date.UTC(2022, 5, 3));
|
||||
expect(dateToISOFormat(dateToNgbDateStruct(date))).toEqual('2022-06-03T00:00:00Z');
|
||||
});
|
||||
});
|
||||
|
||||
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(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(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(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(Date.UTC(2022, 5, 3));
|
||||
expect(dateToString(dateToNgbDateStruct(date))).toEqual('2022-06-03');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('isValidDate', () => {
|
||||
it('should return false for null', () => {
|
||||
expect(isValidDate(null)).toBe(false);
|
||||
});
|
||||
it('should return false for empty string', () => {
|
||||
expect(isValidDate('')).toBe(false);
|
||||
});
|
||||
it('should return false for text', () => {
|
||||
expect(isValidDate('test')).toBe(false);
|
||||
});
|
||||
it('should return true for YYYY', () => {
|
||||
expect(isValidDate('2022')).toBe(true);
|
||||
});
|
||||
it('should return true for YYYY-MM', () => {
|
||||
expect(isValidDate('2022-12')).toBe(true);
|
||||
});
|
||||
it('should return true for YYYY-MM-DD', () => {
|
||||
expect(isValidDate('2022-06-03')).toBe(true);
|
||||
});
|
||||
it('should return true for YYYY-MM-DDTHH:MM:SS', () => {
|
||||
expect(isValidDate('2022-06-03T10:20:30')).toBe(true);
|
||||
});
|
||||
it('should return true for YYYY-MM-DDTHH:MM:SSZ', () => {
|
||||
expect(isValidDate('2022-06-03T10:20:30Z')).toBe(true);
|
||||
});
|
||||
it('should return false for a month that does not exist', () => {
|
||||
expect(isValidDate('2022-13')).toBe(false);
|
||||
});
|
||||
it('should return false for a day that does not exist', () => {
|
||||
expect(isValidDate('2022-02-60')).toBe(false);
|
||||
});
|
||||
it('should return false for a time that does not exist', () => {
|
||||
expect(isValidDate('2022-02-60T10:60:20')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('yearFromString', () => {
|
||||
it('should return year from YYYY string', () => {
|
||||
expect(yearFromString('2022')).toEqual(2022);
|
||||
});
|
||||
it('should return year from YYYY-MM string', () => {
|
||||
expect(yearFromString('1970-06')).toEqual(1970);
|
||||
});
|
||||
it('should return year from YYYY-MM-DD string', () => {
|
||||
expect(yearFromString('1914-10-23')).toEqual(1914);
|
||||
});
|
||||
it('should return year from YYYY-MM-DDTHH:MM:SSZ string', () => {
|
||||
expect(yearFromString('1914-10-23T10:20:30Z')).toEqual(1914);
|
||||
});
|
||||
it('should return null if invalid date', () => {
|
||||
expect(yearFromString('test')).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,9 +1,8 @@
|
||||
import { NgbDateStruct } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
import { isObject } from 'lodash';
|
||||
import * as moment from 'moment';
|
||||
|
||||
import { isNull, isUndefined } from './empty.util';
|
||||
import { formatInTimeZone } from 'date-fns-tz';
|
||||
import { isValid } from 'date-fns';
|
||||
import isObject from 'lodash/isObject';
|
||||
import { hasNoValue } from './empty.util';
|
||||
|
||||
/**
|
||||
* Returns true if the passed value is a NgbDateStruct.
|
||||
@@ -31,21 +30,7 @@ export function dateToISOFormat(date: Date | NgbDateStruct | string): string {
|
||||
const dateObj: Date = (date instanceof Date) ? date :
|
||||
((typeof date === 'string') ? ngbDateStructToDate(stringToNgbDateStruct(date)) : ngbDateStructToDate(date));
|
||||
|
||||
let year = dateObj.getUTCFullYear().toString();
|
||||
let month = (dateObj.getUTCMonth() + 1).toString();
|
||||
let day = dateObj.getUTCDate().toString();
|
||||
let hour = dateObj.getHours().toString();
|
||||
let min = dateObj.getMinutes().toString();
|
||||
let sec = dateObj.getSeconds().toString();
|
||||
|
||||
year = (year.length === 1) ? '0' + year : year;
|
||||
month = (month.length === 1) ? '0' + month : month;
|
||||
day = (day.length === 1) ? '0' + day : day;
|
||||
hour = (hour.length === 1) ? '0' + hour : hour;
|
||||
min = (min.length === 1) ? '0' + min : min;
|
||||
sec = (sec.length === 1) ? '0' + sec : sec;
|
||||
const dateStr = `${year}${month}${day}${hour}${min}${sec}`;
|
||||
return moment.utc(dateStr, 'YYYYMMDDhhmmss').format();
|
||||
return formatInTimeZone(dateObj, 'UTC', "yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,7 +66,7 @@ export function stringToNgbDateStruct(date: string): NgbDateStruct {
|
||||
* the NgbDateStruct object
|
||||
*/
|
||||
export function dateToNgbDateStruct(date?: Date): NgbDateStruct {
|
||||
if (isNull(date) || isUndefined(date)) {
|
||||
if (hasNoValue(date)) {
|
||||
date = new Date();
|
||||
}
|
||||
|
||||
@@ -102,16 +87,7 @@ export function dateToNgbDateStruct(date?: Date): NgbDateStruct {
|
||||
*/
|
||||
export function dateToString(date: Date | NgbDateStruct): string {
|
||||
const dateObj: Date = (date instanceof Date) ? date : ngbDateStructToDate(date);
|
||||
|
||||
let year = dateObj.getUTCFullYear().toString();
|
||||
let month = (dateObj.getUTCMonth() + 1).toString();
|
||||
let day = dateObj.getUTCDate().toString();
|
||||
|
||||
year = (year.length === 1) ? '0' + year : year;
|
||||
month = (month.length === 1) ? '0' + month : month;
|
||||
day = (day.length === 1) ? '0' + day : day;
|
||||
const dateStr = `${year}-${month}-${day}`;
|
||||
return moment.utc(dateStr, 'YYYYMMDD').format('YYYY-MM-DD');
|
||||
return formatInTimeZone(dateObj, 'UTC', 'yyyy-MM-dd');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,5 +95,15 @@ export function dateToString(date: Date | NgbDateStruct): string {
|
||||
* @param date the string to be checked
|
||||
*/
|
||||
export function isValidDate(date: string) {
|
||||
return moment(date).isValid();
|
||||
return (hasNoValue(date)) ? false : isValid(new Date(date));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse given date string to a year number based on expected formats
|
||||
* @param date the string to be parsed
|
||||
* @param formats possible formats the string may align with. MUST be valid date-fns formats
|
||||
*/
|
||||
export function yearFromString(date: string) {
|
||||
return isValidDate(date) ? new Date(date).getUTCFullYear() : null;
|
||||
}
|
||||
|
||||
|
@@ -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(),
|
||||
|
@@ -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"
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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>
|
||||
|
||||
|
@@ -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';
|
||||
|
@@ -1,4 +1,10 @@
|
||||
import { DynamicFormControlLayout, DynamicFormGroupModel, DynamicFormGroupModelConfig, serializable } from '@ng-dynamic-forms/core';
|
||||
import {
|
||||
DynamicFormControlLayout,
|
||||
DynamicFormControlRelation,
|
||||
DynamicFormGroupModel,
|
||||
DynamicFormGroupModelConfig,
|
||||
serializable
|
||||
} from '@ng-dynamic-forms/core';
|
||||
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
@@ -16,6 +22,7 @@ export interface DynamicConcatModelConfig extends DynamicFormGroupModelConfig {
|
||||
separator: string;
|
||||
value?: any;
|
||||
hint?: string;
|
||||
typeBindRelations?: DynamicFormControlRelation[];
|
||||
relationship?: RelationshipOptions;
|
||||
repeatable: boolean;
|
||||
required: boolean;
|
||||
@@ -29,6 +36,8 @@ export class DynamicConcatModel extends DynamicFormGroupModel {
|
||||
|
||||
@serializable() separator: string;
|
||||
@serializable() hasLanguages = false;
|
||||
@serializable() typeBindRelations: DynamicFormControlRelation[];
|
||||
@serializable() typeBindHidden = false;
|
||||
@serializable() relationship?: RelationshipOptions;
|
||||
@serializable() repeatable?: boolean;
|
||||
@serializable() required?: boolean;
|
||||
@@ -55,6 +64,7 @@ export class DynamicConcatModel extends DynamicFormGroupModel {
|
||||
this.metadataValue = config.metadataValue;
|
||||
this.valueUpdates = new Subject<string>();
|
||||
this.valueUpdates.subscribe((value: string) => this.value = value);
|
||||
this.typeBindRelations = config.typeBindRelations ? config.typeBindRelations : [];
|
||||
}
|
||||
|
||||
get value() {
|
||||
|
@@ -2,6 +2,7 @@ import { Subject } from 'rxjs';
|
||||
import {
|
||||
DynamicCheckboxGroupModel,
|
||||
DynamicFormControlLayout,
|
||||
DynamicFormControlRelation,
|
||||
DynamicFormGroupModelConfig,
|
||||
serializable
|
||||
} from '@ng-dynamic-forms/core';
|
||||
@@ -15,6 +16,7 @@ export interface DynamicListCheckboxGroupModelConfig extends DynamicFormGroupMod
|
||||
groupLength?: number;
|
||||
repeatable: boolean;
|
||||
value?: any;
|
||||
typeBindRelations?: DynamicFormControlRelation[];
|
||||
}
|
||||
|
||||
export class DynamicListCheckboxGroupModel extends DynamicCheckboxGroupModel {
|
||||
@@ -23,6 +25,7 @@ export class DynamicListCheckboxGroupModel extends DynamicCheckboxGroupModel {
|
||||
@serializable() repeatable: boolean;
|
||||
@serializable() groupLength: number;
|
||||
@serializable() _value: VocabularyEntry[];
|
||||
@serializable() typeBindRelations: DynamicFormControlRelation[];
|
||||
isListGroup = true;
|
||||
valueUpdates: Subject<any>;
|
||||
|
||||
@@ -37,6 +40,7 @@ export class DynamicListCheckboxGroupModel extends DynamicCheckboxGroupModel {
|
||||
this.valueUpdates = new Subject<any>();
|
||||
this.valueUpdates.subscribe((value: VocabularyEntry | VocabularyEntry[]) => this.value = value);
|
||||
this.valueUpdates.next(config.value);
|
||||
this.typeBindRelations = config.typeBindRelations ? config.typeBindRelations : [];
|
||||
}
|
||||
|
||||
get hasAuthority(): boolean {
|
||||
|
@@ -7,7 +7,7 @@ import {
|
||||
DynamicFormLayoutService,
|
||||
DynamicFormValidationService
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { findKey } from 'lodash';
|
||||
import findKey from 'lodash/findKey';
|
||||
|
||||
import { hasValue, isNotEmpty } from '../../../../../empty.util';
|
||||
import { DynamicListCheckboxGroupModel } from './dynamic-list-checkbox-group.model';
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user