mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 18:14:17 +00:00
Merge branch 'master' into w2p-64503_Edit-collection-Content-Source-2
Conflicts: resources/i18n/en.json5 src/app/+collection-page/edit-collection-page/edit-collection-page.component.ts src/app/+community-page/edit-community-page/edit-community-page.component.ts src/app/shared/shared.module.ts
This commit is contained in:
@@ -244,6 +244,8 @@
|
|||||||
|
|
||||||
"collection.create.head": "Create a Collection",
|
"collection.create.head": "Create a Collection",
|
||||||
|
|
||||||
|
"collection.create.notifications.success": "Successfully created the Collection",
|
||||||
|
|
||||||
"collection.create.sub-head": "Create a Collection for Community {{ parent }}",
|
"collection.create.sub-head": "Create a Collection for Community {{ parent }}",
|
||||||
|
|
||||||
"collection.delete.cancel": "Cancel",
|
"collection.delete.cancel": "Cancel",
|
||||||
@@ -302,6 +304,24 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"collection.edit.logo.label": "Collection logo",
|
||||||
|
|
||||||
|
"collection.edit.logo.notifications.add.error": "Uploading Collection logo failed. Please verify the content before retrying.",
|
||||||
|
|
||||||
|
"collection.edit.logo.notifications.add.success": "Upload Collection logo successful.",
|
||||||
|
|
||||||
|
"collection.edit.logo.notifications.delete.success.title": "Logo deleted",
|
||||||
|
|
||||||
|
"collection.edit.logo.notifications.delete.success.content": "Successfully deleted the collection's logo",
|
||||||
|
|
||||||
|
"collection.edit.logo.notifications.delete.error.title": "Error deleting logo",
|
||||||
|
|
||||||
|
"collection.edit.logo.upload": "Drop a Collection Logo to upload",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"collection.edit.notifications.success": "Successfully edited the Collection",
|
||||||
|
|
||||||
"collection.edit.return": "Return",
|
"collection.edit.return": "Return",
|
||||||
|
|
||||||
|
|
||||||
@@ -410,6 +430,8 @@
|
|||||||
|
|
||||||
"community.create.head": "Create a Community",
|
"community.create.head": "Create a Community",
|
||||||
|
|
||||||
|
"community.create.notifications.success": "Successfully created the Community",
|
||||||
|
|
||||||
"community.create.sub-head": "Create a Sub-Community for Community {{ parent }}",
|
"community.create.sub-head": "Create a Sub-Community for Community {{ parent }}",
|
||||||
|
|
||||||
"community.delete.cancel": "Cancel",
|
"community.delete.cancel": "Cancel",
|
||||||
@@ -428,8 +450,30 @@
|
|||||||
|
|
||||||
"community.edit.head": "Edit Community",
|
"community.edit.head": "Edit Community",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"community.edit.logo.label": "Community logo",
|
||||||
|
|
||||||
|
"community.edit.logo.notifications.add.error": "Uploading Community logo failed. Please verify the content before retrying.",
|
||||||
|
|
||||||
|
"community.edit.logo.notifications.add.success": "Upload Community logo successful.",
|
||||||
|
|
||||||
|
"community.edit.logo.notifications.delete.success.title": "Logo deleted",
|
||||||
|
|
||||||
|
"community.edit.logo.notifications.delete.success.content": "Successfully deleted the community's logo",
|
||||||
|
|
||||||
|
"community.edit.logo.notifications.delete.error.title": "Error deleting logo",
|
||||||
|
|
||||||
|
"community.edit.logo.upload": "Drop a Community Logo to upload",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"community.edit.notifications.success": "Successfully edited the Community",
|
||||||
|
|
||||||
"community.edit.return": "Return",
|
"community.edit.return": "Return",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"community.edit.tabs.curate.head": "Curate",
|
"community.edit.tabs.curate.head": "Curate",
|
||||||
|
|
||||||
"community.edit.tabs.curate.title": "Community Edit - Curate",
|
"community.edit.tabs.curate.title": "Community Edit - Curate",
|
||||||
@@ -442,6 +486,8 @@
|
|||||||
|
|
||||||
"community.edit.tabs.roles.title": "Community Edit - Roles",
|
"community.edit.tabs.roles.title": "Community Edit - Roles",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"community.form.abstract": "Short Description",
|
"community.form.abstract": "Short Description",
|
||||||
|
|
||||||
"community.form.description": "Introductory text (HTML)",
|
"community.form.description": "Introductory text (HTML)",
|
||||||
@@ -1847,7 +1893,7 @@
|
|||||||
|
|
||||||
"uploader.drag-message": "Drag & Drop your files here",
|
"uploader.drag-message": "Drag & Drop your files here",
|
||||||
|
|
||||||
"uploader.or": ", or",
|
"uploader.or": ", or ",
|
||||||
|
|
||||||
"uploader.processing": "Processing",
|
"uploader.processing": "Processing",
|
||||||
|
|
||||||
|
@@ -1,9 +1,15 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
import { DynamicInputModel, DynamicTextAreaModel } from '@ng-dynamic-forms/core';
|
import { DynamicFormService, 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 { Collection } from '../../core/shared/collection.model';
|
import { Collection } from '../../core/shared/collection.model';
|
||||||
import { ComColFormComponent } from '../../shared/comcol-forms/comcol-form/comcol-form.component';
|
import { ComColFormComponent } from '../../shared/comcol-forms/comcol-form/comcol-form.component';
|
||||||
import { NormalizedCollection } from '../../core/cache/models/normalized-collection.model';
|
import { Location } from '@angular/common';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||||
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
import { RequestService } from '../../core/data/request.service';
|
||||||
|
import { ObjectCacheService } from '../../core/cache/object-cache.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Form used for creating and editing collections
|
* Form used for creating and editing collections
|
||||||
@@ -22,7 +28,7 @@ export class CollectionFormComponent extends ComColFormComponent<Collection> {
|
|||||||
/**
|
/**
|
||||||
* @type {Collection.type} This is a collection-type form
|
* @type {Collection.type} This is a collection-type form
|
||||||
*/
|
*/
|
||||||
protected type = Collection.type;
|
type = Collection.type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The dynamic form fields used for creating/editing a collection
|
* The dynamic form fields used for creating/editing a collection
|
||||||
@@ -65,4 +71,15 @@ export class CollectionFormComponent extends ComColFormComponent<Collection> {
|
|||||||
name: 'dc.description.provenance',
|
name: 'dc.description.provenance',
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public constructor(protected location: Location,
|
||||||
|
protected formService: DynamicFormService,
|
||||||
|
protected translate: TranslateService,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected authService: AuthService,
|
||||||
|
protected dsoService: CommunityDataService,
|
||||||
|
protected requestService: RequestService,
|
||||||
|
protected objectCache: ObjectCacheService) {
|
||||||
|
super(location, formService, translate, notificationsService, authService, requestService, objectCache);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,15 +5,17 @@
|
|||||||
<div *ngIf="collectionRD?.payload as collection">
|
<div *ngIf="collectionRD?.payload as collection">
|
||||||
<ds-view-tracker [object]="collection"></ds-view-tracker>
|
<ds-view-tracker [object]="collection"></ds-view-tracker>
|
||||||
<header class="comcol-header border-bottom mb-4 pb-4">
|
<header class="comcol-header border-bottom mb-4 pb-4">
|
||||||
<!-- Collection logo -->
|
<!-- Collection Name -->
|
||||||
<ds-comcol-page-logo *ngIf="logoRD$"
|
|
||||||
[logo]="(logoRD$ | async)?.payload" [alternateText]="'Collection Logo'">
|
|
||||||
[alternateText]="'Collection Logo'">
|
|
||||||
</ds-comcol-page-logo>
|
|
||||||
<!-- Collection Name -->
|
|
||||||
<ds-comcol-page-header
|
<ds-comcol-page-header
|
||||||
[name]="collection.name">
|
[name]="collection.name">
|
||||||
</ds-comcol-page-header>
|
</ds-comcol-page-header>
|
||||||
|
<!-- Collection logo -->
|
||||||
|
<ds-comcol-page-logo *ngIf="logoRD$"
|
||||||
|
[logo]="(logoRD$ | async)?.payload"
|
||||||
|
[alternateText]="'Collection Logo'"
|
||||||
|
[alternateText]="'Collection Logo'">
|
||||||
|
</ds-comcol-page-logo>
|
||||||
|
|
||||||
<!-- Handle -->
|
<!-- Handle -->
|
||||||
<ds-comcol-page-handle
|
<ds-comcol-page-handle
|
||||||
[content]="collection.handle"
|
[content]="collection.handle"
|
||||||
|
@@ -4,5 +4,5 @@
|
|||||||
<h2 id="sub-header" class="border-bottom pb-2">{{'collection.create.sub-head' | translate:{ parent: (parentRD$| async)?.payload.name } }}</h2>
|
<h2 id="sub-header" class="border-bottom pb-2">{{'collection.create.sub-head' | translate:{ parent: (parentRD$| async)?.payload.name } }}</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ds-collection-form (submitForm)="onSubmit($event)"></ds-collection-form>
|
<ds-collection-form (submitForm)="onSubmit($event)" (finish)="navigateToNewPage()"></ds-collection-form>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -10,6 +10,8 @@ import { CollectionDataService } from '../../core/data/collection-data.service';
|
|||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||||
import { CreateCollectionPageComponent } from './create-collection-page.component';
|
import { CreateCollectionPageComponent } from './create-collection-page.component';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { NotificationsServiceStub } from '../../shared/testing/notifications-service-stub';
|
||||||
|
|
||||||
describe('CreateCollectionPageComponent', () => {
|
describe('CreateCollectionPageComponent', () => {
|
||||||
let comp: CreateCollectionPageComponent;
|
let comp: CreateCollectionPageComponent;
|
||||||
@@ -27,6 +29,7 @@ describe('CreateCollectionPageComponent', () => {
|
|||||||
},
|
},
|
||||||
{ provide: RouteService, useValue: { getQueryParameterValue: () => observableOf('1234') } },
|
{ provide: RouteService, useValue: { getQueryParameterValue: () => observableOf('1234') } },
|
||||||
{ provide: Router, useValue: {} },
|
{ provide: Router, useValue: {} },
|
||||||
|
{ provide: NotificationsService, useValue: new NotificationsServiceStub() }
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
@@ -5,6 +5,8 @@ import { Router } from '@angular/router';
|
|||||||
import { CreateComColPageComponent } from '../../shared/comcol-forms/create-comcol-page/create-comcol-page.component';
|
import { CreateComColPageComponent } from '../../shared/comcol-forms/create-comcol-page/create-comcol-page.component';
|
||||||
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';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that represents the page where a user can create a new Collection
|
* Component that represents the page where a user can create a new Collection
|
||||||
@@ -16,13 +18,16 @@ import { CollectionDataService } from '../../core/data/collection-data.service';
|
|||||||
})
|
})
|
||||||
export class CreateCollectionPageComponent extends CreateComColPageComponent<Collection> {
|
export class CreateCollectionPageComponent extends CreateComColPageComponent<Collection> {
|
||||||
protected frontendURL = '/collections/';
|
protected frontendURL = '/collections/';
|
||||||
|
protected type = Collection.type;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
protected communityDataService: CommunityDataService,
|
protected communityDataService: CommunityDataService,
|
||||||
protected collectionDataService: CollectionDataService,
|
protected collectionDataService: CollectionDataService,
|
||||||
protected routeService: RouteService,
|
protected routeService: RouteService,
|
||||||
protected router: Router
|
protected router: Router,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected translate: TranslateService
|
||||||
) {
|
) {
|
||||||
super(collectionDataService, communityDataService, routeService, router);
|
super(collectionDataService, communityDataService, routeService, router, notificationsService, translate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
<ds-collection-form (submitForm)="onSubmit($event)" [dso]="(dsoRD$ | async)?.payload"></ds-collection-form>
|
<ds-collection-form (submitForm)="onSubmit($event)"
|
||||||
|
[dso]="(dsoRD$ | async)?.payload"
|
||||||
|
(finish)="navigateToHomePage()"></ds-collection-form>
|
||||||
<a class="btn btn-danger"
|
<a class="btn btn-danger"
|
||||||
[routerLink]="'/collections/' + (dsoRD$ | async)?.payload.uuid + '/delete'">{{'collection.edit.delete'
|
[routerLink]="'/collections/' + (dsoRD$ | async)?.payload.uuid + '/delete'">{{'collection.edit.delete'
|
||||||
| translate}}</a>
|
| translate}}</a>
|
||||||
|
@@ -8,6 +8,8 @@ import { ActivatedRoute } from '@angular/router';
|
|||||||
import { of as observableOf } from 'rxjs/internal/observable/of';
|
import { of as observableOf } from 'rxjs/internal/observable/of';
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { CollectionMetadataComponent } from './collection-metadata.component';
|
import { CollectionMetadataComponent } from './collection-metadata.component';
|
||||||
|
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||||
|
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub';
|
||||||
|
|
||||||
describe('CollectionMetadataComponent', () => {
|
describe('CollectionMetadataComponent', () => {
|
||||||
let comp: CollectionMetadataComponent;
|
let comp: CollectionMetadataComponent;
|
||||||
@@ -20,6 +22,7 @@ describe('CollectionMetadataComponent', () => {
|
|||||||
providers: [
|
providers: [
|
||||||
{ provide: CollectionDataService, useValue: {} },
|
{ provide: CollectionDataService, useValue: {} },
|
||||||
{ provide: ActivatedRoute, useValue: { parent: { data: observableOf({ dso: { payload: {} } }) } } },
|
{ provide: ActivatedRoute, useValue: { parent: { data: observableOf({ dso: { payload: {} } }) } } },
|
||||||
|
{ provide: NotificationsService, useValue: new NotificationsServiceStub() }
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
@@ -3,6 +3,8 @@ import { ComcolMetadataComponent } from '../../../shared/comcol-forms/edit-comco
|
|||||||
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';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component for editing a collection's metadata
|
* Component for editing a collection's metadata
|
||||||
@@ -13,12 +15,15 @@ import { ActivatedRoute, Router } from '@angular/router';
|
|||||||
})
|
})
|
||||||
export class CollectionMetadataComponent extends ComcolMetadataComponent<Collection> {
|
export class CollectionMetadataComponent extends ComcolMetadataComponent<Collection> {
|
||||||
protected frontendURL = '/collections/';
|
protected frontendURL = '/collections/';
|
||||||
|
protected type = Collection.type;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
protected collectionDataService: CollectionDataService,
|
protected collectionDataService: CollectionDataService,
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
protected route: ActivatedRoute
|
protected route: ActivatedRoute,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected translate: TranslateService
|
||||||
) {
|
) {
|
||||||
super(collectionDataService, router, route);
|
super(collectionDataService, router, route, notificationsService, translate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,7 @@ import { getCollectionPageRoute } from '../collection-page-routing.module';
|
|||||||
templateUrl: '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html'
|
templateUrl: '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html'
|
||||||
})
|
})
|
||||||
export class EditCollectionPageComponent extends EditComColPageComponent<Collection> {
|
export class EditCollectionPageComponent extends EditComColPageComponent<Collection> {
|
||||||
public type = 'collection';
|
type = 'collection';
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
|
@@ -28,7 +28,10 @@ import { CollectionCurateComponent } from './collection-curate/collection-curate
|
|||||||
{
|
{
|
||||||
path: 'metadata',
|
path: 'metadata',
|
||||||
component: CollectionMetadataComponent,
|
component: CollectionMetadataComponent,
|
||||||
data: { title: 'collection.edit.tabs.metadata.title' }
|
data: {
|
||||||
|
title: 'collection.edit.tabs.metadata.title',
|
||||||
|
hideReturnButton: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'roles',
|
path: 'roles',
|
||||||
|
@@ -1,9 +1,16 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
import { DynamicInputModel, DynamicTextAreaModel } from '@ng-dynamic-forms/core';
|
import { DynamicFormService, 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 '../../shared/comcol-forms/comcol-form/comcol-form.component';
|
import { ComColFormComponent } from '../../shared/comcol-forms/comcol-form/comcol-form.component';
|
||||||
|
import { Location } from '@angular/common';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||||
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
import { RequestService } from '../../core/data/request.service';
|
||||||
|
import { ObjectCacheService } from '../../core/cache/object-cache.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Form used for creating and editing communities
|
* Form used for creating and editing communities
|
||||||
@@ -22,7 +29,7 @@ export class CommunityFormComponent extends ComColFormComponent<Community> {
|
|||||||
/**
|
/**
|
||||||
* @type {Community.type} This is a community-type form
|
* @type {Community.type} This is a community-type form
|
||||||
*/
|
*/
|
||||||
protected type = Community.type;
|
type = Community.type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The dynamic form fields used for creating/editing a community
|
* The dynamic form fields used for creating/editing a community
|
||||||
@@ -57,4 +64,15 @@ export class CommunityFormComponent extends ComColFormComponent<Community> {
|
|||||||
name: 'dc.description.tableofcontents',
|
name: 'dc.description.tableofcontents',
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public constructor(protected location: Location,
|
||||||
|
protected formService: DynamicFormService,
|
||||||
|
protected translate: TranslateService,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected authService: AuthService,
|
||||||
|
protected dsoService: CommunityDataService,
|
||||||
|
protected requestService: RequestService,
|
||||||
|
protected objectCache: ObjectCacheService) {
|
||||||
|
super(location, formService, translate, notificationsService, authService, requestService, objectCache);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,12 +3,11 @@
|
|||||||
<div *ngIf="communityRD?.payload; let communityPayload">
|
<div *ngIf="communityRD?.payload; let communityPayload">
|
||||||
<ds-view-tracker [object]="communityPayload"></ds-view-tracker>
|
<ds-view-tracker [object]="communityPayload"></ds-view-tracker>
|
||||||
<header class="comcol-header border-bottom mb-4 pb-4">
|
<header class="comcol-header border-bottom mb-4 pb-4">
|
||||||
|
<!-- Community name -->
|
||||||
|
<ds-comcol-page-header [name]="communityPayload.name"></ds-comcol-page-header>
|
||||||
<!-- Community logo -->
|
<!-- Community logo -->
|
||||||
<ds-comcol-page-logo *ngIf="logoRD$" [logo]="(logoRD$ | async)?.payload" [alternateText]="'Community Logo'">
|
<ds-comcol-page-logo *ngIf="logoRD$" [logo]="(logoRD$ | async)?.payload" [alternateText]="'Community Logo'">
|
||||||
</ds-comcol-page-logo>
|
</ds-comcol-page-logo>
|
||||||
|
|
||||||
<!-- Community name -->
|
|
||||||
<ds-comcol-page-header [name]="communityPayload.name"></ds-comcol-page-header>
|
|
||||||
<!-- Handle -->
|
<!-- Handle -->
|
||||||
<ds-comcol-page-handle [content]="communityPayload.handle" [title]="'community.page.handle'">
|
<ds-comcol-page-handle [content]="communityPayload.handle" [title]="'community.page.handle'">
|
||||||
</ds-comcol-page-handle>
|
</ds-comcol-page-handle>
|
||||||
|
@@ -7,5 +7,5 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ds-community-form (submitForm)="onSubmit($event)"></ds-community-form>
|
<ds-community-form (submitForm)="onSubmit($event)" (finish)="navigateToNewPage()"></ds-community-form>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -10,6 +10,8 @@ import { CollectionDataService } from '../../core/data/collection-data.service';
|
|||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||||
import { CreateCommunityPageComponent } from './create-community-page.component';
|
import { CreateCommunityPageComponent } from './create-community-page.component';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { NotificationsServiceStub } from '../../shared/testing/notifications-service-stub';
|
||||||
|
|
||||||
describe('CreateCommunityPageComponent', () => {
|
describe('CreateCommunityPageComponent', () => {
|
||||||
let comp: CreateCommunityPageComponent;
|
let comp: CreateCommunityPageComponent;
|
||||||
@@ -23,6 +25,7 @@ describe('CreateCommunityPageComponent', () => {
|
|||||||
{ provide: CommunityDataService, useValue: { findById: () => observableOf({}) } },
|
{ provide: CommunityDataService, useValue: { findById: () => observableOf({}) } },
|
||||||
{ provide: RouteService, useValue: { getQueryParameterValue: () => observableOf('1234') } },
|
{ provide: RouteService, useValue: { getQueryParameterValue: () => observableOf('1234') } },
|
||||||
{ provide: Router, useValue: {} },
|
{ provide: Router, useValue: {} },
|
||||||
|
{ provide: NotificationsService, useValue: new NotificationsServiceStub() }
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
@@ -4,6 +4,8 @@ import { CommunityDataService } from '../../core/data/community-data.service';
|
|||||||
import { RouteService } from '../../core/services/route.service';
|
import { RouteService } from '../../core/services/route.service';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { CreateComColPageComponent } from '../../shared/comcol-forms/create-comcol-page/create-comcol-page.component';
|
import { CreateComColPageComponent } from '../../shared/comcol-forms/create-comcol-page/create-comcol-page.component';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that represents the page where a user can create a new Community
|
* Component that represents the page where a user can create a new Community
|
||||||
@@ -15,12 +17,15 @@ import { CreateComColPageComponent } from '../../shared/comcol-forms/create-comc
|
|||||||
})
|
})
|
||||||
export class CreateCommunityPageComponent extends CreateComColPageComponent<Community> {
|
export class CreateCommunityPageComponent extends CreateComColPageComponent<Community> {
|
||||||
protected frontendURL = '/communities/';
|
protected frontendURL = '/communities/';
|
||||||
|
protected type = Community.type;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
protected communityDataService: CommunityDataService,
|
protected communityDataService: CommunityDataService,
|
||||||
protected routeService: RouteService,
|
protected routeService: RouteService,
|
||||||
protected router: Router
|
protected router: Router,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected translate: TranslateService
|
||||||
) {
|
) {
|
||||||
super(communityDataService, communityDataService, routeService, router);
|
super(communityDataService, communityDataService, routeService, router, notificationsService, translate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
<ds-community-form (submitForm)="onSubmit($event)" [dso]="(dsoRD$ | async)?.payload"></ds-community-form>
|
<ds-community-form (submitForm)="onSubmit($event)"
|
||||||
|
[dso]="(dsoRD$ | async)?.payload"
|
||||||
|
(finish)="navigateToHomePage()"></ds-community-form>
|
||||||
<a class="btn btn-danger"
|
<a class="btn btn-danger"
|
||||||
[routerLink]="'/communities/' + (dsoRD$ | async)?.payload.uuid + '/delete'">{{'community.edit.delete'
|
[routerLink]="'/communities/' + (dsoRD$ | async)?.payload.uuid + '/delete'">{{'community.edit.delete'
|
||||||
| translate}}</a>
|
| translate}}</a>
|
||||||
|
@@ -8,6 +8,8 @@ import { of as observableOf } from 'rxjs/internal/observable/of';
|
|||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { CommunityMetadataComponent } from './community-metadata.component';
|
import { CommunityMetadataComponent } from './community-metadata.component';
|
||||||
import { CommunityDataService } from '../../../core/data/community-data.service';
|
import { CommunityDataService } from '../../../core/data/community-data.service';
|
||||||
|
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||||
|
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub';
|
||||||
|
|
||||||
describe('CommunityMetadataComponent', () => {
|
describe('CommunityMetadataComponent', () => {
|
||||||
let comp: CommunityMetadataComponent;
|
let comp: CommunityMetadataComponent;
|
||||||
@@ -20,6 +22,7 @@ describe('CommunityMetadataComponent', () => {
|
|||||||
providers: [
|
providers: [
|
||||||
{ provide: CommunityDataService, useValue: {} },
|
{ provide: CommunityDataService, useValue: {} },
|
||||||
{ provide: ActivatedRoute, useValue: { parent: { data: observableOf({ dso: { payload: {} } }) } } },
|
{ provide: ActivatedRoute, useValue: { parent: { data: observableOf({ dso: { payload: {} } }) } } },
|
||||||
|
{ provide: NotificationsService, useValue: new NotificationsServiceStub() }
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
@@ -3,6 +3,8 @@ import { ComcolMetadataComponent } from '../../../shared/comcol-forms/edit-comco
|
|||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
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 { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component for editing a community's metadata
|
* Component for editing a community's metadata
|
||||||
@@ -13,12 +15,15 @@ import { CommunityDataService } from '../../../core/data/community-data.service'
|
|||||||
})
|
})
|
||||||
export class CommunityMetadataComponent extends ComcolMetadataComponent<Community> {
|
export class CommunityMetadataComponent extends ComcolMetadataComponent<Community> {
|
||||||
protected frontendURL = '/communities/';
|
protected frontendURL = '/communities/';
|
||||||
|
protected type = Community.type;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
protected communityDataService: CommunityDataService,
|
protected communityDataService: CommunityDataService,
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
protected route: ActivatedRoute
|
protected route: ActivatedRoute,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected translate: TranslateService
|
||||||
) {
|
) {
|
||||||
super(communityDataService, router, route);
|
super(communityDataService, router, route, notificationsService, translate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,7 @@ import { getCommunityPageRoute } from '../community-page-routing.module';
|
|||||||
templateUrl: '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html'
|
templateUrl: '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html'
|
||||||
})
|
})
|
||||||
export class EditCommunityPageComponent extends EditComColPageComponent<Community> {
|
export class EditCommunityPageComponent extends EditComColPageComponent<Community> {
|
||||||
public type = 'community';
|
type = 'community';
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
|
@@ -27,7 +27,10 @@ import { CommunityCurateComponent } from './community-curate/community-curate.co
|
|||||||
{
|
{
|
||||||
path: 'metadata',
|
path: 'metadata',
|
||||||
component: CommunityMetadataComponent,
|
component: CommunityMetadataComponent,
|
||||||
data: { title: 'community.edit.tabs.metadata.title' }
|
data: {
|
||||||
|
title: 'community.edit.tabs.metadata.title',
|
||||||
|
hideReturnButton: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'roles',
|
path: 'roles',
|
||||||
|
@@ -33,12 +33,7 @@ export class MyDSpaceNewSubmissionComponent implements OnDestroy, OnInit {
|
|||||||
/**
|
/**
|
||||||
* The UploaderOptions object
|
* The UploaderOptions object
|
||||||
*/
|
*/
|
||||||
public uploadFilesOptions: UploaderOptions = {
|
public uploadFilesOptions: UploaderOptions = new UploaderOptions();
|
||||||
url: '',
|
|
||||||
authToken: null,
|
|
||||||
disableMultipart: false,
|
|
||||||
itemAlias: null
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscription to unsubscribe from
|
* Subscription to unsubscribe from
|
||||||
|
@@ -1,32 +1,41 @@
|
|||||||
import {
|
import {
|
||||||
distinctUntilChanged,
|
distinctUntilChanged,
|
||||||
filter, first,
|
filter, first,map, mergeMap, share, switchMap,
|
||||||
map,
|
|
||||||
mergeMap,
|
|
||||||
share,
|
|
||||||
switchMap,
|
|
||||||
take,
|
take,
|
||||||
tap
|
tap
|
||||||
} from 'rxjs/operators';
|
} from 'rxjs/operators';
|
||||||
import { merge as observableMerge, Observable, throwError as observableThrowError } from 'rxjs';
|
import { merge as observableMerge, Observable, throwError as observableThrowError, combineLatest as observableCombineLatest } from 'rxjs';
|
||||||
import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util';
|
import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util';
|
||||||
import { NormalizedCommunity } from '../cache/models/normalized-community.model';
|
import { NormalizedCommunity } from '../cache/models/normalized-community.model';
|
||||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
import { CommunityDataService } from './community-data.service';
|
import { CommunityDataService } from './community-data.service';
|
||||||
|
|
||||||
import { DataService } from './data.service';
|
import { DataService } from './data.service';
|
||||||
|
import { DeleteRequest, FindListOptions, FindByIDRequest, RestRequest } from './request.models';
|
||||||
import { PaginatedList } from './paginated-list';
|
import { PaginatedList } from './paginated-list';
|
||||||
import { RemoteData } from './remote-data';
|
import { RemoteData } from './remote-data';
|
||||||
import { FindListOptions, FindByIDRequest } from './request.models';
|
|
||||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
import { getResponseFromEntry } from '../shared/operators';
|
import {
|
||||||
|
configureRequest,
|
||||||
|
getRemoteDataPayload,
|
||||||
|
getResponseFromEntry,
|
||||||
|
getSucceededRemoteData
|
||||||
|
} from '../shared/operators';
|
||||||
import { CacheableObject } from '../cache/object-cache.reducer';
|
import { CacheableObject } from '../cache/object-cache.reducer';
|
||||||
|
import { RestResponse } from '../cache/response.models';
|
||||||
|
import { Bitstream } from '../shared/bitstream.model';
|
||||||
|
import { DSpaceObject } from '../shared/dspace-object.model';
|
||||||
|
|
||||||
export abstract class ComColDataService<T extends CacheableObject> extends DataService<T> {
|
export abstract class ComColDataService<T extends CacheableObject> extends DataService<T> {
|
||||||
protected abstract cds: CommunityDataService;
|
protected abstract cds: CommunityDataService;
|
||||||
protected abstract objectCache: ObjectCacheService;
|
protected abstract objectCache: ObjectCacheService;
|
||||||
protected abstract halService: HALEndpointService;
|
protected abstract halService: HALEndpointService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Linkpath of endpoint to delete the logo
|
||||||
|
*/
|
||||||
|
protected logoDeleteLinkpath = 'bitstreams';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the scoped endpoint URL by fetching the object with
|
* Get the scoped endpoint URL by fetching the object with
|
||||||
* the given scopeID and returning its HAL link with this
|
* the given scopeID and returning its HAL link with this
|
||||||
@@ -76,4 +85,33 @@ export abstract class ComColDataService<T extends CacheableObject> extends DataS
|
|||||||
return this.findList(href$, options);
|
return this.findList(href$, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the endpoint for the community or collection's logo
|
||||||
|
* @param id The community or collection's ID
|
||||||
|
*/
|
||||||
|
public getLogoEndpoint(id: string): Observable<string> {
|
||||||
|
return this.halService.getEndpoint(this.linkPath).pipe(
|
||||||
|
switchMap((href: string) => this.halService.getEndpoint('logo', `${href}/${id}`))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the logo from the community or collection
|
||||||
|
* @param dso The object to delete the logo from
|
||||||
|
*/
|
||||||
|
public deleteLogo(dso: DSpaceObject): Observable<RestResponse> {
|
||||||
|
const logo$ = (dso as any).logo;
|
||||||
|
if (hasValue(logo$)) {
|
||||||
|
return observableCombineLatest(
|
||||||
|
logo$.pipe(getSucceededRemoteData(), getRemoteDataPayload(), take(1)),
|
||||||
|
this.halService.getEndpoint(this.logoDeleteLinkpath)
|
||||||
|
).pipe(
|
||||||
|
map(([logo, href]: [Bitstream, string]) => `${href}/${logo.id}`),
|
||||||
|
map((href: string) => new DeleteRequest(this.requestService.generateRequestId(), href)),
|
||||||
|
configureRequest(this.requestService),
|
||||||
|
switchMap((restRequest: RestRequest) => this.requestService.getByUUID(restRequest.uuid)),
|
||||||
|
getResponseFromEntry()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,3 +1,38 @@
|
|||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 d-inline-block">
|
||||||
|
<label>{{type.value + '.edit.logo.label' | translate}}</label>
|
||||||
|
</div>
|
||||||
|
<ng-container *ngVar="(dso?.logo | async)?.payload as logo">
|
||||||
|
<div class="col-12 d-inline-block alert" [ngClass]="{'alert-danger': markLogoForDeletion}" id="logo-section">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-8 d-inline-block">
|
||||||
|
<ds-comcol-page-logo [logo]="logo"></ds-comcol-page-logo>
|
||||||
|
</div>
|
||||||
|
<div class="col-4 d-inline-block">
|
||||||
|
<div *ngIf="logo" class="btn-group btn-group-sm float-right" role="group">
|
||||||
|
<button *ngIf="!markLogoForDeletion" type="button" class="btn btn-danger" (click)="deleteLogo()">
|
||||||
|
<i class="fas fa-trash" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="markLogoForDeletion" type="button" class="btn btn-warning" (click)="undoDeleteLogo()">
|
||||||
|
<i class="fas fa-undo" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="!logo" class="col-12 d-inline-block">
|
||||||
|
<ds-uploader *ngIf="initializedUploaderOptions | async"
|
||||||
|
[dropMsg]="type.value + '.edit.logo.upload'"
|
||||||
|
[dropOverDocumentMsg]="type.value + '.edit.logo.upload'"
|
||||||
|
[enableDragOverDocument]="true"
|
||||||
|
[uploadFilesOptions]="uploadFilesOptions"
|
||||||
|
(onCompleteItem)="onCompleteItem()"
|
||||||
|
(onUploadError)="onUploadError()"></ds-uploader>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<ds-form *ngIf="formModel"
|
<ds-form *ngIf="formModel"
|
||||||
[formId]="'comcol-form-id'"
|
[formId]="'comcol-form-id'"
|
||||||
[formModel]="formModel" (submitForm)="onSubmit()" (cancel)="onCancel()"></ds-form>
|
[formModel]="formModel" (submitForm)="onSubmit()" (cancel)="onCancel()"></ds-form>
|
||||||
|
@@ -7,10 +7,22 @@ import { DynamicFormService, 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 { ComColFormComponent } from './comcol-form.component';
|
import { ComColFormComponent } from './comcol-form.component';
|
||||||
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||||
import { hasValue } from '../../empty.util';
|
import { hasValue } from '../../empty.util';
|
||||||
|
import { VarDirective } from '../../utils/var.directive';
|
||||||
|
import { NotificationsService } from '../../notifications/notifications.service';
|
||||||
|
import { NotificationsServiceStub } from '../../testing/notifications-service-stub';
|
||||||
|
import { AuthService } from '../../../core/auth/auth.service';
|
||||||
|
import { AuthServiceMock } from '../../mocks/mock-auth.service';
|
||||||
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { RemoteData } from '../../../core/data/remote-data';
|
||||||
|
import { RestRequestMethod } from '../../../core/data/rest-request-method';
|
||||||
|
import { ErrorResponse, RestResponse } from '../../../core/cache/response.models';
|
||||||
|
import { RequestError } from '../../../core/data/request.models';
|
||||||
|
import { RequestService } from '../../../core/data/request.service';
|
||||||
|
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
|
||||||
describe('ComColFormComponent', () => {
|
describe('ComColFormComponent', () => {
|
||||||
let comp: ComColFormComponent<DSpaceObject>;
|
let comp: ComColFormComponent<DSpaceObject>;
|
||||||
@@ -49,71 +61,264 @@ describe('ComColFormComponent', () => {
|
|||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const logoEndpoint = 'rest/api/logo/endpoint';
|
||||||
|
const dsoService = Object.assign({
|
||||||
|
getLogoEndpoint: () => observableOf(logoEndpoint),
|
||||||
|
deleteLogo: () => observableOf({})
|
||||||
|
});
|
||||||
|
const notificationsService = new NotificationsServiceStub();
|
||||||
|
|
||||||
/* tslint:disable:no-empty */
|
/* tslint:disable:no-empty */
|
||||||
const locationStub = jasmine.createSpyObj('location', ['back']);
|
const locationStub = jasmine.createSpyObj('location', ['back']);
|
||||||
/* tslint:enable:no-empty */
|
/* tslint:enable:no-empty */
|
||||||
|
|
||||||
|
const requestServiceStub = jasmine.createSpyObj({
|
||||||
|
removeByHrefSubstring: {}
|
||||||
|
});
|
||||||
|
const objectCacheStub = jasmine.createSpyObj({
|
||||||
|
remove: {}
|
||||||
|
});
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [TranslateModule.forRoot(), RouterTestingModule],
|
imports: [TranslateModule.forRoot(), RouterTestingModule],
|
||||||
declarations: [ComColFormComponent],
|
declarations: [ComColFormComponent, VarDirective],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: Location, useValue: locationStub },
|
{ provide: Location, useValue: locationStub },
|
||||||
{ provide: DynamicFormService, useValue: formServiceStub }
|
{ provide: DynamicFormService, useValue: formServiceStub },
|
||||||
|
{ provide: NotificationsService, useValue: notificationsService },
|
||||||
|
{ provide: AuthService, useValue: new AuthServiceMock() },
|
||||||
|
{ provide: RequestService, useValue: requestServiceStub },
|
||||||
|
{ provide: ObjectCacheService, useValue: objectCacheStub }
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
describe('when the dso doesn\'t contain an ID (newly created)', () => {
|
||||||
fixture = TestBed.createComponent(ComColFormComponent);
|
|
||||||
comp = fixture.componentInstance;
|
|
||||||
comp.formModel = [];
|
|
||||||
comp.dso = new Community();
|
|
||||||
fixture.detectChanges();
|
|
||||||
location = (comp as any).location;
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('onSubmit', () => {
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
spyOn(comp.submitForm, 'emit');
|
initComponent(new Community());
|
||||||
comp.formModel = formModel;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should emit the new version of the community', () => {
|
it('should initialize the uploadFilesOptions with a placeholder url', () => {
|
||||||
comp.dso = Object.assign(
|
expect(comp.uploadFilesOptions.url.length).toBeGreaterThan(0);
|
||||||
new Community(),
|
});
|
||||||
{
|
|
||||||
metadata: {
|
|
||||||
...titleMD,
|
|
||||||
...randomMD
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
comp.onSubmit();
|
describe('onSubmit', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(comp.submitForm, 'emit');
|
||||||
|
comp.formModel = formModel;
|
||||||
|
});
|
||||||
|
|
||||||
expect(comp.submitForm.emit).toHaveBeenCalledWith(
|
it('should emit the new version of the community', () => {
|
||||||
Object.assign(
|
comp.dso = Object.assign(
|
||||||
{},
|
|
||||||
new Community(),
|
new Community(),
|
||||||
{
|
{
|
||||||
metadata: {
|
metadata: {
|
||||||
...newTitleMD,
|
...titleMD,
|
||||||
...randomMD,
|
...randomMD
|
||||||
...abstractMD
|
}
|
||||||
},
|
}
|
||||||
type: Community.type
|
);
|
||||||
},
|
|
||||||
)
|
|
||||||
);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('onCancel', () => {
|
comp.onSubmit();
|
||||||
it('should call the back method on the Location service', () => {
|
|
||||||
|
expect(comp.submitForm.emit).toHaveBeenCalledWith(
|
||||||
|
{
|
||||||
|
dso: Object.assign(
|
||||||
|
{},
|
||||||
|
new Community(),
|
||||||
|
{
|
||||||
|
metadata: {
|
||||||
|
...newTitleMD,
|
||||||
|
...randomMD,
|
||||||
|
...abstractMD
|
||||||
|
},
|
||||||
|
type: Community.type
|
||||||
|
},
|
||||||
|
),
|
||||||
|
uploader: {},
|
||||||
|
deleteLogo: false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('onCancel', () => {
|
||||||
|
it('should call the back method on the Location service', () => {
|
||||||
comp.onCancel();
|
comp.onCancel();
|
||||||
expect(locationStub.back).toHaveBeenCalled();
|
expect(locationStub.back).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('onCompleteItem', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(comp.finish, 'emit');
|
||||||
|
comp.onCompleteItem();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show a success notification', () => {
|
||||||
|
expect(notificationsService.success).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emit finish', () => {
|
||||||
|
expect(comp.finish.emit).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove the object\'s cache', () => {
|
||||||
|
expect(requestServiceStub.removeByHrefSubstring).toHaveBeenCalled();
|
||||||
|
expect(objectCacheStub.remove).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('onUploadError', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(comp.finish, 'emit');
|
||||||
|
comp.onUploadError();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show an error notification', () => {
|
||||||
|
expect(notificationsService.error).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emit finish', () => {
|
||||||
|
expect(comp.finish.emit).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when the dso contains an ID (being edited)', () => {
|
||||||
|
describe('and the dso doesn\'t contain a logo', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
initComponent(Object.assign(new Community(), {
|
||||||
|
id: 'community-id',
|
||||||
|
logo: observableOf(new RemoteData(false, false, true, null, undefined))
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should initialize the uploadFilesOptions with the logo\'s endpoint url', () => {
|
||||||
|
expect(comp.uploadFilesOptions.url).toEqual(logoEndpoint);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should initialize the uploadFilesOptions with a POST method', () => {
|
||||||
|
expect(comp.uploadFilesOptions.method).toEqual(RestRequestMethod.POST);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('and the dso contains a logo', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
initComponent(Object.assign(new Community(), {
|
||||||
|
id: 'community-id',
|
||||||
|
logo: observableOf(new RemoteData(false, false, true, null, {}))
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should initialize the uploadFilesOptions with the logo\'s endpoint url', () => {
|
||||||
|
expect(comp.uploadFilesOptions.url).toEqual(logoEndpoint);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should initialize the uploadFilesOptions with a PUT method', () => {
|
||||||
|
expect(comp.uploadFilesOptions.method).toEqual(RestRequestMethod.PUT);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('submit with logo marked for deletion', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
comp.markLogoForDeletion = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when dsoService.deleteLogo returns a successful response', () => {
|
||||||
|
const response = new RestResponse(true, 200, 'OK');
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(dsoService, 'deleteLogo').and.returnValue(observableOf(response));
|
||||||
|
comp.onSubmit();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a success notification', () => {
|
||||||
|
expect(notificationsService.success).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when dsoService.deleteLogo returns an error response', () => {
|
||||||
|
const response = new ErrorResponse(new RequestError('errorMessage'));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(dsoService, 'deleteLogo').and.returnValue(observableOf(response));
|
||||||
|
comp.onSubmit();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display an error notification', () => {
|
||||||
|
expect(notificationsService.error).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('deleteLogo', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
comp.deleteLogo();
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set markLogoForDeletion to true', () => {
|
||||||
|
expect(comp.markLogoForDeletion).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should mark the logo section with a danger alert', () => {
|
||||||
|
const logoSection = fixture.debugElement.query(By.css('#logo-section.alert-danger'));
|
||||||
|
expect(logoSection).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should hide the delete button', () => {
|
||||||
|
const button = fixture.debugElement.query(By.css('#logo-section .btn-danger'));
|
||||||
|
expect(button).not.toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show the undo button', () => {
|
||||||
|
const button = fixture.debugElement.query(By.css('#logo-section .btn-warning'));
|
||||||
|
expect(button).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('undoDeleteLogo', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
comp.markLogoForDeletion = true;
|
||||||
|
comp.undoDeleteLogo();
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set markLogoForDeletion to false', () => {
|
||||||
|
expect(comp.markLogoForDeletion).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should disable the danger alert on the logo section', () => {
|
||||||
|
const logoSection = fixture.debugElement.query(By.css('#logo-section.alert-danger'));
|
||||||
|
expect(logoSection).not.toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show the delete button', () => {
|
||||||
|
const button = fixture.debugElement.query(By.css('#logo-section .btn-danger'));
|
||||||
|
expect(button).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should hide the undo button', () => {
|
||||||
|
const button = fixture.debugElement.query(By.css('#logo-section .btn-warning'));
|
||||||
|
expect(button).not.toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function initComponent(dso: Community) {
|
||||||
|
fixture = TestBed.createComponent(ComColFormComponent);
|
||||||
|
comp = fixture.componentInstance;
|
||||||
|
comp.formModel = [];
|
||||||
|
comp.dso = dso;
|
||||||
|
(comp as any).type = Community.type;
|
||||||
|
comp.uploaderComponent = Object.assign({
|
||||||
|
uploader: {}
|
||||||
|
});
|
||||||
|
(comp as any).dsoService = dsoService;
|
||||||
|
fixture.detectChanges();
|
||||||
|
location = (comp as any).location;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
@@ -1,17 +1,30 @@
|
|||||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
|
||||||
import { Location } from '@angular/common';
|
import { Location } from '@angular/common';
|
||||||
import {
|
import { DynamicFormService, DynamicInputModel } from '@ng-dynamic-forms/core';
|
||||||
DynamicFormService,
|
|
||||||
DynamicInputModel
|
|
||||||
} from '@ng-dynamic-forms/core';
|
|
||||||
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 { MetadataMap, MetadataValue } from '../../../core/shared/metadata.models';
|
import { MetadataMap, MetadataValue } from '../../../core/shared/metadata.models';
|
||||||
import { ResourceType } from '../../../core/shared/resource-type';
|
import { ResourceType } from '../../../core/shared/resource-type';
|
||||||
import { isNotEmpty } from '../../empty.util';
|
import { hasValue, isNotEmpty } from '../../empty.util';
|
||||||
|
import { UploaderOptions } from '../../uploader/uploader-options.model';
|
||||||
|
import { NotificationsService } from '../../notifications/notifications.service';
|
||||||
|
import { ComColDataService } from '../../../core/data/comcol-data.service';
|
||||||
|
import { Subscription } from 'rxjs/internal/Subscription';
|
||||||
|
import { AuthService } from '../../../core/auth/auth.service';
|
||||||
import { Community } from '../../../core/shared/community.model';
|
import { Community } from '../../../core/shared/community.model';
|
||||||
|
import { Collection } from '../../../core/shared/collection.model';
|
||||||
|
import { UploaderComponent } from '../../uploader/uploader.component';
|
||||||
|
import { FileUploader } from 'ng2-file-upload';
|
||||||
|
import { ErrorResponse, RestResponse } from '../../../core/cache/response.models';
|
||||||
|
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
|
||||||
|
import { RemoteData } from '../../../core/data/remote-data';
|
||||||
|
import { Bitstream } from '../../../core/shared/bitstream.model';
|
||||||
|
import { combineLatest as observableCombineLatest } from 'rxjs';
|
||||||
|
import { RestRequestMethod } from '../../../core/data/rest-request-method';
|
||||||
|
import { RequestService } from '../../../core/data/request.service';
|
||||||
|
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A form for creating and editing Communities or Collections
|
* A form for creating and editing Communities or Collections
|
||||||
@@ -21,7 +34,13 @@ import { Community } from '../../../core/shared/community.model';
|
|||||||
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, OnDestroy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logo uploader component
|
||||||
|
*/
|
||||||
|
@ViewChild(UploaderComponent) uploaderComponent: UploaderComponent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DSpaceObject that the form represents
|
* DSpaceObject that the form represents
|
||||||
*/
|
*/
|
||||||
@@ -30,7 +49,7 @@ export class ComColFormComponent<T extends DSpaceObject> implements OnInit {
|
|||||||
/**
|
/**
|
||||||
* Type of DSpaceObject that the form represents
|
* Type of DSpaceObject that the form represents
|
||||||
*/
|
*/
|
||||||
protected type: ResourceType;
|
type: ResourceType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {string} Key prefix used to generate form labels
|
* @type {string} Key prefix used to generate form labels
|
||||||
@@ -53,14 +72,56 @@ export class ComColFormComponent<T extends DSpaceObject> implements OnInit {
|
|||||||
formGroup: FormGroup;
|
formGroup: FormGroup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emits DSO when the form is submitted
|
* The uploader configuration options
|
||||||
* @type {EventEmitter<any>}
|
* @type {UploaderOptions}
|
||||||
*/
|
*/
|
||||||
@Output() submitForm: EventEmitter<any> = new EventEmitter();
|
uploadFilesOptions: UploaderOptions = Object.assign(new UploaderOptions(), {
|
||||||
|
autoUpload: false
|
||||||
|
});
|
||||||
|
|
||||||
public constructor(private location: Location,
|
/**
|
||||||
private formService: DynamicFormService,
|
* Emits DSO and Uploader when the form is submitted
|
||||||
private translate: TranslateService) {
|
*/
|
||||||
|
@Output() submitForm: EventEmitter<{
|
||||||
|
dso: T,
|
||||||
|
uploader: FileUploader,
|
||||||
|
deleteLogo: boolean
|
||||||
|
}> = new EventEmitter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires an event when the logo has finished uploading (with or without errors) or was removed
|
||||||
|
*/
|
||||||
|
@Output() finish: EventEmitter<any> = new EventEmitter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Observable keeping track whether or not the uploader has finished initializing
|
||||||
|
* Used to start rendering the uploader component
|
||||||
|
*/
|
||||||
|
initializedUploaderOptions = new BehaviorSubject(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the logo marked to be deleted?
|
||||||
|
*/
|
||||||
|
markLogoForDeletion = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
|
protected subs: Subscription[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The service used to fetch from or send data to
|
||||||
|
*/
|
||||||
|
protected dsoService: ComColDataService<Community | Collection>;
|
||||||
|
|
||||||
|
public constructor(protected location: Location,
|
||||||
|
protected formService: DynamicFormService,
|
||||||
|
protected translate: TranslateService,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected authService: AuthService,
|
||||||
|
protected requestService: RequestService,
|
||||||
|
protected objectCache: ObjectCacheService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
@@ -76,12 +137,55 @@ export class ComColFormComponent<T extends DSpaceObject> implements OnInit {
|
|||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.updateFieldTranslations();
|
this.updateFieldTranslations();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (hasValue(this.dso.id)) {
|
||||||
|
this.subs.push(
|
||||||
|
observableCombineLatest(
|
||||||
|
this.dsoService.getLogoEndpoint(this.dso.id),
|
||||||
|
(this.dso as any).logo
|
||||||
|
).subscribe(([href, logoRD]: [string, RemoteData<Bitstream>]) => {
|
||||||
|
this.uploadFilesOptions.url = href;
|
||||||
|
this.uploadFilesOptions.authToken = this.authService.buildAuthHeader();
|
||||||
|
// If the object already contains a logo, send out a PUT request instead of POST for setting a new logo
|
||||||
|
if (hasValue(logoRD.payload)) {
|
||||||
|
this.uploadFilesOptions.method = RestRequestMethod.PUT;
|
||||||
|
}
|
||||||
|
this.initializedUploaderOptions.next(true);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Set a placeholder URL to not break the uploader component. This will be replaced once the object is created.
|
||||||
|
this.uploadFilesOptions.url = 'placeholder';
|
||||||
|
this.uploadFilesOptions.authToken = this.authService.buildAuthHeader();
|
||||||
|
this.initializedUploaderOptions.next(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks which new fields were added and sends the updated version of the DSO to the parent component
|
* Checks which new fields were added and sends the updated version of the DSO to the parent component
|
||||||
*/
|
*/
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
|
if (this.markLogoForDeletion && hasValue(this.dso.id)) {
|
||||||
|
this.dsoService.deleteLogo(this.dso).subscribe((response: RestResponse) => {
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
this.notificationsService.success(
|
||||||
|
this.translate.get(this.type.value + '.edit.logo.notifications.delete.success.title'),
|
||||||
|
this.translate.get(this.type.value + '.edit.logo.notifications.delete.success.content')
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const errorResponse = response as ErrorResponse;
|
||||||
|
this.notificationsService.error(
|
||||||
|
this.translate.get(this.type.value + '.edit.logo.notifications.delete.error.title'),
|
||||||
|
errorResponse.errorMessage
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(this.dso as any).logo = undefined;
|
||||||
|
this.uploadFilesOptions.method = RestRequestMethod.POST;
|
||||||
|
this.refreshCache();
|
||||||
|
this.finish.emit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const formMetadata = new Object() as MetadataMap;
|
const formMetadata = new Object() as MetadataMap;
|
||||||
this.formModel.forEach((fieldModel: DynamicInputModel) => {
|
this.formModel.forEach((fieldModel: DynamicInputModel) => {
|
||||||
const value: MetadataValue = {
|
const value: MetadataValue = {
|
||||||
@@ -102,7 +206,11 @@ export class ComColFormComponent<T extends DSpaceObject> implements OnInit {
|
|||||||
},
|
},
|
||||||
type: Community.type
|
type: Community.type
|
||||||
});
|
});
|
||||||
this.submitForm.emit(updatedDSO);
|
this.submitForm.emit({
|
||||||
|
dso: updatedDSO,
|
||||||
|
uploader: hasValue(this.uploaderComponent) ? this.uploaderComponent.uploader : undefined,
|
||||||
|
deleteLogo: this.markLogoForDeletion
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,7 +230,59 @@ export class ComColFormComponent<T extends DSpaceObject> implements OnInit {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark the logo to be deleted
|
||||||
|
* Send out a delete request to remove the logo from the community/collection and display notifications
|
||||||
|
*/
|
||||||
|
deleteLogo() {
|
||||||
|
this.markLogoForDeletion = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undo marking the logo to be deleted
|
||||||
|
*/
|
||||||
|
undoDeleteLogo() {
|
||||||
|
this.markLogoForDeletion = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh the object's cache to ensure the latest version
|
||||||
|
*/
|
||||||
|
private refreshCache() {
|
||||||
|
this.requestService.removeByHrefSubstring(this.dso.self);
|
||||||
|
this.objectCache.remove(this.dso.self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The request was successful, display a success notification
|
||||||
|
*/
|
||||||
|
public onCompleteItem() {
|
||||||
|
this.refreshCache();
|
||||||
|
this.notificationsService.success(null, this.translate.get(this.type.value + '.edit.logo.notifications.add.success'));
|
||||||
|
this.finish.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The request was unsuccessful, display an error notification
|
||||||
|
*/
|
||||||
|
public onUploadError() {
|
||||||
|
this.notificationsService.error(null, this.translate.get(this.type.value + '.edit.logo.notifications.add.error'));
|
||||||
|
this.finish.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel the form and return to the previous page
|
||||||
|
*/
|
||||||
onCancel() {
|
onCancel() {
|
||||||
this.location.back();
|
this.location.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsubscribe from open subscriptions
|
||||||
|
*/
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.subs
|
||||||
|
.filter((subscription) => hasValue(subscription))
|
||||||
|
.forEach((subscription) => subscription.unsubscribe());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,11 +11,13 @@ 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 { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||||
import { CreateComColPageComponent } from './create-comcol-page.component';
|
import { CreateComColPageComponent } from './create-comcol-page.component';
|
||||||
import { DataService } from '../../../core/data/data.service';
|
|
||||||
import {
|
import {
|
||||||
createFailedRemoteDataObject$,
|
createFailedRemoteDataObject$,
|
||||||
createSuccessfulRemoteDataObject$
|
createSuccessfulRemoteDataObject$
|
||||||
} from '../../testing/utils';
|
} from '../../testing/utils';
|
||||||
|
import { ComColDataService } from '../../../core/data/comcol-data.service';
|
||||||
|
import { NotificationsService } from '../../notifications/notifications.service';
|
||||||
|
import { NotificationsServiceStub } from '../../testing/notifications-service-stub';
|
||||||
|
|
||||||
describe('CreateComColPageComponent', () => {
|
describe('CreateComColPageComponent', () => {
|
||||||
let comp: CreateComColPageComponent<DSpaceObject>;
|
let comp: CreateComColPageComponent<DSpaceObject>;
|
||||||
@@ -31,6 +33,8 @@ describe('CreateComColPageComponent', () => {
|
|||||||
let routeServiceStub;
|
let routeServiceStub;
|
||||||
let routerStub;
|
let routerStub;
|
||||||
|
|
||||||
|
const logoEndpoint = 'rest/api/logo/endpoint';
|
||||||
|
|
||||||
function initializeVars() {
|
function initializeVars() {
|
||||||
community = Object.assign(new Community(), {
|
community = Object.assign(new Community(), {
|
||||||
uuid: 'a20da287-e174-466a-9926-f66b9300d347',
|
uuid: 'a20da287-e174-466a-9926-f66b9300d347',
|
||||||
@@ -56,8 +60,8 @@ describe('CreateComColPageComponent', () => {
|
|||||||
value: community.name
|
value: community.name
|
||||||
}]
|
}]
|
||||||
})),
|
})),
|
||||||
create: (com, uuid?) => createSuccessfulRemoteDataObject$(newCommunity)
|
create: (com, uuid?) => createSuccessfulRemoteDataObject$(newCommunity),
|
||||||
|
getLogoEndpoint: () => observableOf(logoEndpoint)
|
||||||
};
|
};
|
||||||
|
|
||||||
routeServiceStub = {
|
routeServiceStub = {
|
||||||
@@ -74,10 +78,11 @@ describe('CreateComColPageComponent', () => {
|
|||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: DataService, useValue: communityDataServiceStub },
|
{ provide: ComColDataService, 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 },
|
||||||
|
{ provide: NotificationsService, useValue: new NotificationsServiceStub() }
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
@@ -86,6 +91,7 @@ describe('CreateComColPageComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(CreateComColPageComponent);
|
fixture = TestBed.createComponent(CreateComColPageComponent);
|
||||||
comp = fixture.componentInstance;
|
comp = fixture.componentInstance;
|
||||||
|
(comp as any).type = Community.type;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
dsoDataService = (comp as any).dsoDataService;
|
dsoDataService = (comp as any).dsoDataService;
|
||||||
communityDataService = (comp as any).communityDataService;
|
communityDataService = (comp as any).communityDataService;
|
||||||
@@ -95,27 +101,86 @@ describe('CreateComColPageComponent', () => {
|
|||||||
|
|
||||||
describe('onSubmit', () => {
|
describe('onSubmit', () => {
|
||||||
let data;
|
let data;
|
||||||
beforeEach(() => {
|
|
||||||
data = Object.assign(new Community(), {
|
describe('with an empty queue in the uploader', () => {
|
||||||
metadata: [{
|
beforeEach(() => {
|
||||||
key: 'dc.title',
|
data = {
|
||||||
value: 'test'
|
dso: Object.assign(new Community(), {
|
||||||
}]
|
metadata: [{
|
||||||
|
key: 'dc.title',
|
||||||
|
value: 'test'
|
||||||
|
}]
|
||||||
|
}),
|
||||||
|
uploader: {
|
||||||
|
options: {
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
queue: [],
|
||||||
|
/* tslint:disable:no-empty */
|
||||||
|
uploadAll: () => {}
|
||||||
|
/* tslint:enable:no-empty */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
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(dsoDataService, 'create').and.returnValue(createFailedRemoteDataObject$(newCommunity));
|
||||||
|
comp.onSubmit(data);
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(router.navigate).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('should navigate when successful', () => {
|
|
||||||
spyOn(router, 'navigate');
|
|
||||||
comp.onSubmit(data);
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(router.navigate).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not navigate on failure', () => {
|
describe('with at least one item in the uploader\'s queue', () => {
|
||||||
spyOn(router, 'navigate');
|
beforeEach(() => {
|
||||||
spyOn(dsoDataService, 'create').and.returnValue(createFailedRemoteDataObject$(newCommunity));
|
data = {
|
||||||
comp.onSubmit(data);
|
dso: Object.assign(new Community(), {
|
||||||
fixture.detectChanges();
|
metadata: [{
|
||||||
expect(router.navigate).not.toHaveBeenCalled();
|
key: 'dc.title',
|
||||||
|
value: 'test'
|
||||||
|
}]
|
||||||
|
}),
|
||||||
|
uploader: {
|
||||||
|
options: {
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
queue: [
|
||||||
|
{}
|
||||||
|
],
|
||||||
|
/* tslint:disable:no-empty */
|
||||||
|
uploadAll: () => {}
|
||||||
|
/* tslint:enable:no-empty */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not navigate', () => {
|
||||||
|
spyOn(router, 'navigate');
|
||||||
|
comp.onSubmit(data);
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(router.navigate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the uploader\'s url to the logo\'s endpoint', () => {
|
||||||
|
comp.onSubmit(data);
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(data.uploader.options.url).toEqual(logoEndpoint);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call the uploader\'s uploadAll', () => {
|
||||||
|
spyOn(data.uploader, 'uploadAll');
|
||||||
|
comp.onSubmit(data);
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(data.uploader.uploadAll).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -3,13 +3,17 @@ 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 '../../../core/services/route.service';
|
import { RouteService } from '../../../core/services/route.service';
|
||||||
import { Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { RemoteData } from '../../../core/data/remote-data';
|
import { RemoteData } from '../../../core/data/remote-data';
|
||||||
import { isNotEmpty, isNotUndefined } from '../../empty.util';
|
import { hasValue, 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 { ComColDataService } from '../../../core/data/comcol-data.service';
|
||||||
|
import { NotificationsService } from '../../notifications/notifications.service';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { ResourceType } from '../../../core/shared/resource-type';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component representing the create page for communities and collections
|
* Component representing the create page for communities and collections
|
||||||
@@ -34,11 +38,23 @@ export class CreateComColPageComponent<TDomain extends DSpaceObject> implements
|
|||||||
*/
|
*/
|
||||||
public parentRD$: Observable<RemoteData<Community>>;
|
public parentRD$: Observable<RemoteData<Community>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The UUID of the newly created object
|
||||||
|
*/
|
||||||
|
private newUUID: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the dso
|
||||||
|
*/
|
||||||
|
protected type: ResourceType;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
protected dsoDataService: DataService<TDomain>,
|
protected dsoDataService: ComColDataService<TDomain>,
|
||||||
protected parentDataService: CommunityDataService,
|
protected parentDataService: CommunityDataService,
|
||||||
protected routeService: RouteService,
|
protected routeService: RouteService,
|
||||||
protected router: Router
|
protected router: Router,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected translate: TranslateService
|
||||||
) {
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -53,20 +69,40 @@ export class CreateComColPageComponent<TDomain extends DSpaceObject> implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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
|
* Creates a new DSO based on the submitted user data and navigates to the new object's home page
|
||||||
|
* @param event The event returned by the community/collection form. Contains the new dso and logo uploader
|
||||||
*/
|
*/
|
||||||
onSubmit(dso: TDomain) {
|
onSubmit(event) {
|
||||||
|
const dso = event.dso;
|
||||||
|
const uploader = event.uploader;
|
||||||
|
|
||||||
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)
|
||||||
.pipe(getSucceededRemoteData())
|
.pipe(getSucceededRemoteData())
|
||||||
.subscribe((dsoRD: RemoteData<TDomain>) => {
|
.subscribe((dsoRD: RemoteData<TDomain>) => {
|
||||||
if (isNotUndefined(dsoRD)) {
|
if (isNotUndefined(dsoRD)) {
|
||||||
const newUUID = dsoRD.payload.uuid;
|
this.newUUID = dsoRD.payload.uuid;
|
||||||
this.router.navigate([this.frontendURL + newUUID]);
|
if (uploader.queue.length > 0) {
|
||||||
|
this.dsoDataService.getLogoEndpoint(this.newUUID).pipe(take(1)).subscribe((href: string) => {
|
||||||
|
uploader.options.url = href;
|
||||||
|
uploader.uploadAll();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.navigateToNewPage();
|
||||||
|
}
|
||||||
|
this.notificationsService.success(null, this.translate.get(this.type.value + '.create.notifications.success'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to the page of the newly created object
|
||||||
|
*/
|
||||||
|
navigateToNewPage() {
|
||||||
|
if (hasValue(this.newUUID)) {
|
||||||
|
this.router.navigate([this.frontendURL + this.newUUID]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,10 @@ import { RouterTestingModule } from '@angular/router/testing';
|
|||||||
import { DataService } from '../../../../core/data/data.service';
|
import { DataService } from '../../../../core/data/data.service';
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { ComcolMetadataComponent } from './comcol-metadata.component';
|
import { ComcolMetadataComponent } from './comcol-metadata.component';
|
||||||
|
import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../../testing/utils';
|
||||||
|
import { ComColDataService } from '../../../../core/data/comcol-data.service';
|
||||||
|
import { NotificationsServiceStub } from '../../../testing/notifications-service-stub';
|
||||||
|
import { NotificationsService } from '../../../notifications/notifications.service';
|
||||||
|
|
||||||
describe('ComColMetadataComponent', () => {
|
describe('ComColMetadataComponent', () => {
|
||||||
let comp: ComcolMetadataComponent<DSpaceObject>;
|
let comp: ComcolMetadataComponent<DSpaceObject>;
|
||||||
@@ -25,6 +29,8 @@ describe('ComColMetadataComponent', () => {
|
|||||||
let routerStub;
|
let routerStub;
|
||||||
let routeStub;
|
let routeStub;
|
||||||
|
|
||||||
|
const logoEndpoint = 'rest/api/logo/endpoint';
|
||||||
|
|
||||||
function initializeVars() {
|
function initializeVars() {
|
||||||
community = Object.assign(new Community(), {
|
community = Object.assign(new Community(), {
|
||||||
uuid: 'a20da287-e174-466a-9926-f66b9300d347',
|
uuid: 'a20da287-e174-466a-9926-f66b9300d347',
|
||||||
@@ -43,8 +49,8 @@ describe('ComColMetadataComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
communityDataServiceStub = {
|
communityDataServiceStub = {
|
||||||
update: (com, uuid?) => observableOf(new RemoteData(false, false, true, undefined, newCommunity))
|
update: (com, uuid?) => createSuccessfulRemoteDataObject$(newCommunity),
|
||||||
|
getLogoEndpoint: () => observableOf(logoEndpoint)
|
||||||
};
|
};
|
||||||
|
|
||||||
routerStub = {
|
routerStub = {
|
||||||
@@ -53,7 +59,9 @@ describe('ComColMetadataComponent', () => {
|
|||||||
|
|
||||||
routeStub = {
|
routeStub = {
|
||||||
parent: {
|
parent: {
|
||||||
data: observableOf(community)
|
data: observableOf({
|
||||||
|
dso: new RemoteData(false, false, true, null, community)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -64,9 +72,10 @@ describe('ComColMetadataComponent', () => {
|
|||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: DataService, useValue: communityDataServiceStub },
|
{ provide: ComColDataService, useValue: communityDataServiceStub },
|
||||||
{ provide: Router, useValue: routerStub },
|
{ provide: Router, useValue: routerStub },
|
||||||
{ provide: ActivatedRoute, useValue: routeStub },
|
{ provide: ActivatedRoute, useValue: routeStub },
|
||||||
|
{ provide: NotificationsService, useValue: new NotificationsServiceStub() }
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
@@ -75,6 +84,7 @@ describe('ComColMetadataComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(ComcolMetadataComponent);
|
fixture = TestBed.createComponent(ComcolMetadataComponent);
|
||||||
comp = fixture.componentInstance;
|
comp = fixture.componentInstance;
|
||||||
|
(comp as any).type = Community.type;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
dsoDataService = (comp as any).dsoDataService;
|
dsoDataService = (comp as any).dsoDataService;
|
||||||
router = (comp as any).router;
|
router = (comp as any).router;
|
||||||
@@ -82,27 +92,98 @@ describe('ComColMetadataComponent', () => {
|
|||||||
|
|
||||||
describe('onSubmit', () => {
|
describe('onSubmit', () => {
|
||||||
let data;
|
let data;
|
||||||
beforeEach(() => {
|
|
||||||
data = Object.assign(new Community(), {
|
describe('with an empty queue in the uploader', () => {
|
||||||
metadata: [{
|
beforeEach(() => {
|
||||||
key: 'dc.title',
|
data = {
|
||||||
value: 'test'
|
dso: Object.assign(new Community(), {
|
||||||
}]
|
metadata: [{
|
||||||
|
key: 'dc.title',
|
||||||
|
value: 'test'
|
||||||
|
}]
|
||||||
|
}),
|
||||||
|
uploader: {
|
||||||
|
options: {
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
queue: [],
|
||||||
|
/* tslint:disable:no-empty */
|
||||||
|
uploadAll: () => {}
|
||||||
|
/* tslint:enable:no-empty */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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(dsoDataService, 'update').and.returnValue(createFailedRemoteDataObject$(newCommunity));
|
||||||
|
comp.onSubmit(data);
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(router.navigate).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('should navigate when successful', () => {
|
|
||||||
spyOn(router, 'navigate');
|
|
||||||
comp.onSubmit(data);
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(router.navigate).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not navigate on failure', () => {
|
describe('with at least one item in the uploader\'s queue', () => {
|
||||||
spyOn(router, 'navigate');
|
beforeEach(() => {
|
||||||
spyOn(dsoDataService, 'update').and.returnValue(observableOf(new RemoteData(true, true, false, undefined, newCommunity)));
|
data = {
|
||||||
comp.onSubmit(data);
|
dso: Object.assign(new Community(), {
|
||||||
fixture.detectChanges();
|
metadata: [{
|
||||||
expect(router.navigate).not.toHaveBeenCalled();
|
key: 'dc.title',
|
||||||
|
value: 'test'
|
||||||
|
}]
|
||||||
|
}),
|
||||||
|
uploader: {
|
||||||
|
options: {
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
queue: [
|
||||||
|
{}
|
||||||
|
],
|
||||||
|
/* tslint:disable:no-empty */
|
||||||
|
uploadAll: () => {}
|
||||||
|
/* tslint:enable:no-empty */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not navigate', () => {
|
||||||
|
spyOn(router, 'navigate');
|
||||||
|
comp.onSubmit(data);
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(router.navigate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the uploader\'s url to the logo\'s endpoint', () => {
|
||||||
|
comp.onSubmit(data);
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(data.uploader.options.url).toEqual(logoEndpoint);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call the uploader\'s uploadAll', () => {
|
||||||
|
spyOn(data.uploader, 'uploadAll');
|
||||||
|
comp.onSubmit(data);
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(data.uploader.uploadAll).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('navigateToHomePage', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(router, 'navigate');
|
||||||
|
comp.navigateToHomePage();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should navigate', () => {
|
||||||
|
expect(router.navigate).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@@ -3,10 +3,14 @@ import { DSpaceObject } from '../../../../core/shared/dspace-object.model';
|
|||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import { RemoteData } from '../../../../core/data/remote-data';
|
import { RemoteData } from '../../../../core/data/remote-data';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { first, map } from 'rxjs/operators';
|
import { first, map, take } from 'rxjs/operators';
|
||||||
import { getSucceededRemoteData } from '../../../../core/shared/operators';
|
import { getSucceededRemoteData } from '../../../../core/shared/operators';
|
||||||
import { isNotUndefined } from '../../../empty.util';
|
import { hasValue, isNotUndefined } from '../../../empty.util';
|
||||||
import { DataService } from '../../../../core/data/data.service';
|
import { DataService } from '../../../../core/data/data.service';
|
||||||
|
import { ResourceType } from '../../../../core/shared/resource-type';
|
||||||
|
import { ComColDataService } from '../../../../core/data/comcol-data.service';
|
||||||
|
import { NotificationsService } from '../../../notifications/notifications.service';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-comcol-metadata',
|
selector: 'ds-comcol-metadata',
|
||||||
@@ -17,13 +21,22 @@ export class ComcolMetadataComponent<TDomain extends DSpaceObject> implements On
|
|||||||
* Frontend endpoint for this type of DSO
|
* Frontend endpoint for this type of DSO
|
||||||
*/
|
*/
|
||||||
protected frontendURL: string;
|
protected frontendURL: string;
|
||||||
|
/**
|
||||||
|
* The initial DSO object
|
||||||
|
*/
|
||||||
public dsoRD$: Observable<RemoteData<TDomain>>;
|
public dsoRD$: Observable<RemoteData<TDomain>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the dso
|
||||||
|
*/
|
||||||
|
protected type: ResourceType;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
protected dsoDataService: DataService<TDomain>,
|
protected dsoDataService: ComColDataService<TDomain>,
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
protected route: ActivatedRoute
|
protected route: ActivatedRoute,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected translate: TranslateService
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,17 +45,41 @@ export class ComcolMetadataComponent<TDomain extends DSpaceObject> implements On
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {TDomain} dso The updated version of the DSO
|
|
||||||
* Updates an existing DSO based on the submitted user data and navigates to the edited object's home page
|
* Updates an existing DSO based on the submitted user data and navigates to the edited object's home page
|
||||||
|
* @param event The event returned by the community/collection form. Contains the new dso and logo uploader
|
||||||
*/
|
*/
|
||||||
onSubmit(dso: TDomain) {
|
onSubmit(event) {
|
||||||
|
const dso = event.dso;
|
||||||
|
const uploader = event.uploader;
|
||||||
|
const deleteLogo = event.deleteLogo;
|
||||||
|
|
||||||
this.dsoDataService.update(dso)
|
this.dsoDataService.update(dso)
|
||||||
.pipe(getSucceededRemoteData())
|
.pipe(getSucceededRemoteData())
|
||||||
.subscribe((dsoRD: RemoteData<TDomain>) => {
|
.subscribe((dsoRD: RemoteData<TDomain>) => {
|
||||||
if (isNotUndefined(dsoRD)) {
|
if (isNotUndefined(dsoRD)) {
|
||||||
const newUUID = dsoRD.payload.uuid;
|
const newUUID = dsoRD.payload.uuid;
|
||||||
this.router.navigate([this.frontendURL + newUUID]);
|
if (hasValue(uploader) && uploader.queue.length > 0) {
|
||||||
|
this.dsoDataService.getLogoEndpoint(newUUID).pipe(take(1)).subscribe((href: string) => {
|
||||||
|
uploader.options.url = href;
|
||||||
|
uploader.uploadAll();
|
||||||
|
});
|
||||||
|
} else if (!deleteLogo) {
|
||||||
|
this.router.navigate([this.frontendURL + newUUID]);
|
||||||
|
}
|
||||||
|
this.notificationsService.success(null, this.translate.get(this.type.value + '.edit.notifications.success'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to the home page of the object
|
||||||
|
*/
|
||||||
|
navigateToHomePage() {
|
||||||
|
this.dsoRD$.pipe(
|
||||||
|
getSucceededRemoteData(),
|
||||||
|
take(1)
|
||||||
|
).subscribe((dsoRD: RemoteData<TDomain>) => {
|
||||||
|
this.router.navigate([this.frontendURL + dsoRD.payload.id]);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
</div>
|
</div>
|
||||||
<a [routerLink]="getPageUrl((dsoRD$ | async)?.payload)" class="btn btn-outline-secondary">{{ type + '.edit.return' | translate }}</a>
|
<a *ngIf="!hideReturnButton" [routerLink]="getPageUrl((dsoRD$ | async)?.payload)" class="btn btn-outline-secondary">{{ type + '.edit.return' | translate }}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -39,7 +39,14 @@ describe('EditComColPageComponent', () => {
|
|||||||
dso: community
|
dso: community
|
||||||
}),
|
}),
|
||||||
routeConfig: {
|
routeConfig: {
|
||||||
children: []
|
children: [
|
||||||
|
{
|
||||||
|
path: 'mockUrl',
|
||||||
|
data: {
|
||||||
|
hideReturnButton: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
snapshot: {
|
snapshot: {
|
||||||
firstChild: {
|
firstChild: {
|
||||||
|
@@ -34,12 +34,19 @@ export class EditComColPageComponent<TDomain extends DSpaceObject> implements On
|
|||||||
*/
|
*/
|
||||||
public dsoRD$: Observable<RemoteData<TDomain>>;
|
public dsoRD$: Observable<RemoteData<TDomain>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide the default return button?
|
||||||
|
*/
|
||||||
|
public hideReturnButton: boolean;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
protected route: ActivatedRoute
|
protected route: ActivatedRoute
|
||||||
) {
|
) {
|
||||||
this.router.events.subscribe(() => {
|
this.router.events.subscribe(() => {
|
||||||
this.currentPage = this.route.snapshot.firstChild.routeConfig.path;
|
this.currentPage = this.route.snapshot.firstChild.routeConfig.path;
|
||||||
|
this.hideReturnButton = this.route.routeConfig.children
|
||||||
|
.find((child: any) => child.path === this.currentPage).data.hideReturnButton;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,4 +3,7 @@ export class AuthServiceMock {
|
|||||||
public checksAuthenticationToken() {
|
public checksAuthenticationToken() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
public buildAuthHeader() {
|
||||||
|
return 'auth-header';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -130,8 +130,6 @@ import { RoleDirective } from './roles/role.directive';
|
|||||||
import { UserMenuComponent } from './auth-nav-menu/user-menu/user-menu.component';
|
import { UserMenuComponent } from './auth-nav-menu/user-menu/user-menu.component';
|
||||||
import { ClaimedTaskActionsReturnToPoolComponent } from './mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component';
|
import { ClaimedTaskActionsReturnToPoolComponent } from './mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component';
|
||||||
import { ItemDetailPreviewFieldComponent } from './object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component';
|
import { ItemDetailPreviewFieldComponent } from './object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component';
|
||||||
import { AbstractTrackableComponent } from './trackable/abstract-trackable.component';
|
|
||||||
import { ComcolMetadataComponent } from './comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component';
|
|
||||||
import { DsDynamicLookupRelationModalComponent } from './form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component';
|
import { DsDynamicLookupRelationModalComponent } from './form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component';
|
||||||
import { SearchResultsComponent } from './search/search-results/search-results.component';
|
import { SearchResultsComponent } from './search/search-results/search-results.component';
|
||||||
import { SearchSidebarComponent } from './search/search-sidebar/search-sidebar.component';
|
import { SearchSidebarComponent } from './search/search-sidebar/search-sidebar.component';
|
||||||
@@ -156,6 +154,8 @@ import { DsDynamicDisabledComponent } from './form/builder/ds-dynamic-form-ui/mo
|
|||||||
import { DsDynamicLookupRelationSearchTabComponent } from './form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component';
|
import { DsDynamicLookupRelationSearchTabComponent } from './form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component';
|
||||||
import { DsDynamicLookupRelationSelectionTabComponent } from './form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component';
|
import { DsDynamicLookupRelationSelectionTabComponent } from './form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component';
|
||||||
import { PageSizeSelectorComponent } from './page-size-selector/page-size-selector.component';
|
import { PageSizeSelectorComponent } from './page-size-selector/page-size-selector.component';
|
||||||
|
import { AbstractTrackableComponent } from './trackable/abstract-trackable.component';
|
||||||
|
import { ComcolMetadataComponent } from './comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component';
|
||||||
import { ItemSelectComponent } from './object-select/item-select/item-select.component';
|
import { ItemSelectComponent } from './object-select/item-select/item-select.component';
|
||||||
import { CollectionSelectComponent } from './object-select/collection-select/collection-select.component';
|
import { CollectionSelectComponent } from './object-select/collection-select/collection-select.component';
|
||||||
import { FilterInputSuggestionsComponent } from './input-suggestions/filter-suggestions/filter-input-suggestions.component';
|
import { FilterInputSuggestionsComponent } from './input-suggestions/filter-suggestions/filter-input-suggestions.component';
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import { RestRequestMethod } from '../../core/data/rest-request-method';
|
||||||
|
|
||||||
export class UploaderOptions {
|
export class UploaderOptions {
|
||||||
/**
|
/**
|
||||||
@@ -9,5 +10,15 @@ export class UploaderOptions {
|
|||||||
|
|
||||||
disableMultipart = false;
|
disableMultipart = false;
|
||||||
|
|
||||||
itemAlias: string;
|
itemAlias: string = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically send out an upload request when adding files
|
||||||
|
*/
|
||||||
|
autoUpload = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The request method to use for the file upload request
|
||||||
|
*/
|
||||||
|
method: RestRequestMethod = RestRequestMethod.POST;
|
||||||
}
|
}
|
||||||
|
@@ -19,23 +19,24 @@
|
|||||||
(fileOver)="fileOverBase($event)"
|
(fileOver)="fileOverBase($event)"
|
||||||
class="well ds-base-drop-zone mt-1 mb-3 text-muted">
|
class="well ds-base-drop-zone mt-1 mb-3 text-muted">
|
||||||
<p class="text-center m-0 p-0 d-flex justify-content-center align-items-center" *ngIf="uploader?.queue?.length === 0">
|
<p class="text-center m-0 p-0 d-flex justify-content-center align-items-center" *ngIf="uploader?.queue?.length === 0">
|
||||||
<span><i class="fas fa-cloud-upload" aria-hidden="true"></i> {{dropMsg | translate}} {{'uploader.or' | translate}}
|
<span><i class="fas fa-cloud-upload" aria-hidden="true"></i> {{dropMsg | translate}} {{'uploader.or' | translate}}</span>
|
||||||
<label class="btn btn-link m-0 p-0">
|
<label class="btn btn-link m-0 p-0 ml-1">
|
||||||
<input class="d-none" type="file" ng2FileSelect [uploader]="uploader" multiple />
|
<input class="d-none" type="file" ng2FileSelect [uploader]="uploader" multiple />
|
||||||
{{'uploader.browse' | translate}}
|
{{'uploader.browse' | translate}}
|
||||||
</label>
|
</label>
|
||||||
</span>
|
|
||||||
</p>
|
</p>
|
||||||
<div *ngIf="(isOverBaseDropZone | async) || uploader?.queue?.length !== 0">
|
<div *ngIf="(isOverBaseDropZone | async) || uploader?.queue?.length !== 0">
|
||||||
<div class="m-1">
|
<div class="m-1">
|
||||||
<div class="upload-item-top">
|
<div class="upload-item-top">
|
||||||
<span class="filename">{{'uploader.queue-length' | translate}}: {{ uploader?.queue?.length }} | {{ uploader?.queue[0]?.file.name }}</span>
|
<span class="filename">
|
||||||
|
<span *ngIf="!uploader.options.disableMultipart">{{'uploader.queue-length' | translate}}: {{ uploader?.queue?.length }} | </span>{{ uploader?.queue[0]?.file.name }}
|
||||||
|
</span>
|
||||||
<div class="btn-group btn-group-sm float-right" role="group">
|
<div class="btn-group btn-group-sm float-right" role="group">
|
||||||
<button type="button" class="btn btn-danger" (click)="uploader.clearQueue()" [disabled]="!uploader.queue.length">
|
<button type="button" class="btn btn-danger" (click)="uploader.clearQueue()" [disabled]="!uploader.queue.length">
|
||||||
<i class="fas fa-trash" aria-hidden="true"></i>
|
<i class="fas fa-trash" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<span *ngIf="uploader.progress < 100" class="float-right mr-3">{{ uploader.progress }}%</span>
|
<span *ngIf="uploader.progress < 100 && !(uploader.progress === 0 && !uploader.options.autoUpload)" class="float-right mr-3">{{ uploader.progress }}%</span>
|
||||||
<span *ngIf="uploader.progress === 100" class="float-right mr-3">{{'uploader.processing' | translate}}...</span>
|
<span *ngIf="uploader.progress === 100" class="float-right mr-3">{{'uploader.processing' | translate}}...</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="ds-base-drop-zone-progress clearfix mt-2">
|
<div class="ds-base-drop-zone-progress clearfix mt-2">
|
||||||
|
@@ -64,12 +64,12 @@ describe('Chips component', () => {
|
|||||||
template: ``
|
template: ``
|
||||||
})
|
})
|
||||||
class TestComponent {
|
class TestComponent {
|
||||||
public uploadFilesOptions: UploaderOptions = {
|
public uploadFilesOptions: UploaderOptions = Object.assign(new UploaderOptions(), {
|
||||||
url: 'http://test',
|
url: 'http://test',
|
||||||
authToken: null,
|
authToken: null,
|
||||||
disableMultipart: false,
|
disableMultipart: false,
|
||||||
itemAlias: null
|
itemAlias: null
|
||||||
};
|
});
|
||||||
|
|
||||||
/* tslint:disable:no-empty */
|
/* tslint:disable:no-empty */
|
||||||
public onBeforeUpload = () => {
|
public onBeforeUpload = () => {
|
||||||
|
@@ -95,7 +95,8 @@ export class UploaderComponent {
|
|||||||
disableMultipart: this.uploadFilesOptions.disableMultipart,
|
disableMultipart: this.uploadFilesOptions.disableMultipart,
|
||||||
itemAlias: this.uploadFilesOptions.itemAlias,
|
itemAlias: this.uploadFilesOptions.itemAlias,
|
||||||
removeAfterUpload: true,
|
removeAfterUpload: true,
|
||||||
autoUpload: true
|
autoUpload: this.uploadFilesOptions.autoUpload,
|
||||||
|
method: this.uploadFilesOptions.method
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isUndefined(this.enableDragOverDocument)) {
|
if (isUndefined(this.enableDragOverDocument)) {
|
||||||
@@ -117,7 +118,10 @@ export class UploaderComponent {
|
|||||||
if (isUndefined(this.onBeforeUpload)) {
|
if (isUndefined(this.onBeforeUpload)) {
|
||||||
this.onBeforeUpload = () => {return};
|
this.onBeforeUpload = () => {return};
|
||||||
}
|
}
|
||||||
this.uploader.onBeforeUploadItem = () => {
|
this.uploader.onBeforeUploadItem = (item) => {
|
||||||
|
if (item.url !== this.uploader.options.url) {
|
||||||
|
item.url = this.uploader.options.url;
|
||||||
|
}
|
||||||
this.onBeforeUpload();
|
this.onBeforeUpload();
|
||||||
this.isOverDocumentDropZone = observableOf(false);
|
this.isOverDocumentDropZone = observableOf(false);
|
||||||
|
|
||||||
|
@@ -77,12 +77,7 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
|||||||
* The uploader configuration options
|
* The uploader configuration options
|
||||||
* @type {UploaderOptions}
|
* @type {UploaderOptions}
|
||||||
*/
|
*/
|
||||||
public uploadFilesOptions: UploaderOptions = {
|
public uploadFilesOptions: UploaderOptions = new UploaderOptions();
|
||||||
url: '',
|
|
||||||
authToken: null,
|
|
||||||
disableMultipart: false,
|
|
||||||
itemAlias: null
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A boolean representing if component is active
|
* A boolean representing if component is active
|
||||||
|
@@ -28,6 +28,7 @@ import { SubmissionJsonPatchOperationsServiceStub } from '../../../shared/testin
|
|||||||
import { SubmissionJsonPatchOperationsService } from '../../../core/submission/submission-json-patch-operations.service';
|
import { SubmissionJsonPatchOperationsService } from '../../../core/submission/submission-json-patch-operations.service';
|
||||||
import { SharedModule } from '../../../shared/shared.module';
|
import { SharedModule } from '../../../shared/shared.module';
|
||||||
import { createTestComponent } from '../../../shared/testing/utils';
|
import { createTestComponent } from '../../../shared/testing/utils';
|
||||||
|
import { UploaderOptions } from '../../../shared/uploader/uploader-options.model';
|
||||||
|
|
||||||
describe('SubmissionUploadFilesComponent Component', () => {
|
describe('SubmissionUploadFilesComponent Component', () => {
|
||||||
|
|
||||||
@@ -112,12 +113,12 @@ describe('SubmissionUploadFilesComponent Component', () => {
|
|||||||
comp.submissionId = submissionId;
|
comp.submissionId = submissionId;
|
||||||
comp.collectionId = collectionId;
|
comp.collectionId = collectionId;
|
||||||
comp.sectionId = 'upload';
|
comp.sectionId = 'upload';
|
||||||
comp.uploadFilesOptions = {
|
comp.uploadFilesOptions = Object.assign(new UploaderOptions(),{
|
||||||
url: '',
|
url: '',
|
||||||
authToken: null,
|
authToken: null,
|
||||||
disableMultipart: false,
|
disableMultipart: false,
|
||||||
itemAlias: null
|
itemAlias: null
|
||||||
};
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -208,11 +209,11 @@ class TestComponent {
|
|||||||
submissionId = mockSubmissionId;
|
submissionId = mockSubmissionId;
|
||||||
collectionId = mockSubmissionCollectionId;
|
collectionId = mockSubmissionCollectionId;
|
||||||
sectionId = 'upload';
|
sectionId = 'upload';
|
||||||
uploadFilesOptions = {
|
uploadFilesOptions = Object.assign(new UploaderOptions(), {
|
||||||
url: '',
|
url: '',
|
||||||
authToken: null,
|
authToken: null,
|
||||||
disableMultipart: false,
|
disableMultipart: false,
|
||||||
itemAlias: null
|
itemAlias: null
|
||||||
};
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user