mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-08 18:44:14 +00:00
Finished refactoring, guards, docs, tests
This commit is contained in:
@@ -1,73 +0,0 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
import { SharedModule } from '../../shared/shared.module';
|
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
|
||||||
import { By } from '@angular/platform-browser';
|
|
||||||
import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
|
|
||||||
import { CollectionFormComponent } from './collection-form.component';
|
|
||||||
import { Location } from '@angular/common';
|
|
||||||
import { DynamicFormService } from '@ng-dynamic-forms/core';
|
|
||||||
|
|
||||||
describe('CommunityFormComponent', () => {
|
|
||||||
let comp: CollectionFormComponent;
|
|
||||||
let fixture: ComponentFixture<CollectionFormComponent>
|
|
||||||
let location: Location;
|
|
||||||
|
|
||||||
/* tslint:disable:no-empty */
|
|
||||||
const locationStub = {
|
|
||||||
back: () => {}
|
|
||||||
};
|
|
||||||
/* tslint:enable:no-empty */
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
|
||||||
declarations: [CollectionFormComponent],
|
|
||||||
providers: [
|
|
||||||
{ provide: Location, useValue: locationStub },
|
|
||||||
],
|
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
|
||||||
}).compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(CollectionFormComponent);
|
|
||||||
comp = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
location = (comp as any).location;
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when submitting', () => {
|
|
||||||
let input: DebugElement;
|
|
||||||
let submit: DebugElement;
|
|
||||||
let cancel: DebugElement;
|
|
||||||
let error: DebugElement;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
input = fixture.debugElement.query(By.css('input#collection-name'));
|
|
||||||
submit = fixture.debugElement.query(By.css('button#collection-submit'));
|
|
||||||
cancel = fixture.debugElement.query(By.css('button#collection-cancel'));
|
|
||||||
error = fixture.debugElement.query(By.css('div.invalid-feedback'));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should display an error when leaving name empty', () => {
|
|
||||||
const el = input.nativeElement;
|
|
||||||
|
|
||||||
el.value = '';
|
|
||||||
el.dispatchEvent(new Event('input'));
|
|
||||||
submit.nativeElement.click();
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
expect(error.nativeElement.style.display).not.toEqual('none');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should navigate back when pressing cancel', () => {
|
|
||||||
spyOn(location, 'back');
|
|
||||||
cancel.nativeElement.click();
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
expect(location.back).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
})
|
|
||||||
});
|
|
@@ -6,16 +6,31 @@ import {
|
|||||||
import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model';
|
import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model';
|
||||||
import { ResourceType } from '../../core/shared/resource-type';
|
import { ResourceType } from '../../core/shared/resource-type';
|
||||||
import { Collection } from '../../core/shared/collection.model';
|
import { Collection } from '../../core/shared/collection.model';
|
||||||
import { ComColFormComponent } from '../../comcol-forms/comcol-form/comcol-form.component';
|
import { ComColFormComponent } from '../../shared/comcol-forms/comcol-form/comcol-form.component';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form used for creating and editing collections
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-collection-form',
|
selector: 'ds-collection-form',
|
||||||
styleUrls: ['../../comcol-forms/comcol-form.component.scss'],
|
styleUrls: ['../../shared/comcol-forms/comcol-form/comcol-form.component.scss'],
|
||||||
templateUrl: '../../comcol-forms/comcol-form/comcol-form.component.html'
|
templateUrl: '../../shared/comcol-forms/comcol-form/comcol-form.component.html'
|
||||||
})
|
})
|
||||||
export class CollectionFormComponent extends ComColFormComponent<Collection> {
|
export class CollectionFormComponent extends ComColFormComponent<Collection> {
|
||||||
|
/**
|
||||||
|
* @type {Collection} A new collection when a collection is being created, an existing Input collection when a collection is being edited
|
||||||
|
*/
|
||||||
@Input() dso: Collection = new Collection();
|
@Input() dso: Collection = new Collection();
|
||||||
type = ResourceType.Collection;
|
|
||||||
|
/**
|
||||||
|
* @type {ResourceType.Collection} This is a collection-type form
|
||||||
|
*/
|
||||||
|
protected type = ResourceType.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The dynamic form fields used for creating/editing a collection
|
||||||
|
* @type {(DynamicInputModel | DynamicTextAreaModel)[]}
|
||||||
|
*/
|
||||||
formModel: DynamicFormControlModel[] = [
|
formModel: DynamicFormControlModel[] = [
|
||||||
new DynamicInputModel({
|
new DynamicInputModel({
|
||||||
id: 'title',
|
id: 'title',
|
||||||
|
@@ -5,13 +5,26 @@ import { CollectionPageComponent } from './collection-page.component';
|
|||||||
import { CollectionPageResolver } from './collection-page.resolver';
|
import { CollectionPageResolver } from './collection-page.resolver';
|
||||||
import { CreateCollectionPageComponent } from './create-collection-page/create-collection-page.component';
|
import { CreateCollectionPageComponent } from './create-collection-page/create-collection-page.component';
|
||||||
import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
|
import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
|
||||||
|
import { EditCollectionPageComponent } from './edit-collection-page/edit-collection-page.component';
|
||||||
|
import { CreateCollectionPageGuard } from './create-collection-page/create-collection-page.guard';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
RouterModule.forChild([
|
RouterModule.forChild([
|
||||||
{ path: 'create',
|
{
|
||||||
|
path: 'create',
|
||||||
component: CreateCollectionPageComponent,
|
component: CreateCollectionPageComponent,
|
||||||
canActivate: [AuthenticatedGuard] },
|
canActivate: [AuthenticatedGuard, CreateCollectionPageGuard]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ':id/edit',
|
||||||
|
pathMatch: 'full',
|
||||||
|
component: EditCollectionPageComponent,
|
||||||
|
canActivate: [AuthenticatedGuard],
|
||||||
|
resolve: {
|
||||||
|
dso: CollectionPageResolver
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: ':id',
|
path: ':id',
|
||||||
component: CollectionPageComponent,
|
component: CollectionPageComponent,
|
||||||
@@ -24,6 +37,7 @@ import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
|
|||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
CollectionPageResolver,
|
CollectionPageResolver,
|
||||||
|
CreateCollectionPageGuard
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class CollectionPageRoutingModule {
|
export class CollectionPageRoutingModule {
|
||||||
|
@@ -55,7 +55,8 @@ export class CollectionPageComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.collectionRD$ = this.route.data.pipe(
|
this.collectionRD$ = this.route.data.pipe(
|
||||||
map((data) => data.collection)
|
map((data) => data.collection),
|
||||||
|
tap((data) => this.collectionId = data.payload.id)
|
||||||
);
|
);
|
||||||
this.logoRD$ = this.collectionRD$.pipe(
|
this.logoRD$ = this.collectionRD$.pipe(
|
||||||
map((rd: RemoteData<Collection>) => rd.payload),
|
map((rd: RemoteData<Collection>) => rd.payload),
|
||||||
|
@@ -8,6 +8,7 @@ import { CollectionPageRoutingModule } from './collection-page-routing.module';
|
|||||||
import { CreateCollectionPageComponent } from './create-collection-page/create-collection-page.component';
|
import { CreateCollectionPageComponent } from './create-collection-page/create-collection-page.component';
|
||||||
import { CollectionFormComponent } from './collection-form/collection-form.component';
|
import { CollectionFormComponent } from './collection-form/collection-form.component';
|
||||||
import { SearchPageModule } from '../+search-page/search-page.module';
|
import { SearchPageModule } from '../+search-page/search-page.module';
|
||||||
|
import { EditCollectionPageComponent } from './edit-collection-page/edit-collection-page.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -19,6 +20,7 @@ import { SearchPageModule } from '../+search-page/search-page.module';
|
|||||||
declarations: [
|
declarations: [
|
||||||
CollectionPageComponent,
|
CollectionPageComponent,
|
||||||
CreateCollectionPageComponent,
|
CreateCollectionPageComponent,
|
||||||
|
EditCollectionPageComponent,
|
||||||
CollectionFormComponent
|
CollectionFormComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@@ -1,10 +1,7 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 pb-4">
|
<div class="col-12 pb-4">
|
||||||
<ng-container *ngVar="(parentUUID$ | async)?.payload as parent">
|
<h2 id="sub-header" class="border-bottom pb-2">{{'collection.create.sub-head' | translate:{ parent: (parentRD$| async)?.payload.name } }}</h2>
|
||||||
<h2 *ngIf="!parent" id="header" class="border-bottom pb-2">{{ 'collection.create.head' | translate }}</h2>
|
|
||||||
<h2 *ngIf="parent" id="sub-header" class="border-bottom pb-2">{{ 'collection.create.sub-head' | translate:{ parent: parent.name } }}</h2>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ds-collection-form (submitForm)="onSubmit($event)"></ds-collection-form>
|
<ds-collection-form (submitForm)="onSubmit($event)"></ds-collection-form>
|
||||||
|
@@ -1,108 +0,0 @@
|
|||||||
import { SharedModule } from '../../shared/shared.module';
|
|
||||||
import { Community } from '../../core/shared/community.model';
|
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
import { CommonModule, Location } from '@angular/common';
|
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
|
||||||
import { RouteService } from '../../shared/services/route.service';
|
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
|
||||||
import { CreateCollectionPageComponent } from './create-collection-page.component';
|
|
||||||
import { CollectionDataService } from '../../core/data/collection-data.service';
|
|
||||||
import { Collection } from '../../core/shared/collection.model';
|
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
|
||||||
import { CollectionFormComponent } from '../collection-form/collection-form.component';
|
|
||||||
import { of as observableOf } from 'rxjs';
|
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
|
||||||
|
|
||||||
describe('CreateCollectionPageComponent', () => {
|
|
||||||
let comp: CreateCollectionPageComponent;
|
|
||||||
let fixture: ComponentFixture<CreateCollectionPageComponent>;
|
|
||||||
let collectionDataService: CollectionDataService;
|
|
||||||
let communityDataService: CommunityDataService;
|
|
||||||
let routeService: RouteService;
|
|
||||||
let router: Router;
|
|
||||||
|
|
||||||
const community = Object.assign(new Community(), {
|
|
||||||
uuid: 'a20da287-e174-466a-9926-f66b9300d347',
|
|
||||||
metadata: [{
|
|
||||||
key: 'dc.title',
|
|
||||||
value: 'test collection'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
|
|
||||||
const collection = Object.assign(new Collection(), {
|
|
||||||
uuid: 'ce41d451-97ed-4a9c-94a1-7de34f16a9f4',
|
|
||||||
metadata: [{
|
|
||||||
key: 'dc.title',
|
|
||||||
value: 'new collection'
|
|
||||||
}] });
|
|
||||||
|
|
||||||
const collectionDataServiceStub = {
|
|
||||||
create: (col, uuid?) => observableOf(new RemoteData(false, false, true, undefined, collection))
|
|
||||||
};
|
|
||||||
const communityDataServiceStub = {
|
|
||||||
findById: (uuid) => observableOf(new RemoteData(false, false, true, null, Object.assign(new Community(), {
|
|
||||||
uuid: uuid,
|
|
||||||
metadata: [{
|
|
||||||
key: 'dc.title',
|
|
||||||
value: community.name
|
|
||||||
}]
|
|
||||||
})))
|
|
||||||
};
|
|
||||||
const routeServiceStub = {
|
|
||||||
getQueryParameterValue: (param) => observableOf(community.uuid)
|
|
||||||
};
|
|
||||||
const routerStub = {
|
|
||||||
navigate: (commands) => commands
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
|
||||||
declarations: [CreateCollectionPageComponent],
|
|
||||||
providers: [
|
|
||||||
{ provide: CollectionDataService, useValue: collectionDataServiceStub },
|
|
||||||
{ provide: CommunityDataService, useValue: communityDataServiceStub },
|
|
||||||
{ provide: RouteService, useValue: routeServiceStub },
|
|
||||||
{ provide: Router, useValue: routerStub }
|
|
||||||
],
|
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
|
||||||
}).compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(CreateCollectionPageComponent);
|
|
||||||
comp = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
collectionDataService = (comp as any).collectionDataService;
|
|
||||||
communityDataService = (comp as any).communityDataService;
|
|
||||||
routeService = (comp as any).routeService;
|
|
||||||
router = (comp as any).router;
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('onSubmit', () => {
|
|
||||||
const data = {
|
|
||||||
metadata: [{
|
|
||||||
key: 'dc.title',
|
|
||||||
value:'test'
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
|
|
||||||
it('should navigate when successful', () => {
|
|
||||||
spyOn(router, 'navigate');
|
|
||||||
comp.onSubmit(data);
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(router.navigate).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not navigate on failure', () => {
|
|
||||||
spyOn(router, 'navigate');
|
|
||||||
spyOn(collectionDataService, 'create').and.returnValue(observableOf(new RemoteData(true, true, false, undefined, collection)));
|
|
||||||
comp.onSubmit(data);
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(router.navigate).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@@ -2,18 +2,21 @@ import { Component } from '@angular/core';
|
|||||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||||
import { RouteService } from '../../shared/services/route.service';
|
import { RouteService } from '../../shared/services/route.service';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { CreateComColPageComponent } from '../../comcol-forms/create-comcol-page/create-comcol-page.component';
|
import { CreateComColPageComponent } from '../../shared/comcol-forms/create-comcol-page/create-comcol-page.component';
|
||||||
import { NormalizedCollection } from '../../core/cache/models/normalized-collection.model';
|
import { NormalizedCollection } from '../../core/cache/models/normalized-collection.model';
|
||||||
import { Collection } from '../../core/shared/collection.model';
|
import { Collection } from '../../core/shared/collection.model';
|
||||||
import { CollectionDataService } from '../../core/data/collection-data.service';
|
import { CollectionDataService } from '../../core/data/collection-data.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component that represents the page where a user can create a new Collection
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-create-community',
|
selector: 'ds-create-collection',
|
||||||
styleUrls: ['./create-community-page.component.scss'],
|
styleUrls: ['./create-collection-page.component.scss'],
|
||||||
templateUrl: './create-community-page.component.html'
|
templateUrl: './create-collection-page.component.html'
|
||||||
})
|
})
|
||||||
export class CreateCommunityPageComponent extends CreateComColPageComponent<Collection, NormalizedCollection> {
|
export class CreateCollectionPageComponent extends CreateComColPageComponent<Collection, NormalizedCollection> {
|
||||||
protected frontendURL = 'collections';
|
protected frontendURL = '/collections/';
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
protected communityDataService: CommunityDataService,
|
protected communityDataService: CommunityDataService,
|
||||||
|
@@ -0,0 +1,67 @@
|
|||||||
|
import { CreateCollectionPageGuard } from './create-collection-page.guard';
|
||||||
|
import { MockRouter } from '../../shared/mocks/mock-router';
|
||||||
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
|
import { Community } from '../../core/shared/community.model';
|
||||||
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { first } from 'rxjs/operators';
|
||||||
|
|
||||||
|
describe('CreateCollectionPageGuard', () => {
|
||||||
|
describe('canActivate', () => {
|
||||||
|
let guard: CreateCollectionPageGuard;
|
||||||
|
let router;
|
||||||
|
let communityDataServiceStub: any;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
communityDataServiceStub = {
|
||||||
|
findById: (id: string) => {
|
||||||
|
if (id === 'valid-id') {
|
||||||
|
return observableOf(new RemoteData(false, false, true, null, new Community()));
|
||||||
|
} else if (id === 'invalid-id') {
|
||||||
|
return observableOf(new RemoteData(false, false, true, null, undefined));
|
||||||
|
} else if (id === 'error-id') {
|
||||||
|
return observableOf(new RemoteData(false, false, false, null, new Community()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
router = new MockRouter();
|
||||||
|
|
||||||
|
guard = new CreateCollectionPageGuard(router, communityDataServiceStub);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true when the parent ID resolves to a community', () => {
|
||||||
|
guard.canActivate({ queryParams: { parent: 'valid-id' } } as any, undefined)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(
|
||||||
|
(canActivate) =>
|
||||||
|
expect(canActivate).toEqual(true)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false when no parent ID has been provided', () => {
|
||||||
|
guard.canActivate({ queryParams: { } } as any, undefined)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(
|
||||||
|
(canActivate) =>
|
||||||
|
expect(canActivate).toEqual(false)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false when the parent ID does not resolve to a community', () => {
|
||||||
|
guard.canActivate({ queryParams: { parent: 'invalid-id' } } as any, undefined)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(
|
||||||
|
(canActivate) =>
|
||||||
|
expect(canActivate).toEqual(false)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false when the parent ID resolves to an error response', () => {
|
||||||
|
guard.canActivate({ queryParams: { parent: 'error-id' } } as any, undefined)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(
|
||||||
|
(canActivate) =>
|
||||||
|
expect(canActivate).toEqual(false)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,46 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
|
||||||
|
|
||||||
|
import { hasNoValue, hasValue } from '../../shared/empty.util';
|
||||||
|
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||||
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
|
import { Community } from '../../core/shared/community.model';
|
||||||
|
import { getFinishedRemoteData } from '../../core/shared/operators';
|
||||||
|
import { map, tap } from 'rxjs/operators';
|
||||||
|
import { Observable, of as observableOf } from 'rxjs';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent creation of a collection without a parent community provided
|
||||||
|
* @class CreateCollectionPageGuard
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class CreateCollectionPageGuard implements CanActivate {
|
||||||
|
public constructor(private router: Router, private communityService: CommunityDataService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True when either a parent ID query parameter has been provided and the parent ID resolves to a valid parent community
|
||||||
|
* Reroutes to a 404 page when the page cannot be activated
|
||||||
|
* @method canActivate
|
||||||
|
*/
|
||||||
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
|
||||||
|
const parentID = route.queryParams.parent;
|
||||||
|
if (hasNoValue(parentID)) {
|
||||||
|
this.router.navigate(['/404']);
|
||||||
|
return observableOf(false);
|
||||||
|
}
|
||||||
|
const parent: Observable<RemoteData<Community>> = this.communityService.findById(parentID)
|
||||||
|
.pipe(
|
||||||
|
getFinishedRemoteData(),
|
||||||
|
);
|
||||||
|
|
||||||
|
return parent.pipe(
|
||||||
|
map((communityRD: RemoteData<Community>) => hasValue(communityRD) && communityRD.hasSucceeded && hasValue(communityRD.payload)),
|
||||||
|
tap((isValid: boolean) => {
|
||||||
|
if (!isValid) {
|
||||||
|
this.router.navigate(['/404']);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,8 +1,8 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 pb-4">
|
<div class="col-12 pb-4">
|
||||||
<h2 id="header" class="border-bottom pb-2">{{ 'community.edit.head' | translate }}</h2>
|
<h2 id="header" class="border-bottom pb-2">{{ 'collection.edit.head' | translate }}</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ds-community-form (submitForm)="onSubmit($event)" [community]="(communityRD$ | async)?.payload"></ds-community-form>
|
<ds-collection-form (submitForm)="onSubmit($event)" [dso]="(dsoRD$ | async)?.payload"></ds-collection-form>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -0,0 +1,28 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { RouteService } from '../../shared/services/route.service';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { EditComColPageComponent } from '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component';
|
||||||
|
import { NormalizedCollection } from '../../core/cache/models/normalized-collection.model';
|
||||||
|
import { Collection } from '../../core/shared/collection.model';
|
||||||
|
import { CollectionDataService } from '../../core/data/collection-data.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component that represents the page where a user can edit an existing Collection
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-edit-collection',
|
||||||
|
styleUrls: ['./edit-collection-page.component.scss'],
|
||||||
|
templateUrl: './edit-collection-page.component.html'
|
||||||
|
})
|
||||||
|
export class EditCollectionPageComponent extends EditComColPageComponent<Collection, NormalizedCollection> {
|
||||||
|
protected frontendURL = '/collections/';
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
protected collectionDataService: CollectionDataService,
|
||||||
|
protected routeService: RouteService,
|
||||||
|
protected router: Router,
|
||||||
|
protected route: ActivatedRoute
|
||||||
|
) {
|
||||||
|
super(collectionDataService, routeService, router, route);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,121 +0,0 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
|
||||||
import { RouteService } from '../../shared/services/route.service';
|
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
|
||||||
import { of as observableOf } from 'rxjs';
|
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
|
||||||
import { Community } from '../../core/shared/community.model';
|
|
||||||
import { SharedModule } from '../../shared/shared.module';
|
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
|
||||||
import { EditCommunityPageComponent } from './edit-community-page.component';
|
|
||||||
import { ActivatedRouteStub } from '../../shared/testing/active-router-stub';
|
|
||||||
|
|
||||||
fdescribe('EditCommunityPageComponent', () => {
|
|
||||||
let comp: EditCommunityPageComponent;
|
|
||||||
let fixture: ComponentFixture<EditCommunityPageComponent>;
|
|
||||||
let communityDataService: CommunityDataService;
|
|
||||||
let routeService: RouteService;
|
|
||||||
let router: Router;
|
|
||||||
|
|
||||||
let community;
|
|
||||||
let newCommunity;
|
|
||||||
let communityDataServiceStub;
|
|
||||||
let routeServiceStub;
|
|
||||||
let routerStub;
|
|
||||||
let routeStub;
|
|
||||||
|
|
||||||
function initializeVars() {
|
|
||||||
community = Object.assign(new Community(), {
|
|
||||||
uuid: 'a20da287-e174-466a-9926-f66b9300d347',
|
|
||||||
metadata: [{
|
|
||||||
key: 'dc.title',
|
|
||||||
value: 'test community'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
|
|
||||||
newCommunity = Object.assign(new Community(), {
|
|
||||||
uuid: '1ff59938-a69a-4e62-b9a4-718569c55d48',
|
|
||||||
metadata: [{
|
|
||||||
key: 'dc.title',
|
|
||||||
value: 'new community'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
|
|
||||||
communityDataServiceStub = {
|
|
||||||
findById: (uuid) => observableOf(new RemoteData(false, false, true, null, Object.assign(new Community(), {
|
|
||||||
uuid: uuid,
|
|
||||||
metadata: [{
|
|
||||||
key: 'dc.title',
|
|
||||||
value: community.name
|
|
||||||
}]
|
|
||||||
}))),
|
|
||||||
update: (com, uuid?) => observableOf(new RemoteData(false, false, true, undefined, newCommunity))
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
routeServiceStub = {
|
|
||||||
getQueryParameterValue: (param) => observableOf(community.uuid)
|
|
||||||
};
|
|
||||||
routerStub = {
|
|
||||||
navigate: (commands) => commands
|
|
||||||
};
|
|
||||||
|
|
||||||
routeStub = {
|
|
||||||
data: observableOf(community)
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
initializeVars();
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
|
||||||
declarations: [EditCommunityPageComponent],
|
|
||||||
providers: [
|
|
||||||
{ provide: CommunityDataService, useValue: communityDataServiceStub },
|
|
||||||
{ provide: RouteService, useValue: routeServiceStub },
|
|
||||||
{ provide: Router, useValue: routerStub },
|
|
||||||
{ provide: ActivatedRoute, useValue: routeStub },
|
|
||||||
],
|
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
|
||||||
}).compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(EditCommunityPageComponent);
|
|
||||||
comp = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
communityDataService = (comp as any).communityDataService;
|
|
||||||
routeService = (comp as any).routeService;
|
|
||||||
router = (comp as any).router;
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('onSubmit', () => {
|
|
||||||
let data;
|
|
||||||
beforeEach(() => {
|
|
||||||
data = Object.assign(new Community(), {
|
|
||||||
metadata: [{
|
|
||||||
key: 'dc.title',
|
|
||||||
value: 'test'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('should navigate when successful', () => {
|
|
||||||
spyOn(router, 'navigate');
|
|
||||||
comp.onSubmit(data);
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(router.navigate).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not navigate on failure', () => {
|
|
||||||
spyOn(router, 'navigate');
|
|
||||||
spyOn(communityDataService, 'update').and.returnValue(observableOf(new RemoteData(true, true, false, undefined, newCommunity)));
|
|
||||||
comp.onSubmit(data);
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(router.navigate).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,45 +0,0 @@
|
|||||||
import { Component } from '@angular/core';
|
|
||||||
import { Community } from '../../core/shared/community.model';
|
|
||||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { RouteService } from '../../shared/services/route.service';
|
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
|
||||||
import { isNotUndefined } from '../../shared/empty.util';
|
|
||||||
import { first, map } from 'rxjs/operators';
|
|
||||||
import { getSucceededRemoteData } from '../../core/shared/operators';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ds-edit-community',
|
|
||||||
styleUrls: ['./edit-community-page.component.scss'],
|
|
||||||
templateUrl: './edit-collection-page.component.html'
|
|
||||||
})
|
|
||||||
export class EditCommunityPageComponent {
|
|
||||||
|
|
||||||
public parentUUID$: Observable<string>;
|
|
||||||
public parentRD$: Observable<RemoteData<Community>>;
|
|
||||||
public communityRD$: Observable<RemoteData<Community>>;
|
|
||||||
|
|
||||||
public constructor(
|
|
||||||
private communityDataService: CommunityDataService,
|
|
||||||
private routeService: RouteService,
|
|
||||||
private router: Router,
|
|
||||||
private route: ActivatedRoute
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.communityRD$ = this.route.data.pipe(first(), map((data) => data.community));
|
|
||||||
}
|
|
||||||
|
|
||||||
onSubmit(community: Community) {
|
|
||||||
this.communityDataService.update(community)
|
|
||||||
.pipe(getSucceededRemoteData())
|
|
||||||
.subscribe((communityRD: RemoteData<Community>) => {
|
|
||||||
if (isNotUndefined(communityRD)) {
|
|
||||||
const newUUID = communityRD.payload.uuid;
|
|
||||||
this.router.navigate(['/communities/' + newUUID]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,21 +1,33 @@
|
|||||||
import { Component, Input, OnInit, Output } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
import {
|
import { DynamicInputModel, DynamicTextAreaModel } from '@ng-dynamic-forms/core';
|
||||||
DynamicInputModel,
|
|
||||||
DynamicTextAreaModel
|
|
||||||
} from '@ng-dynamic-forms/core';
|
|
||||||
import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model';
|
import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model';
|
||||||
import { Community } from '../../core/shared/community.model';
|
import { Community } from '../../core/shared/community.model';
|
||||||
import { ResourceType } from '../../core/shared/resource-type';
|
import { ResourceType } from '../../core/shared/resource-type';
|
||||||
import { ComColFormComponent } from '../../comcol-forms/comcol-form/comcol-form.component';
|
import { ComColFormComponent } from '../../shared/comcol-forms/comcol-form/comcol-form.component';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form used for creating and editing communities
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-community-form',
|
selector: 'ds-community-form',
|
||||||
styleUrls: ['../../comcol-forms/comcol-form.component.scss'],
|
styleUrls: ['../../shared/comcol-forms/comcol-form/comcol-form.component.scss'],
|
||||||
templateUrl: '../../comcol-forms/comcol-form/comcol-form.component.html'
|
templateUrl: '../../shared/comcol-forms/comcol-form/comcol-form.component.html'
|
||||||
})
|
})
|
||||||
export class CommunityFormComponent extends ComColFormComponent<Community> {
|
export class CommunityFormComponent extends ComColFormComponent<Community> {
|
||||||
|
/**
|
||||||
|
* @type {Community} A new community when a community is being created, an existing Input community when a community is being edited
|
||||||
|
*/
|
||||||
@Input() dso: Community = new Community();
|
@Input() dso: Community = new Community();
|
||||||
type = ResourceType.Community;
|
|
||||||
|
/**
|
||||||
|
* @type {ResourceType.Community} This is a community-type form
|
||||||
|
*/
|
||||||
|
protected type = ResourceType.Community;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The dynamic form fields used for creating/editing a community
|
||||||
|
* @type {(DynamicInputModel | DynamicTextAreaModel)[]}
|
||||||
|
*/
|
||||||
formModel: DynamicFormControlModel[] = [
|
formModel: DynamicFormControlModel[] = [
|
||||||
new DynamicInputModel({
|
new DynamicInputModel({
|
||||||
id: 'title',
|
id: 'title',
|
||||||
|
@@ -6,20 +6,23 @@ import { CommunityPageResolver } from './community-page.resolver';
|
|||||||
import { CreateCommunityPageComponent } from './create-community-page/create-community-page.component';
|
import { CreateCommunityPageComponent } from './create-community-page/create-community-page.component';
|
||||||
import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
|
import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
|
||||||
import { EditCommunityPageComponent } from './edit-community-page/edit-community-page.component';
|
import { EditCommunityPageComponent } from './edit-community-page/edit-community-page.component';
|
||||||
|
import { CreateCommunityPageGuard } from './create-community-page/create-community-page.guard';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
RouterModule.forChild([
|
RouterModule.forChild([
|
||||||
{ path: 'create',
|
{
|
||||||
|
path: 'create',
|
||||||
component: CreateCommunityPageComponent,
|
component: CreateCommunityPageComponent,
|
||||||
canActivate: [AuthenticatedGuard]
|
canActivate: [AuthenticatedGuard, CreateCommunityPageGuard]
|
||||||
},
|
},
|
||||||
{ path: ':id/edit',
|
{
|
||||||
|
path: ':id/edit',
|
||||||
pathMatch: 'full',
|
pathMatch: 'full',
|
||||||
component: EditCommunityPageComponent,
|
component: EditCommunityPageComponent,
|
||||||
canActivate: [AuthenticatedGuard],
|
canActivate: [AuthenticatedGuard],
|
||||||
resolve: {
|
resolve: {
|
||||||
community: CommunityPageResolver
|
dso: CommunityPageResolver
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -34,6 +37,7 @@ import { EditCommunityPageComponent } from './edit-community-page/edit-community
|
|||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
CommunityPageResolver,
|
CommunityPageResolver,
|
||||||
|
CreateCommunityPageGuard
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class CommunityPageRoutingModule {
|
export class CommunityPageRoutingModule {
|
||||||
|
@@ -28,7 +28,6 @@
|
|||||||
<ds-community-page-sub-collection-list [community]="communityPayload"></ds-community-page-sub-collection-list>
|
<ds-community-page-sub-collection-list [community]="communityPayload"></ds-community-page-sub-collection-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a [routerLink]="'edit'">Edit</a>
|
|
||||||
|
|
||||||
<ds-error *ngIf="communityRD?.hasFailed" message="{{'error.community' | translate}}"></ds-error>
|
<ds-error *ngIf="communityRD?.hasFailed" message="{{'error.community' | translate}}"></ds-error>
|
||||||
<ds-loading *ngIf="communityRD?.isLoading" message="{{'loading.community' | translate}}"></ds-loading>
|
<ds-loading *ngIf="communityRD?.isLoading" message="{{'loading.community' | translate}}"></ds-loading>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 pb-4">
|
<div class="col-12 pb-4">
|
||||||
<ng-container *ngVar="(parentUUID$ | async)?.payload as parent">
|
<ng-container *ngVar="(parentRD$ | async)?.payload as parent">
|
||||||
<h2 *ngIf="!parent" id="header" class="border-bottom pb-2">{{ 'community.create.head' | translate }}</h2>
|
<h2 *ngIf="!parent" id="header" class="border-bottom pb-2">{{ 'community.create.head' | translate }}</h2>
|
||||||
<h2 *ngIf="parent" id="sub-header" class="border-bottom pb-2">{{ 'community.create.sub-head' | translate:{ parent: parent.name } }}</h2>
|
<h2 *ngIf="parent" id="sub-header" class="border-bottom pb-2">{{ 'community.create.sub-head' | translate:{ parent: parent.name } }}</h2>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
@@ -3,16 +3,20 @@ import { Community } from '../../core/shared/community.model';
|
|||||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||||
import { RouteService } from '../../shared/services/route.service';
|
import { RouteService } from '../../shared/services/route.service';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { CreateComColPageComponent } from '../../comcol-forms/create-comcol-page/create-comcol-page.component';
|
import { CreateComColPageComponent } from '../../shared/comcol-forms/create-comcol-page/create-comcol-page.component';
|
||||||
import { NormalizedCommunity } from '../../core/cache/models/normalized-community.model';
|
import { NormalizedCommunity } from '../../core/cache/models/normalized-community.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component that represents the page where a user can create a new Community
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-create-community',
|
selector: 'ds-create-community',
|
||||||
styleUrls: ['./create-community-page.component.scss'],
|
styleUrls: ['./create-community-page.component.scss'],
|
||||||
templateUrl: './create-community-page.component.html'
|
templateUrl: './create-community-page.component.html'
|
||||||
})
|
})
|
||||||
export class CreateCommunityPageComponent extends CreateComColPageComponent<Community, NormalizedCommunity> {
|
export class CreateCommunityPageComponent extends CreateComColPageComponent<Community, NormalizedCommunity> {
|
||||||
protected frontendURL = 'communities';
|
protected frontendURL = '/communities/';
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
protected communityDataService: CommunityDataService,
|
protected communityDataService: CommunityDataService,
|
||||||
protected routeService: RouteService,
|
protected routeService: RouteService,
|
||||||
|
@@ -0,0 +1,67 @@
|
|||||||
|
import { CreateCommunityPageGuard } from './create-community-page.guard';
|
||||||
|
import { MockRouter } from '../../shared/mocks/mock-router';
|
||||||
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
|
import { Community } from '../../core/shared/community.model';
|
||||||
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { first } from 'rxjs/operators';
|
||||||
|
|
||||||
|
describe('CreateCommunityPageGuard', () => {
|
||||||
|
describe('canActivate', () => {
|
||||||
|
let guard: CreateCommunityPageGuard;
|
||||||
|
let router;
|
||||||
|
let communityDataServiceStub: any;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
communityDataServiceStub = {
|
||||||
|
findById: (id: string) => {
|
||||||
|
if (id === 'valid-id') {
|
||||||
|
return observableOf(new RemoteData(false, false, true, null, new Community()));
|
||||||
|
} else if (id === 'invalid-id') {
|
||||||
|
return observableOf(new RemoteData(false, false, true, null, undefined));
|
||||||
|
} else if (id === 'error-id') {
|
||||||
|
return observableOf(new RemoteData(false, false, false, null, new Community()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
router = new MockRouter();
|
||||||
|
|
||||||
|
guard = new CreateCommunityPageGuard(router, communityDataServiceStub);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true when the parent ID resolves to a community', () => {
|
||||||
|
guard.canActivate({ queryParams: { parent: 'valid-id' } } as any, undefined)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(
|
||||||
|
(canActivate) =>
|
||||||
|
expect(canActivate).toEqual(true)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true when no parent ID has been provided', () => {
|
||||||
|
guard.canActivate({ queryParams: { } } as any, undefined)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(
|
||||||
|
(canActivate) =>
|
||||||
|
expect(canActivate).toEqual(true)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false when the parent ID does not resolve to a community', () => {
|
||||||
|
guard.canActivate({ queryParams: { parent: 'invalid-id' } } as any, undefined)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(
|
||||||
|
(canActivate) =>
|
||||||
|
expect(canActivate).toEqual(false)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false when the parent ID resolves to an error response', () => {
|
||||||
|
guard.canActivate({ queryParams: { parent: 'error-id' } } as any, undefined)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(
|
||||||
|
(canActivate) =>
|
||||||
|
expect(canActivate).toEqual(false)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,46 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
|
||||||
|
|
||||||
|
import { hasNoValue, hasValue } from '../../shared/empty.util';
|
||||||
|
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||||
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
|
import { Community } from '../../core/shared/community.model';
|
||||||
|
import { getFinishedRemoteData } from '../../core/shared/operators';
|
||||||
|
import { map, tap } from 'rxjs/operators';
|
||||||
|
import { Observable, of as observableOf } from 'rxjs';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent creation of a community with an invalid parent community provided
|
||||||
|
* @class CreateCommunityPageGuard
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class CreateCommunityPageGuard implements CanActivate {
|
||||||
|
public constructor(private router: Router, private communityService: CommunityDataService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True when either NO parent ID query parameter has been provided, or the parent ID resolves to a valid parent community
|
||||||
|
* Reroutes to a 404 page when the page cannot be activated
|
||||||
|
* @method canActivate
|
||||||
|
*/
|
||||||
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
|
||||||
|
const parentID = route.queryParams.parent;
|
||||||
|
if (hasNoValue(parentID)) {
|
||||||
|
return observableOf(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent: Observable<RemoteData<Community>> = this.communityService.findById(parentID)
|
||||||
|
.pipe(
|
||||||
|
getFinishedRemoteData(),
|
||||||
|
);
|
||||||
|
|
||||||
|
return parent.pipe(
|
||||||
|
map((communityRD: RemoteData<Community>) => hasValue(communityRD) && communityRD.hasSucceeded && hasValue(communityRD.payload)),
|
||||||
|
tap((isValid: boolean) => {
|
||||||
|
if (!isValid) {
|
||||||
|
this.router.navigate(['/404']);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -4,5 +4,5 @@
|
|||||||
<h2 id="header" class="border-bottom pb-2">{{ 'community.edit.head' | translate }}</h2>
|
<h2 id="header" class="border-bottom pb-2">{{ 'community.edit.head' | translate }}</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ds-community-form (submitForm)="onSubmit($event)" [community]="(communityRD$ | async)?.payload"></ds-community-form>
|
<ds-community-form (submitForm)="onSubmit($event)" [dso]="(dsoRD$ | async)?.payload"></ds-community-form>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,45 +1,28 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { Community } from '../../core/shared/community.model';
|
import { Community } from '../../core/shared/community.model';
|
||||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { RouteService } from '../../shared/services/route.service';
|
import { RouteService } from '../../shared/services/route.service';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { NormalizedCommunity } from '../../core/cache/models/normalized-community.model';
|
||||||
import { isNotUndefined } from '../../shared/empty.util';
|
import { EditComColPageComponent } from '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component';
|
||||||
import { first, map } from 'rxjs/operators';
|
|
||||||
import { getSucceededRemoteData } from '../../core/shared/operators';
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component that represents the page where a user can edit an existing Community
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-edit-community',
|
selector: 'ds-edit-community',
|
||||||
styleUrls: ['./edit-community-page.component.scss'],
|
styleUrls: ['./edit-community-page.component.scss'],
|
||||||
templateUrl: './edit-community-page.component.html'
|
templateUrl: './edit-community-page.component.html'
|
||||||
})
|
})
|
||||||
export class EditCommunityPageComponent {
|
export class EditCommunityPageComponent extends EditComColPageComponent<Community, NormalizedCommunity> {
|
||||||
|
protected frontendURL = '/communities/';
|
||||||
public parentUUID$: Observable<string>;
|
|
||||||
public parentRD$: Observable<RemoteData<Community>>;
|
|
||||||
public communityRD$: Observable<RemoteData<Community>>;
|
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
private communityDataService: CommunityDataService,
|
protected communityDataService: CommunityDataService,
|
||||||
private routeService: RouteService,
|
protected routeService: RouteService,
|
||||||
private router: Router,
|
protected router: Router,
|
||||||
private route: ActivatedRoute
|
protected route: ActivatedRoute
|
||||||
) {
|
) {
|
||||||
}
|
super(communityDataService, routeService, router, route);
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.communityRD$ = this.route.data.pipe(first(), map((data) => data.community));
|
|
||||||
}
|
|
||||||
|
|
||||||
onSubmit(community: Community) {
|
|
||||||
this.communityDataService.update(community)
|
|
||||||
.pipe(getSucceededRemoteData())
|
|
||||||
.subscribe((communityRD: RemoteData<Community>) => {
|
|
||||||
if (isNotUndefined(communityRD)) {
|
|
||||||
const newUUID = communityRD.payload.uuid;
|
|
||||||
this.router.navigate(['/communities/' + newUUID]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,45 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import { Community } from '../../core/shared/community.model';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { RouteService } from '../../shared/services/route.service';
|
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
|
||||||
import { isNotUndefined } from '../../shared/empty.util';
|
|
||||||
import { first, map } from 'rxjs/operators';
|
|
||||||
import { getSucceededRemoteData } from '../../core/shared/operators';
|
|
||||||
import { DataService } from '../../core/data/data.service';
|
|
||||||
import { NormalizedDSpaceObject } from '../../core/cache/models/normalized-dspace-object.model';
|
|
||||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ds-edit-community',
|
|
||||||
styleUrls: ['./edit-community-page.component.scss'],
|
|
||||||
templateUrl: './edit-community-page.component.html'
|
|
||||||
})
|
|
||||||
export class EditComColPageComponent<TDomain extends DSpaceObject, TNormalized extends NormalizedDSpaceObject> implements OnInit {
|
|
||||||
protected frontendURL: string;
|
|
||||||
public dsoRD$: Observable<RemoteData<Community>>;
|
|
||||||
|
|
||||||
public constructor(
|
|
||||||
protected dsoDataService: DataService<TNormalized, TDomain>,
|
|
||||||
private routeService: RouteService,
|
|
||||||
private router: Router,
|
|
||||||
private route: ActivatedRoute
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.dsoRD$ = this.route.data.pipe(first(), map((data) => data.dso));
|
|
||||||
}
|
|
||||||
|
|
||||||
onSubmit(dso: TDomain) {
|
|
||||||
this.dsoDataService.update(dso)
|
|
||||||
.pipe(getSucceededRemoteData())
|
|
||||||
.subscribe((dsoRD: RemoteData<TDomain>) => {
|
|
||||||
if (isNotUndefined(dsoRD)) {
|
|
||||||
const newUUID = dsoRD.payload.uuid;
|
|
||||||
this.router.navigate([this.frontendURL + newUUID]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@@ -161,7 +161,13 @@ describe('ConfigResponseParsingService', () => {
|
|||||||
page: { size: 20, totalElements: 2, totalPages: 1, number: 0 }
|
page: { size: 20, totalElements: 2, totalPages: 1, number: 0 }
|
||||||
}, statusCode: '500'
|
}, statusCode: '500'
|
||||||
};
|
};
|
||||||
const pageinfo = Object.assign(new PageInfo(), { elementsPerPage: 4, totalElements: 4, totalPages: 1, currentPage: 1 });
|
const pageinfo = Object.assign(new PageInfo(), {
|
||||||
|
elementsPerPage: 4,
|
||||||
|
totalElements: 4,
|
||||||
|
totalPages: 1,
|
||||||
|
currentPage: 1,
|
||||||
|
self: 'https://rest.api/config/submissiondefinitions/traditional/sections'
|
||||||
|
});
|
||||||
const definitions =
|
const definitions =
|
||||||
Object.assign(new SubmissionDefinitionsModel(), {
|
Object.assign(new SubmissionDefinitionsModel(), {
|
||||||
isDefault: true,
|
isDefault: true,
|
||||||
|
@@ -5,18 +5,17 @@ import { RemoteDataBuildService } from '../cache/builders/remote-data-build.serv
|
|||||||
import { CoreState } from '../core.reducers';
|
import { CoreState } from '../core.reducers';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable, of as observableOf } from 'rxjs';
|
||||||
import { FindAllOptions } from './request.models';
|
import { FindAllOptions } from './request.models';
|
||||||
import { SortOptions, SortDirection } from '../cache/models/sort-options.model';
|
import { SortDirection, SortOptions } from '../cache/models/sort-options.model';
|
||||||
import { of as observableOf } from 'rxjs';
|
|
||||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
import { Operation } from '../../../../node_modules/fast-json-patch';
|
import { Operation } from '../../../../node_modules/fast-json-patch';
|
||||||
import { DSpaceObject } from '../shared/dspace-object.model';
|
import { DSpaceObject } from '../shared/dspace-object.model';
|
||||||
import { AuthService } from '../auth/auth.service';
|
|
||||||
import { UpdateComparator } from './update-comparator';
|
import { UpdateComparator } from './update-comparator';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { DataBuildService } from '../cache/builders/data-build.service';
|
import { DataBuildService } from '../cache/builders/data-build.service';
|
||||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { compare } from 'fast-json-patch';
|
||||||
|
|
||||||
const endpoint = 'https://rest.api/core';
|
const endpoint = 'https://rest.api/core';
|
||||||
|
|
||||||
@@ -45,6 +44,12 @@ class TestService extends DataService<NormalizedTestObject, any> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DummyComparator implements UpdateComparator<NormalizedTestObject> {
|
||||||
|
compare(object1: NormalizedTestObject, object2: NormalizedTestObject): Operation[] {
|
||||||
|
return compare((object1 as any).metadata, (object2 as any).metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
describe('DataService', () => {
|
describe('DataService', () => {
|
||||||
let service: TestService;
|
let service: TestService;
|
||||||
let options: FindAllOptions;
|
let options: FindAllOptions;
|
||||||
@@ -53,8 +58,10 @@ describe('DataService', () => {
|
|||||||
const rdbService = {} as RemoteDataBuildService;
|
const rdbService = {} as RemoteDataBuildService;
|
||||||
const notificationsService = {} as NotificationsService;
|
const notificationsService = {} as NotificationsService;
|
||||||
const http = {} as HttpClient;
|
const http = {} as HttpClient;
|
||||||
const comparator = {} as any;
|
const comparator = new DummyComparator() as any;
|
||||||
const dataBuildService = {} as DataBuildService;
|
const dataBuildService = {
|
||||||
|
normalize: (object) => object
|
||||||
|
} as DataBuildService;
|
||||||
const objectCache = {
|
const objectCache = {
|
||||||
addPatch: () => {
|
addPatch: () => {
|
||||||
/* empty */
|
/* empty */
|
||||||
@@ -136,7 +143,7 @@ describe('DataService', () => {
|
|||||||
elementsPerPage: 10,
|
elementsPerPage: 10,
|
||||||
sort: sortOptions,
|
sort: sortOptions,
|
||||||
startsWith: 'ab'
|
startsWith: 'ab'
|
||||||
}
|
};
|
||||||
const expected = `${endpoint}?page=${options.currentPage - 1}&size=${options.elementsPerPage}` +
|
const expected = `${endpoint}?page=${options.currentPage - 1}&size=${options.elementsPerPage}` +
|
||||||
`&sort=${sortOptions.field},${sortOptions.direction}&startsWith=${options.startsWith}`;
|
`&sort=${sortOptions.field},${sortOptions.direction}&startsWith=${options.startsWith}`;
|
||||||
|
|
||||||
@@ -169,7 +176,7 @@ describe('DataService', () => {
|
|||||||
const name1 = 'random string';
|
const name1 = 'random string';
|
||||||
const name2 = 'another random string';
|
const name2 = 'another random string';
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
operations = [{ op: 'replace', path: '/metadata/dc.title', value: name2 } as Operation];
|
operations = [{ op: 'replace', path: '/0/value', value: name2 } as Operation];
|
||||||
selfLink = 'https://rest.api/endpoint/1698f1d3-be98-4c51-9fd8-6bfedcbd59b7';
|
selfLink = 'https://rest.api/endpoint/1698f1d3-be98-4c51-9fd8-6bfedcbd59b7';
|
||||||
|
|
||||||
dso = new DSpaceObject();
|
dso = new DSpaceObject();
|
||||||
@@ -180,17 +187,18 @@ describe('DataService', () => {
|
|||||||
dso2.self = selfLink;
|
dso2.self = selfLink;
|
||||||
dso2.metadata = [{ key: 'dc.title', value: name2 }];
|
dso2.metadata = [{ key: 'dc.title', value: name2 }];
|
||||||
|
|
||||||
spyOn(objectCache, 'getBySelfLink').and.returnValue(dso);
|
spyOn(service, 'findById').and.returnValues(observableOf(dso));
|
||||||
|
spyOn(objectCache, 'getBySelfLink').and.returnValues(observableOf(dso));
|
||||||
spyOn(objectCache, 'addPatch');
|
spyOn(objectCache, 'addPatch');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call addPatch on the object cache with the right parameters when there are differences', () => {
|
it('should call addPatch on the object cache with the right parameters when there are differences', () => {
|
||||||
service.update(dso2);
|
service.update(dso2).subscribe();
|
||||||
expect(objectCache.addPatch).toHaveBeenCalledWith(selfLink, operations);
|
expect(objectCache.addPatch).toHaveBeenCalledWith(selfLink, operations);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not call addPatch on the object cache with the right parameters when there are no differences', () => {
|
it('should not call addPatch on the object cache with the right parameters when there are no differences', () => {
|
||||||
service.update(dso);
|
service.update(dso).subscribe();
|
||||||
expect(objectCache.addPatch).not.toHaveBeenCalled();
|
expect(objectCache.addPatch).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -35,6 +35,8 @@ import { AuthService } from '../auth/auth.service';
|
|||||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { EmptyError } from 'rxjs/internal-compatibility';
|
import { EmptyError } from 'rxjs/internal-compatibility';
|
||||||
|
import { DataBuildService } from '../cache/builders/data-build.service';
|
||||||
|
import { DSOUpdateComparator } from '../data/dso-update-comparator';
|
||||||
|
|
||||||
/* tslint:disable:max-classes-per-file */
|
/* tslint:disable:max-classes-per-file */
|
||||||
@Component({
|
@Component({
|
||||||
@@ -117,6 +119,8 @@ describe('MetadataService', () => {
|
|||||||
{ provide: AuthService, useValue: {} },
|
{ provide: AuthService, useValue: {} },
|
||||||
{ provide: NotificationsService, useValue: {} },
|
{ provide: NotificationsService, useValue: {} },
|
||||||
{ provide: HttpClient, useValue: {} },
|
{ provide: HttpClient, useValue: {} },
|
||||||
|
{ provide: DataBuildService, useValue: {} },
|
||||||
|
{ provide: DSOUpdateComparator, useValue: {} },
|
||||||
Meta,
|
Meta,
|
||||||
Title,
|
Title,
|
||||||
ItemDataService,
|
ItemDataService,
|
||||||
|
@@ -67,7 +67,7 @@ export class MetadataService {
|
|||||||
public processRemoteData(remoteData: Observable<RemoteData<CacheableObject>>): void {
|
public processRemoteData(remoteData: Observable<RemoteData<CacheableObject>>): void {
|
||||||
remoteData.pipe(map((rd: RemoteData<CacheableObject>) => rd.payload),
|
remoteData.pipe(map((rd: RemoteData<CacheableObject>) => rd.payload),
|
||||||
filter((co: CacheableObject) => hasValue(co)),
|
filter((co: CacheableObject) => hasValue(co)),
|
||||||
take(1),)
|
take(1))
|
||||||
.subscribe((dspaceObject: DSpaceObject) => {
|
.subscribe((dspaceObject: DSpaceObject) => {
|
||||||
if (!this.initialized) {
|
if (!this.initialized) {
|
||||||
this.initialize(dspaceObject);
|
this.initialize(dspaceObject);
|
||||||
@@ -269,7 +269,7 @@ export class MetadataService {
|
|||||||
const item = this.currentObject.value as Item;
|
const item = this.currentObject.value as Item;
|
||||||
item.getFiles()
|
item.getFiles()
|
||||||
.pipe(
|
.pipe(
|
||||||
find((files) => isNotEmpty(files)),
|
first((files) => isNotEmpty(files)),
|
||||||
catchError((error) => {
|
catchError((error) => {
|
||||||
console.debug(error.message);
|
console.debug(error.message);
|
||||||
return []
|
return []
|
||||||
@@ -277,7 +277,7 @@ export class MetadataService {
|
|||||||
.subscribe((bitstreams: Bitstream[]) => {
|
.subscribe((bitstreams: Bitstream[]) => {
|
||||||
for (const bitstream of bitstreams) {
|
for (const bitstream of bitstreams) {
|
||||||
bitstream.format.pipe(
|
bitstream.format.pipe(
|
||||||
take(1),
|
first(),
|
||||||
catchError((error: Error) => {
|
catchError((error: Error) => {
|
||||||
console.debug(error.message);
|
console.debug(error.message);
|
||||||
return []
|
return []
|
||||||
|
@@ -62,6 +62,10 @@ export const getSucceededRemoteData = () =>
|
|||||||
<T>(source: Observable<RemoteData<T>>): Observable<RemoteData<T>> =>
|
<T>(source: Observable<RemoteData<T>>): Observable<RemoteData<T>> =>
|
||||||
source.pipe(find((rd: RemoteData<T>) => rd.hasSucceeded));
|
source.pipe(find((rd: RemoteData<T>) => rd.hasSucceeded));
|
||||||
|
|
||||||
|
export const getFinishedRemoteData = () =>
|
||||||
|
<T>(source: Observable<RemoteData<T>>): Observable<RemoteData<T>> =>
|
||||||
|
source.pipe(find((rd: RemoteData<T>) => !rd.isLoading));
|
||||||
|
|
||||||
export const toDSpaceObjectListRD = () =>
|
export const toDSpaceObjectListRD = () =>
|
||||||
<T extends DSpaceObject>(source: Observable<RemoteData<PaginatedList<SearchResult<T>>>>): Observable<RemoteData<PaginatedList<T>>> =>
|
<T extends DSpaceObject>(source: Observable<RemoteData<PaginatedList<SearchResult<T>>>>): Observable<RemoteData<PaginatedList<T>>> =>
|
||||||
source.pipe(
|
source.pipe(
|
||||||
|
@@ -1,41 +1,46 @@
|
|||||||
import { CommunityFormComponent } from './community-form.component';
|
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { Location } from '@angular/common';
|
import { Location } from '@angular/common';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import {
|
import { DynamicFormService, DynamicInputModel } from '@ng-dynamic-forms/core';
|
||||||
DynamicFormService,
|
|
||||||
DynamicInputControlModel,
|
|
||||||
DynamicInputModel
|
|
||||||
} from '@ng-dynamic-forms/core';
|
|
||||||
import { FormControl, FormGroup } from '@angular/forms';
|
import { FormControl, FormGroup } from '@angular/forms';
|
||||||
import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model';
|
import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model';
|
||||||
import { Community } from '../../core/shared/community.model';
|
import { Community } from '../../../core/shared/community.model';
|
||||||
import { ResourceType } from '../../core/shared/resource-type';
|
import { ResourceType } from '../../../core/shared/resource-type';
|
||||||
|
import { ComColFormComponent } from './comcol-form.component';
|
||||||
|
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||||
|
import { hasValue } from '../../empty.util';
|
||||||
|
import { Metadatum } from '../../../core/shared/metadatum.model';
|
||||||
|
|
||||||
fdescribe('CommunityFormComponent', () => {
|
describe('ComColFormComponent', () => {
|
||||||
let comp: CommunityFormComponent;
|
let comp: ComColFormComponent<DSpaceObject>;
|
||||||
let fixture: ComponentFixture<CommunityFormComponent>;
|
let fixture: ComponentFixture<ComColFormComponent<DSpaceObject>>;
|
||||||
let location: Location;
|
let location: Location;
|
||||||
const formServiceStub: any = {
|
const formServiceStub: any = {
|
||||||
createFormGroup: (formModel: DynamicFormControlModel[]) => {
|
createFormGroup: (fModel: DynamicFormControlModel[]) => {
|
||||||
const controls = {};
|
const controls = {};
|
||||||
formModel.forEach((controlModel) => {
|
if (hasValue(fModel)) {
|
||||||
|
fModel.forEach((controlModel) => {
|
||||||
controls[controlModel.id] = new FormControl((controlModel as any).value);
|
controls[controlModel.id] = new FormControl((controlModel as any).value);
|
||||||
});
|
});
|
||||||
return new FormGroup(controls);
|
return new FormGroup(controls);
|
||||||
}
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const titleMD = { key: 'dc.title', value: 'Community Title' };
|
const titleMD = { key: 'dc.title', value: 'Community Title' } as Metadatum;
|
||||||
const randomMD = { key: 'dc.random', value: 'Random metadata excluded from form' };
|
const randomMD = { key: 'dc.random', value: 'Random metadata excluded from form' } as Metadatum;
|
||||||
const abstractMD = { key: 'dc.description.abstract', value: 'Community description' };
|
const abstractMD = {
|
||||||
const newTitleMD = { key: 'dc.title', value: 'New Community Title' };
|
key: 'dc.description.abstract',
|
||||||
|
value: 'Community description'
|
||||||
|
} as Metadatum;
|
||||||
|
const newTitleMD = { key: 'dc.title', value: 'New Community Title' } as Metadatum;
|
||||||
const formModel = [
|
const formModel = [
|
||||||
new DynamicInputModel({
|
new DynamicInputModel({
|
||||||
id: 'title',
|
id: 'title',
|
||||||
name: newTitleMD.key,
|
name: newTitleMD.key,
|
||||||
value: newTitleMD.value
|
value: 'New Community Title'
|
||||||
}),
|
}),
|
||||||
new DynamicInputModel({
|
new DynamicInputModel({
|
||||||
id: 'abstract',
|
id: 'abstract',
|
||||||
@@ -54,7 +59,7 @@ fdescribe('CommunityFormComponent', () => {
|
|||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [TranslateModule.forRoot(), RouterTestingModule],
|
imports: [TranslateModule.forRoot(), RouterTestingModule],
|
||||||
declarations: [CommunityFormComponent],
|
declarations: [ComColFormComponent],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: Location, useValue: locationStub },
|
{ provide: Location, useValue: locationStub },
|
||||||
{ provide: DynamicFormService, useValue: formServiceStub }
|
{ provide: DynamicFormService, useValue: formServiceStub }
|
||||||
@@ -64,20 +69,22 @@ fdescribe('CommunityFormComponent', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(CommunityFormComponent);
|
fixture = TestBed.createComponent(ComColFormComponent);
|
||||||
comp = fixture.componentInstance;
|
comp = fixture.componentInstance;
|
||||||
|
comp.formModel = [];
|
||||||
|
comp.dso = new Community();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
location = (comp as any).location;
|
location = (comp as any).location;
|
||||||
comp.formModel = formModel;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('onSubmit', () => {
|
describe('onSubmit', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
spyOn(comp.submitForm, 'emit');
|
spyOn(comp.submitForm, 'emit');
|
||||||
|
comp.formModel = formModel;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update emit the new version of the community', () => {
|
it('should emit the new version of the community', () => {
|
||||||
comp.community = Object.assign(
|
comp.dso = Object.assign(
|
||||||
new Community(),
|
new Community(),
|
||||||
{
|
{
|
||||||
metadata: [
|
metadata: [
|
@@ -7,23 +7,50 @@ import {
|
|||||||
import { FormGroup } from '@angular/forms';
|
import { FormGroup } from '@angular/forms';
|
||||||
import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model';
|
import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||||
import { isNotEmpty } from '../../shared/empty.util';
|
import { isNotEmpty } from '../../empty.util';
|
||||||
import { ResourceType } from '../../core/shared/resource-type';
|
import { ResourceType } from '../../../core/shared/resource-type';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-comcol-form',
|
selector: 'ds-comcol-form',
|
||||||
// styleUrls: ['./comcol-form.component.scss'],
|
styleUrls: ['./comcol-form.component.scss'],
|
||||||
templateUrl: './comcol-form.component.html'
|
templateUrl: './comcol-form.component.html'
|
||||||
})
|
})
|
||||||
export class ComColFormComponent<T extends DSpaceObject> implements OnInit {
|
export class ComColFormComponent<T extends DSpaceObject> implements OnInit {
|
||||||
|
/**
|
||||||
|
* DSpaceObject that the form represents
|
||||||
|
*/
|
||||||
@Input() dso: T;
|
@Input() dso: T;
|
||||||
type;
|
|
||||||
LABEL_KEY_PREFIX = this.type + '.form.';
|
/**
|
||||||
ERROR_KEY_PREFIX = this.type + '.form.errors.';
|
* Type of DSpaceObject that the form represents
|
||||||
|
*/
|
||||||
|
protected type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string} Key prefix used to generate form labels
|
||||||
|
*/
|
||||||
|
LABEL_KEY_PREFIX = '.form.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string} Key prefix used to generate form error messages
|
||||||
|
*/
|
||||||
|
ERROR_KEY_PREFIX = '.form.errors.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The form model that represents the fields in the form
|
||||||
|
*/
|
||||||
formModel: DynamicFormControlModel[];
|
formModel: DynamicFormControlModel[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The form group of this form
|
||||||
|
*/
|
||||||
formGroup: FormGroup;
|
formGroup: FormGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits DSO when the form is submitted
|
||||||
|
* @type {EventEmitter<any>}
|
||||||
|
*/
|
||||||
@Output() submitForm: EventEmitter<any> = new EventEmitter();
|
@Output() submitForm: EventEmitter<any> = new EventEmitter();
|
||||||
|
|
||||||
public constructor(private location: Location,
|
public constructor(private location: Location,
|
||||||
@@ -38,6 +65,7 @@ export class ComColFormComponent<T extends DSpaceObject> implements OnInit {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
this.formGroup = this.formService.createFormGroup(this.formModel);
|
this.formGroup = this.formService.createFormGroup(this.formModel);
|
||||||
|
|
||||||
this.updateFieldTranslations();
|
this.updateFieldTranslations();
|
||||||
this.translate.onLangChange
|
this.translate.onLangChange
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
@@ -45,6 +73,9 @@ export class ComColFormComponent<T extends DSpaceObject> implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks which new fields where added and sends the updated version of the DSO to the parent component
|
||||||
|
*/
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
const metadata = this.formModel.map(
|
const metadata = this.formModel.map(
|
||||||
(fieldModel: DynamicInputModel) => {
|
(fieldModel: DynamicInputModel) => {
|
||||||
@@ -53,6 +84,7 @@ export class ComColFormComponent<T extends DSpaceObject> implements OnInit {
|
|||||||
);
|
);
|
||||||
const filteredOldMetadata = this.dso.metadata.filter((filter) => !metadata.map((md) => md.key).includes(filter.key));
|
const filteredOldMetadata = this.dso.metadata.filter((filter) => !metadata.map((md) => md.key).includes(filter.key));
|
||||||
const filteredNewMetadata = metadata.filter((md) => isNotEmpty(md.value));
|
const filteredNewMetadata = metadata.filter((md) => isNotEmpty(md.value));
|
||||||
|
|
||||||
const newMetadata = [...filteredOldMetadata, ...filteredNewMetadata];
|
const newMetadata = [...filteredOldMetadata, ...filteredNewMetadata];
|
||||||
const updatedDSO = Object.assign({}, this.dso, {
|
const updatedDSO = Object.assign({}, this.dso, {
|
||||||
metadata: newMetadata,
|
metadata: newMetadata,
|
||||||
@@ -61,14 +93,17 @@ export class ComColFormComponent<T extends DSpaceObject> implements OnInit {
|
|||||||
this.submitForm.emit(updatedDSO);
|
this.submitForm.emit(updatedDSO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used the update translations of errors and labels on init and on language change
|
||||||
|
*/
|
||||||
private updateFieldTranslations() {
|
private updateFieldTranslations() {
|
||||||
this.formModel.forEach(
|
this.formModel.forEach(
|
||||||
(fieldModel: DynamicInputModel) => {
|
(fieldModel: DynamicInputModel) => {
|
||||||
fieldModel.label = this.translate.instant(this.LABEL_KEY_PREFIX + fieldModel.id);
|
fieldModel.label = this.translate.instant(this.type + this.LABEL_KEY_PREFIX + fieldModel.id);
|
||||||
if (isNotEmpty(fieldModel.validators)) {
|
if (isNotEmpty(fieldModel.validators)) {
|
||||||
fieldModel.errorMessages = {};
|
fieldModel.errorMessages = {};
|
||||||
Object.keys(fieldModel.validators).forEach((key) => {
|
Object.keys(fieldModel.validators).forEach((key) => {
|
||||||
fieldModel.errorMessages[key] = this.translate.instant(this.ERROR_KEY_PREFIX + fieldModel.id + '.' + key);
|
fieldModel.errorMessages[key] = this.translate.instant(this.type + this.ERROR_KEY_PREFIX + fieldModel.id + '.' + key);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,21 +1,25 @@
|
|||||||
import { CreateCommunityPageComponent } from './create-community-page.component';
|
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
import { CommunityDataService } from '../../../core/data/community-data.service';
|
||||||
import { RouteService } from '../../shared/services/route.service';
|
import { RouteService } from '../../services/route.service';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { RemoteData } from '../../../core/data/remote-data';
|
||||||
import { Community } from '../../core/shared/community.model';
|
import { Community } from '../../../core/shared/community.model';
|
||||||
import { SharedModule } from '../../shared/shared.module';
|
import { SharedModule } from '../../shared.module';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||||
|
import { NormalizedDSpaceObject } from '../../../core/cache/models/normalized-dspace-object.model';
|
||||||
|
import { CreateComColPageComponent } from './create-comcol-page.component';
|
||||||
|
import { DataService } from '../../../core/data/data.service';
|
||||||
|
|
||||||
fdescribe('CreateCommunityPageComponent', () => {
|
describe('CreateComColPageComponent', () => {
|
||||||
let comp: CreateCommunityPageComponent;
|
let comp: CreateComColPageComponent<DSpaceObject, NormalizedDSpaceObject>;
|
||||||
let fixture: ComponentFixture<CreateCommunityPageComponent>;
|
let fixture: ComponentFixture<CreateComColPageComponent<DSpaceObject, NormalizedDSpaceObject>>;
|
||||||
let communityDataService: CommunityDataService;
|
let communityDataService: CommunityDataService;
|
||||||
|
let dsoDataService: CommunityDataService;
|
||||||
let routeService: RouteService;
|
let routeService: RouteService;
|
||||||
let router: Router;
|
let router: Router;
|
||||||
|
|
||||||
@@ -67,8 +71,8 @@ fdescribe('CreateCommunityPageComponent', () => {
|
|||||||
initializeVars();
|
initializeVars();
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
||||||
declarations: [CreateCommunityPageComponent],
|
|
||||||
providers: [
|
providers: [
|
||||||
|
{ provide: DataService, useValue: communityDataServiceStub },
|
||||||
{ provide: CommunityDataService, useValue: communityDataServiceStub },
|
{ provide: CommunityDataService, useValue: communityDataServiceStub },
|
||||||
{ provide: RouteService, useValue: routeServiceStub },
|
{ provide: RouteService, useValue: routeServiceStub },
|
||||||
{ provide: Router, useValue: routerStub },
|
{ provide: Router, useValue: routerStub },
|
||||||
@@ -78,9 +82,10 @@ fdescribe('CreateCommunityPageComponent', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(CreateCommunityPageComponent);
|
fixture = TestBed.createComponent(CreateComColPageComponent);
|
||||||
comp = fixture.componentInstance;
|
comp = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
dsoDataService = (comp as any).dsoDataService;
|
||||||
communityDataService = (comp as any).communityDataService;
|
communityDataService = (comp as any).communityDataService;
|
||||||
routeService = (comp as any).routeService;
|
routeService = (comp as any).routeService;
|
||||||
router = (comp as any).router;
|
router = (comp as any).router;
|
||||||
@@ -105,7 +110,7 @@ fdescribe('CreateCommunityPageComponent', () => {
|
|||||||
|
|
||||||
it('should not navigate on failure', () => {
|
it('should not navigate on failure', () => {
|
||||||
spyOn(router, 'navigate');
|
spyOn(router, 'navigate');
|
||||||
spyOn(communityDataService, 'create').and.returnValue(observableOf(new RemoteData(true, true, false, undefined, newCommunity)));
|
spyOn(dsoDataService, 'create').and.returnValue(observableOf(new RemoteData(true, true, false, undefined, newCommunity)));
|
||||||
comp.onSubmit(data);
|
comp.onSubmit(data);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(router.navigate).not.toHaveBeenCalled();
|
expect(router.navigate).not.toHaveBeenCalled();
|
@@ -1,25 +1,38 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { Community } from '../../core/shared/community.model';
|
import { Community } from '../../../core/shared/community.model';
|
||||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
import { CommunityDataService } from '../../../core/data/community-data.service';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { RouteService } from '../../shared/services/route.service';
|
import { RouteService } from '../../services/route.service';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { RemoteData } from '../../../core/data/remote-data';
|
||||||
import { isNotEmpty, isNotUndefined } from '../../shared/empty.util';
|
import { isNotEmpty, isNotUndefined } from '../../empty.util';
|
||||||
import { take } from 'rxjs/operators';
|
import { take } from 'rxjs/operators';
|
||||||
import { getSucceededRemoteData } from '../../core/shared/operators';
|
import { getSucceededRemoteData } from '../../../core/shared/operators';
|
||||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||||
import { DataService } from '../../core/data/data.service';
|
import { DataService } from '../../../core/data/data.service';
|
||||||
import { NormalizedDSpaceObject } from '../../core/cache/models/normalized-dspace-object.model';
|
import { NormalizedDSpaceObject } from '../../../core/cache/models/normalized-dspace-object.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component representing the create page for communities and collections
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-create-community',
|
selector: 'ds-create-comcol',
|
||||||
styleUrls: ['./create-community-page.component.scss'],
|
template: ''
|
||||||
templateUrl: './create-community-page.component.html'
|
|
||||||
})
|
})
|
||||||
export class CreateComColPageComponent<TDomain extends DSpaceObject, TNormalized extends NormalizedDSpaceObject> implements OnInit {
|
export class CreateComColPageComponent<TDomain extends DSpaceObject, TNormalized extends NormalizedDSpaceObject> implements OnInit {
|
||||||
|
/**
|
||||||
|
* Frontend endpoint where for this type of DSP
|
||||||
|
*/
|
||||||
protected frontendURL: string;
|
protected frontendURL: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The provided UUID for the parent community
|
||||||
|
*/
|
||||||
public parentUUID$: Observable<string>;
|
public parentUUID$: Observable<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parent community of the object that is to be created
|
||||||
|
*/
|
||||||
public parentRD$: Observable<RemoteData<Community>>;
|
public parentRD$: Observable<RemoteData<Community>>;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
@@ -40,6 +53,10 @@ export class CreateComColPageComponent<TDomain extends DSpaceObject, TNormalized
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {TDomain} dso The updated version of the DSO
|
||||||
|
* Creates a new DSO based on the submitted user data and navigates to the new object's home page
|
||||||
|
*/
|
||||||
onSubmit(dso: TDomain) {
|
onSubmit(dso: TDomain) {
|
||||||
this.parentUUID$.pipe(take(1)).subscribe((uuid: string) => {
|
this.parentUUID$.pipe(take(1)).subscribe((uuid: string) => {
|
||||||
this.dsoDataService.create(dso, uuid)
|
this.dsoDataService.create(dso, uuid)
|
@@ -1,22 +1,25 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
import { CommunityDataService } from '../../../core/data/community-data.service';
|
||||||
import { RouteService } from '../../shared/services/route.service';
|
import { RouteService } from '../../services/route.service';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { RemoteData } from '../../../core/data/remote-data';
|
||||||
import { Community } from '../../core/shared/community.model';
|
import { Community } from '../../../core/shared/community.model';
|
||||||
import { SharedModule } from '../../shared/shared.module';
|
import { SharedModule } from '../../shared.module';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { EditCommunityPageComponent } from './edit-community-page.component';
|
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||||
import { ActivatedRouteStub } from '../../shared/testing/active-router-stub';
|
import { NormalizedDSpaceObject } from '../../../core/cache/models/normalized-dspace-object.model';
|
||||||
|
import { EditComColPageComponent } from './edit-comcol-page.component';
|
||||||
|
import { DataService } from '../../../core/data/data.service';
|
||||||
|
|
||||||
fdescribe('EditCommunityPageComponent', () => {
|
describe('EditComColPageComponent', () => {
|
||||||
let comp: EditCommunityPageComponent;
|
let comp: EditComColPageComponent<DSpaceObject, NormalizedDSpaceObject>;
|
||||||
let fixture: ComponentFixture<EditCommunityPageComponent>;
|
let fixture: ComponentFixture<EditComColPageComponent<DSpaceObject, NormalizedDSpaceObject>>;
|
||||||
let communityDataService: CommunityDataService;
|
let communityDataService: CommunityDataService;
|
||||||
|
let dsoDataService: CommunityDataService;
|
||||||
let routeService: RouteService;
|
let routeService: RouteService;
|
||||||
let router: Router;
|
let router: Router;
|
||||||
|
|
||||||
@@ -73,9 +76,8 @@ fdescribe('EditCommunityPageComponent', () => {
|
|||||||
initializeVars();
|
initializeVars();
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
||||||
declarations: [EditCommunityPageComponent],
|
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: CommunityDataService, useValue: communityDataServiceStub },
|
{ provide: DataService, useValue: communityDataServiceStub },
|
||||||
{ provide: RouteService, useValue: routeServiceStub },
|
{ provide: RouteService, useValue: routeServiceStub },
|
||||||
{ provide: Router, useValue: routerStub },
|
{ provide: Router, useValue: routerStub },
|
||||||
{ provide: ActivatedRoute, useValue: routeStub },
|
{ provide: ActivatedRoute, useValue: routeStub },
|
||||||
@@ -85,9 +87,10 @@ fdescribe('EditCommunityPageComponent', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(EditCommunityPageComponent);
|
fixture = TestBed.createComponent(EditComColPageComponent);
|
||||||
comp = fixture.componentInstance;
|
comp = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
dsoDataService = (comp as any).dsoDataService;
|
||||||
communityDataService = (comp as any).communityDataService;
|
communityDataService = (comp as any).communityDataService;
|
||||||
routeService = (comp as any).routeService;
|
routeService = (comp as any).routeService;
|
||||||
router = (comp as any).router;
|
router = (comp as any).router;
|
||||||
@@ -112,7 +115,7 @@ fdescribe('EditCommunityPageComponent', () => {
|
|||||||
|
|
||||||
it('should not navigate on failure', () => {
|
it('should not navigate on failure', () => {
|
||||||
spyOn(router, 'navigate');
|
spyOn(router, 'navigate');
|
||||||
spyOn(communityDataService, 'update').and.returnValue(observableOf(new RemoteData(true, true, false, undefined, newCommunity)));
|
spyOn(dsoDataService, 'update').and.returnValue(observableOf(new RemoteData(true, true, false, undefined, newCommunity)));
|
||||||
comp.onSubmit(data);
|
comp.onSubmit(data);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(router.navigate).not.toHaveBeenCalled();
|
expect(router.navigate).not.toHaveBeenCalled();
|
@@ -0,0 +1,56 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { RouteService } from '../../services/route.service';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { RemoteData } from '../../../core/data/remote-data';
|
||||||
|
import { isNotUndefined } from '../../empty.util';
|
||||||
|
import { first, map } from 'rxjs/operators';
|
||||||
|
import { getSucceededRemoteData } from '../../../core/shared/operators';
|
||||||
|
import { DataService } from '../../../core/data/data.service';
|
||||||
|
import { NormalizedDSpaceObject } from '../../../core/cache/models/normalized-dspace-object.model';
|
||||||
|
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component representing the edit page for communities and collections
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-edit-comcol',
|
||||||
|
template: ''
|
||||||
|
})
|
||||||
|
export class EditComColPageComponent<TDomain extends DSpaceObject, TNormalized extends NormalizedDSpaceObject> implements OnInit {
|
||||||
|
/**
|
||||||
|
* Frontend endpoint where for this type of DSP
|
||||||
|
*/
|
||||||
|
protected frontendURL: string;
|
||||||
|
/**
|
||||||
|
* The initial DSO object
|
||||||
|
*/
|
||||||
|
public dsoRD$: Observable<RemoteData<TDomain>>;
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
protected dsoDataService: DataService<TNormalized, TDomain>,
|
||||||
|
protected routeService: RouteService,
|
||||||
|
protected router: Router,
|
||||||
|
protected route: ActivatedRoute
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.dsoRD$ = this.route.data.pipe(first(), map((data) => data.dso));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {TDomain} dso The updated version of the DSO
|
||||||
|
* Updates an existing DSO based on the submitted user data and navigates to the editted object's home page
|
||||||
|
*/
|
||||||
|
onSubmit(dso: TDomain) {
|
||||||
|
this.dsoDataService.update(dso)
|
||||||
|
.pipe(getSucceededRemoteData())
|
||||||
|
.subscribe((dsoRD: RemoteData<TDomain>) => {
|
||||||
|
if (isNotUndefined(dsoRD)) {
|
||||||
|
const newUUID = dsoRD.payload.uuid;
|
||||||
|
this.router.navigate([this.frontendURL + newUUID]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -86,6 +86,9 @@ import { CapitalizePipe } from './utils/capitalize.pipe';
|
|||||||
import { ObjectKeysPipe } from './utils/object-keys-pipe';
|
import { ObjectKeysPipe } from './utils/object-keys-pipe';
|
||||||
import { MomentModule } from 'ngx-moment';
|
import { MomentModule } from 'ngx-moment';
|
||||||
import { MenuModule } from './menu/menu.module';
|
import { MenuModule } from './menu/menu.module';
|
||||||
|
import { ComColFormComponent } from './comcol-forms/comcol-form/comcol-form.component';
|
||||||
|
import { CreateComColPageComponent } from './comcol-forms/create-comcol-page/create-comcol-page.component';
|
||||||
|
import { EditComColPageComponent } from './comcol-forms/edit-comcol-page/edit-comcol-page.component';
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
||||||
@@ -129,6 +132,9 @@ const COMPONENTS = [
|
|||||||
ComcolPageContentComponent,
|
ComcolPageContentComponent,
|
||||||
ComcolPageHeaderComponent,
|
ComcolPageHeaderComponent,
|
||||||
ComcolPageLogoComponent,
|
ComcolPageLogoComponent,
|
||||||
|
ComColFormComponent,
|
||||||
|
CreateComColPageComponent,
|
||||||
|
EditComColPageComponent,
|
||||||
DsDynamicFormComponent,
|
DsDynamicFormComponent,
|
||||||
DsDynamicFormControlComponent,
|
DsDynamicFormControlComponent,
|
||||||
DsDynamicListComponent,
|
DsDynamicListComponent,
|
||||||
|
Reference in New Issue
Block a user