mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
Merge remote-tracking branch 'remotes/origin/master' into upgrade-angular-7
# Conflicts: # src/app/+collection-page/collection-form/collection-form.component.ts # src/app/+community-page/community-form/community-form.component.ts # src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts
This commit is contained in:
@@ -244,6 +244,8 @@
|
||||
|
||||
"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.delete.cancel": "Cancel",
|
||||
@@ -302,6 +304,46 @@
|
||||
|
||||
|
||||
|
||||
"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.tabs.curate.head": "Curate",
|
||||
|
||||
"collection.edit.tabs.curate.title": "Collection Edit - Curate",
|
||||
|
||||
"collection.edit.tabs.metadata.head": "Edit Metadata",
|
||||
|
||||
"collection.edit.tabs.metadata.title": "Collection Edit - Metadata",
|
||||
|
||||
"collection.edit.tabs.roles.head": "Assign Roles",
|
||||
|
||||
"collection.edit.tabs.roles.title": "Collection Edit - Roles",
|
||||
|
||||
"collection.edit.tabs.source.head": "Content Source",
|
||||
|
||||
"collection.edit.tabs.source.title": "Collection Edit - Content Source",
|
||||
|
||||
|
||||
|
||||
"collection.form.abstract": "Short Description",
|
||||
|
||||
"collection.form.description": "Introductory text (HTML)",
|
||||
@@ -350,6 +392,8 @@
|
||||
|
||||
"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.delete.cancel": "Cancel",
|
||||
@@ -368,6 +412,44 @@
|
||||
|
||||
"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.tabs.curate.head": "Curate",
|
||||
|
||||
"community.edit.tabs.curate.title": "Community Edit - Curate",
|
||||
|
||||
"community.edit.tabs.metadata.head": "Edit Metadata",
|
||||
|
||||
"community.edit.tabs.metadata.title": "Community Edit - Metadata",
|
||||
|
||||
"community.edit.tabs.roles.head": "Assign Roles",
|
||||
|
||||
"community.edit.tabs.roles.title": "Community Edit - Roles",
|
||||
|
||||
|
||||
|
||||
"community.form.abstract": "Short Description",
|
||||
|
||||
"community.form.description": "Introductory text (HTML)",
|
||||
@@ -1771,7 +1853,7 @@
|
||||
|
||||
"uploader.drag-message": "Drag & Drop your files here",
|
||||
|
||||
"uploader.or": ", or",
|
||||
"uploader.or": ", or ",
|
||||
|
||||
"uploader.processing": "Processing",
|
||||
|
||||
|
@@ -1,7 +1,19 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { DynamicFormControlModel, DynamicInputModel, DynamicTextAreaModel } from '@ng-dynamic-forms/core';
|
||||
import {
|
||||
DynamicFormControlModel,
|
||||
DynamicFormService,
|
||||
DynamicInputModel,
|
||||
DynamicTextAreaModel
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { Collection } from '../../core/shared/collection.model';
|
||||
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 collections
|
||||
@@ -20,7 +32,7 @@ export class CollectionFormComponent extends ComColFormComponent<Collection> {
|
||||
/**
|
||||
* @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
|
||||
@@ -63,4 +75,15 @@ export class CollectionFormComponent extends ComColFormComponent<Collection> {
|
||||
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,7 +5,6 @@ import { CollectionPageComponent } from './collection-page.component';
|
||||
import { CollectionPageResolver } from './collection-page.resolver';
|
||||
import { CreateCollectionPageComponent } from './create-collection-page/create-collection-page.component';
|
||||
import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
|
||||
import { EditCollectionPageComponent } from './edit-collection-page/edit-collection-page.component';
|
||||
import { CreateCollectionPageGuard } from './create-collection-page/create-collection-page.guard';
|
||||
import { DeleteCollectionPageComponent } from './delete-collection-page/delete-collection-page.component';
|
||||
import { URLCombiner } from '../core/url-combiner/url-combiner';
|
||||
@@ -39,12 +38,8 @@ const COLLECTION_EDIT_PATH = ':id/edit';
|
||||
},
|
||||
{
|
||||
path: COLLECTION_EDIT_PATH,
|
||||
pathMatch: 'full',
|
||||
component: EditCollectionPageComponent,
|
||||
canActivate: [AuthenticatedGuard],
|
||||
resolve: {
|
||||
dso: CollectionPageResolver
|
||||
}
|
||||
loadChildren: './edit-collection-page/edit-collection-page.module#EditCollectionPageModule',
|
||||
canActivate: [AuthenticatedGuard]
|
||||
},
|
||||
{
|
||||
path: ':id/delete',
|
||||
|
@@ -5,15 +5,17 @@
|
||||
<div *ngIf="collectionRD?.payload as collection">
|
||||
<ds-view-tracker [object]="collection"></ds-view-tracker>
|
||||
<header class="comcol-header border-bottom mb-4 pb-4">
|
||||
<!-- Collection logo -->
|
||||
<ds-comcol-page-logo *ngIf="logoRD$"
|
||||
[logo]="(logoRD$ | async)?.payload" [alternateText]="'Collection Logo'">
|
||||
[alternateText]="'Collection Logo'">
|
||||
</ds-comcol-page-logo>
|
||||
<!-- Collection Name -->
|
||||
<!-- Collection Name -->
|
||||
<ds-comcol-page-header
|
||||
[name]="collection.name">
|
||||
</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 -->
|
||||
<ds-comcol-page-handle
|
||||
[content]="collection.handle"
|
||||
|
@@ -7,7 +7,6 @@ import { CollectionPageComponent } from './collection-page.component';
|
||||
import { CollectionPageRoutingModule } from './collection-page-routing.module';
|
||||
import { CreateCollectionPageComponent } from './create-collection-page/create-collection-page.component';
|
||||
import { CollectionFormComponent } from './collection-form/collection-form.component';
|
||||
import { EditCollectionPageComponent } from './edit-collection-page/edit-collection-page.component';
|
||||
import { DeleteCollectionPageComponent } from './delete-collection-page/delete-collection-page.component';
|
||||
import { CollectionItemMapperComponent } from './collection-item-mapper/collection-item-mapper.component';
|
||||
import { SearchService } from '../core/shared/search/search.service';
|
||||
@@ -23,11 +22,13 @@ import { StatisticsModule } from '../statistics/statistics.module';
|
||||
declarations: [
|
||||
CollectionPageComponent,
|
||||
CreateCollectionPageComponent,
|
||||
EditCollectionPageComponent,
|
||||
DeleteCollectionPageComponent,
|
||||
CollectionFormComponent,
|
||||
CollectionItemMapperComponent
|
||||
],
|
||||
exports: [
|
||||
CollectionFormComponent
|
||||
],
|
||||
providers: [
|
||||
SearchService,
|
||||
]
|
||||
|
@@ -4,5 +4,5 @@
|
||||
<h2 id="sub-header" class="border-bottom pb-2">{{'collection.create.sub-head' | translate:{ parent: (parentRD$| async)?.payload.name } }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<ds-collection-form (submitForm)="onSubmit($event)"></ds-collection-form>
|
||||
<ds-collection-form (submitForm)="onSubmit($event)" (finish)="navigateToNewPage()"></ds-collection-form>
|
||||
</div>
|
||||
|
@@ -10,6 +10,8 @@ import { CollectionDataService } from '../../core/data/collection-data.service';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||
import { CreateCollectionPageComponent } from './create-collection-page.component';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { NotificationsServiceStub } from '../../shared/testing/notifications-service-stub';
|
||||
|
||||
describe('CreateCollectionPageComponent', () => {
|
||||
let comp: CreateCollectionPageComponent;
|
||||
@@ -27,6 +29,7 @@ describe('CreateCollectionPageComponent', () => {
|
||||
},
|
||||
{ provide: RouteService, useValue: { getQueryParameterValue: () => observableOf('1234') } },
|
||||
{ provide: Router, useValue: {} },
|
||||
{ provide: NotificationsService, useValue: new NotificationsServiceStub() }
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents();
|
||||
|
@@ -5,6 +5,8 @@ import { Router } from '@angular/router';
|
||||
import { CreateComColPageComponent } from '../../shared/comcol-forms/create-comcol-page/create-comcol-page.component';
|
||||
import { Collection } from '../../core/shared/collection.model';
|
||||
import { CollectionDataService } from '../../core/data/collection-data.service';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
/**
|
||||
* 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> {
|
||||
protected frontendURL = '/collections/';
|
||||
protected type = Collection.type;
|
||||
|
||||
public constructor(
|
||||
protected communityDataService: CommunityDataService,
|
||||
protected collectionDataService: CollectionDataService,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
/**
|
||||
* Component for managing a collection's curation tasks
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-collection-curate',
|
||||
templateUrl: './collection-curate.component.html',
|
||||
})
|
||||
export class CollectionCurateComponent {
|
||||
/* TODO: Implement Collection Edit - Curate */
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
<ds-collection-form (submitForm)="onSubmit($event)"
|
||||
[dso]="(dsoRD$ | async)?.payload"
|
||||
(finish)="navigateToHomePage()"></ds-collection-form>
|
||||
<a class="btn btn-danger"
|
||||
[routerLink]="'/collections/' + (dsoRD$ | async)?.payload.uuid + '/delete'">{{'collection.edit.delete'
|
||||
| translate}}</a>
|
@@ -0,0 +1,42 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { SharedModule } from '../../../shared/shared.module';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { CollectionDataService } from '../../../core/data/collection-data.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { of as observableOf } from 'rxjs/internal/observable/of';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { CollectionMetadataComponent } from './collection-metadata.component';
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub';
|
||||
|
||||
describe('CollectionMetadataComponent', () => {
|
||||
let comp: CollectionMetadataComponent;
|
||||
let fixture: ComponentFixture<CollectionMetadataComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
||||
declarations: [CollectionMetadataComponent],
|
||||
providers: [
|
||||
{ provide: CollectionDataService, useValue: {} },
|
||||
{ provide: ActivatedRoute, useValue: { parent: { data: observableOf({ dso: { payload: {} } }) } } },
|
||||
{ provide: NotificationsService, useValue: new NotificationsServiceStub() }
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CollectionMetadataComponent);
|
||||
comp = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
describe('frontendURL', () => {
|
||||
it('should have the right frontendURL set', () => {
|
||||
expect((comp as any).frontendURL).toEqual('/collections/');
|
||||
})
|
||||
});
|
||||
});
|
@@ -0,0 +1,29 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ComcolMetadataComponent } from '../../../shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component';
|
||||
import { Collection } from '../../../core/shared/collection.model';
|
||||
import { CollectionDataService } from '../../../core/data/collection-data.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
/**
|
||||
* Component for editing a collection's metadata
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-collection-metadata',
|
||||
templateUrl: './collection-metadata.component.html',
|
||||
})
|
||||
export class CollectionMetadataComponent extends ComcolMetadataComponent<Collection> {
|
||||
protected frontendURL = '/collections/';
|
||||
protected type = Collection.type;
|
||||
|
||||
public constructor(
|
||||
protected collectionDataService: CollectionDataService,
|
||||
protected router: Router,
|
||||
protected route: ActivatedRoute,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected translate: TranslateService
|
||||
) {
|
||||
super(collectionDataService, router, route, notificationsService, translate);
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
/**
|
||||
* Component for managing a collection's roles
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-collection-roles',
|
||||
templateUrl: './collection-roles.component.html',
|
||||
})
|
||||
export class CollectionRolesComponent {
|
||||
/* TODO: Implement Collection Edit - Roles */
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
/**
|
||||
* Component for managing the content source of the collection
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-collection-source',
|
||||
templateUrl: './collection-source.component.html',
|
||||
})
|
||||
export class CollectionSourceComponent {
|
||||
/* TODO: Implement Collection Edit - Content Source */
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12 pb-4">
|
||||
<h2 id="header" class="border-bottom pb-2">{{ 'collection.edit.head' | translate }}</h2>
|
||||
<ds-collection-form (submitForm)="onSubmit($event)" [dso]="(dsoRD$ | async)?.payload"></ds-collection-form>
|
||||
<a class="btn btn-danger"
|
||||
[routerLink]="'/collections/' + (dsoRD$ | async)?.payload.uuid + '/delete'">{{'collection.edit.delete'
|
||||
| translate}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -1 +0,0 @@
|
||||
|
@@ -13,13 +13,29 @@ describe('EditCollectionPageComponent', () => {
|
||||
let comp: EditCollectionPageComponent;
|
||||
let fixture: ComponentFixture<EditCollectionPageComponent>;
|
||||
|
||||
const routeStub = {
|
||||
data: observableOf({
|
||||
dso: { payload: {} }
|
||||
}),
|
||||
routeConfig: {
|
||||
children: []
|
||||
},
|
||||
snapshot: {
|
||||
firstChild: {
|
||||
routeConfig: {
|
||||
path: 'mockUrl'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
||||
declarations: [EditCollectionPageComponent],
|
||||
providers: [
|
||||
{ provide: CollectionDataService, useValue: {} },
|
||||
{ provide: ActivatedRoute, useValue: { data: observableOf({ dso: { payload: {} } }) } },
|
||||
{ provide: ActivatedRoute, useValue: routeStub },
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents();
|
||||
@@ -31,9 +47,9 @@ describe('EditCollectionPageComponent', () => {
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
describe('frontendURL', () => {
|
||||
it('should have the right frontendURL set', () => {
|
||||
expect((comp as any).frontendURL).toEqual('/collections/');
|
||||
describe('type', () => {
|
||||
it('should have the right type set', () => {
|
||||
expect((comp as any).type).toEqual('collection');
|
||||
})
|
||||
});
|
||||
});
|
||||
|
@@ -2,24 +2,30 @@ import { Component } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { EditComColPageComponent } from '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component';
|
||||
import { Collection } from '../../core/shared/collection.model';
|
||||
import { CollectionDataService } from '../../core/data/collection-data.service';
|
||||
import { getCollectionPageRoute } from '../collection-page-routing.module';
|
||||
|
||||
/**
|
||||
* Component that represents the page where a user can edit an existing Collection
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-edit-collection',
|
||||
styleUrls: ['./edit-collection-page.component.scss'],
|
||||
templateUrl: './edit-collection-page.component.html'
|
||||
templateUrl: '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html'
|
||||
})
|
||||
export class EditCollectionPageComponent extends EditComColPageComponent<Collection> {
|
||||
protected frontendURL = '/collections/';
|
||||
type = 'collection';
|
||||
|
||||
public constructor(
|
||||
protected collectionDataService: CollectionDataService,
|
||||
protected router: Router,
|
||||
protected route: ActivatedRoute
|
||||
) {
|
||||
super(collectionDataService, router, route);
|
||||
super(router, route);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the collection page url
|
||||
* @param collection The collection for which the url is requested
|
||||
*/
|
||||
getPageUrl(collection: Collection): string {
|
||||
return getCollectionPageRoute(collection.id)
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,32 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { EditCollectionPageComponent } from './edit-collection-page.component';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
import { EditCollectionPageRoutingModule } from './edit-collection-page.routing.module';
|
||||
import { CollectionMetadataComponent } from './collection-metadata/collection-metadata.component';
|
||||
import { CollectionPageModule } from '../collection-page.module';
|
||||
import { CollectionRolesComponent } from './collection-roles/collection-roles.component';
|
||||
import { CollectionCurateComponent } from './collection-curate/collection-curate.component';
|
||||
import { CollectionSourceComponent } from './collection-source/collection-source.component';
|
||||
|
||||
/**
|
||||
* Module that contains all components related to the Edit Collection page administrator functionality
|
||||
*/
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
EditCollectionPageRoutingModule,
|
||||
CollectionPageModule
|
||||
],
|
||||
declarations: [
|
||||
EditCollectionPageComponent,
|
||||
CollectionMetadataComponent,
|
||||
CollectionRolesComponent,
|
||||
CollectionCurateComponent,
|
||||
CollectionSourceComponent
|
||||
]
|
||||
})
|
||||
export class EditCollectionPageModule {
|
||||
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { EditCollectionPageComponent } from './edit-collection-page.component';
|
||||
import { CollectionPageResolver } from '../collection-page.resolver';
|
||||
import { CollectionMetadataComponent } from './collection-metadata/collection-metadata.component';
|
||||
import { CollectionRolesComponent } from './collection-roles/collection-roles.component';
|
||||
import { CollectionSourceComponent } from './collection-source/collection-source.component';
|
||||
import { CollectionCurateComponent } from './collection-curate/collection-curate.component';
|
||||
|
||||
/**
|
||||
* Routing module that handles the routing for the Edit Collection page administrator functionality
|
||||
*/
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forChild([
|
||||
{
|
||||
path: '',
|
||||
component: EditCollectionPageComponent,
|
||||
resolve: {
|
||||
dso: CollectionPageResolver
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'metadata',
|
||||
pathMatch: 'full'
|
||||
},
|
||||
{
|
||||
path: 'metadata',
|
||||
component: CollectionMetadataComponent,
|
||||
data: {
|
||||
title: 'collection.edit.tabs.metadata.title',
|
||||
hideReturnButton: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'roles',
|
||||
component: CollectionRolesComponent,
|
||||
data: { title: 'collection.edit.tabs.roles.title' }
|
||||
},
|
||||
{
|
||||
path: 'source',
|
||||
component: CollectionSourceComponent,
|
||||
data: { title: 'collection.edit.tabs.source.title' }
|
||||
},
|
||||
{
|
||||
path: 'curate',
|
||||
component: CollectionCurateComponent,
|
||||
data: { title: 'collection.edit.tabs.curate.title' }
|
||||
}
|
||||
]
|
||||
}
|
||||
])
|
||||
],
|
||||
providers: [
|
||||
CollectionPageResolver,
|
||||
]
|
||||
})
|
||||
export class EditCollectionPageRoutingModule {
|
||||
|
||||
}
|
@@ -1,7 +1,19 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { DynamicFormControlModel, DynamicInputModel, DynamicTextAreaModel } from '@ng-dynamic-forms/core';
|
||||
import {
|
||||
DynamicFormControlModel,
|
||||
DynamicFormService,
|
||||
DynamicInputModel,
|
||||
DynamicTextAreaModel
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { Community } from '../../core/shared/community.model';
|
||||
import { ComColFormComponent } from '../../shared/comcol-forms/comcol-form/comcol-form.component';
|
||||
import { 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
|
||||
@@ -20,7 +32,7 @@ export class CommunityFormComponent extends ComColFormComponent<Community> {
|
||||
/**
|
||||
* @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
|
||||
@@ -55,4 +67,15 @@ export class CommunityFormComponent extends ComColFormComponent<Community> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@ import { CommunityPageComponent } from './community-page.component';
|
||||
import { CommunityPageResolver } from './community-page.resolver';
|
||||
import { CreateCommunityPageComponent } from './create-community-page/create-community-page.component';
|
||||
import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
|
||||
import { EditCommunityPageComponent } from './edit-community-page/edit-community-page.component';
|
||||
import { CreateCommunityPageGuard } from './create-community-page/create-community-page.guard';
|
||||
import { DeleteCommunityPageComponent } from './delete-community-page/delete-community-page.component';
|
||||
import { URLCombiner } from '../core/url-combiner/url-combiner';
|
||||
@@ -38,12 +37,8 @@ const COMMUNITY_EDIT_PATH = ':id/edit';
|
||||
},
|
||||
{
|
||||
path: COMMUNITY_EDIT_PATH,
|
||||
pathMatch: 'full',
|
||||
component: EditCommunityPageComponent,
|
||||
canActivate: [AuthenticatedGuard],
|
||||
resolve: {
|
||||
dso: CommunityPageResolver
|
||||
}
|
||||
loadChildren: './edit-community-page/edit-community-page.module#EditCommunityPageModule',
|
||||
canActivate: [AuthenticatedGuard]
|
||||
},
|
||||
{
|
||||
path: ':id/delete',
|
||||
|
@@ -3,12 +3,11 @@
|
||||
<div *ngIf="communityRD?.payload; let communityPayload">
|
||||
<ds-view-tracker [object]="communityPayload"></ds-view-tracker>
|
||||
<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 -->
|
||||
<ds-comcol-page-logo *ngIf="logoRD$" [logo]="(logoRD$ | async)?.payload" [alternateText]="'Community Logo'">
|
||||
</ds-comcol-page-logo>
|
||||
|
||||
<!-- Community name -->
|
||||
<ds-comcol-page-header [name]="communityPayload.name"></ds-comcol-page-header>
|
||||
<!-- Handle -->
|
||||
<ds-comcol-page-handle [content]="communityPayload.handle" [title]="'community.page.handle'">
|
||||
</ds-comcol-page-handle>
|
||||
|
@@ -9,7 +9,6 @@ import { CommunityPageRoutingModule } from './community-page-routing.module';
|
||||
import { CommunityPageSubCommunityListComponent } from './sub-community-list/community-page-sub-community-list.component';
|
||||
import { CreateCommunityPageComponent } from './create-community-page/create-community-page.component';
|
||||
import { CommunityFormComponent } from './community-form/community-form.component';
|
||||
import { EditCommunityPageComponent } from './edit-community-page/edit-community-page.component';
|
||||
import { DeleteCommunityPageComponent } from './delete-community-page/delete-community-page.component';
|
||||
import { StatisticsModule } from '../statistics/statistics.module';
|
||||
|
||||
@@ -25,9 +24,11 @@ import { StatisticsModule } from '../statistics/statistics.module';
|
||||
CommunityPageSubCollectionListComponent,
|
||||
CommunityPageSubCommunityListComponent,
|
||||
CreateCommunityPageComponent,
|
||||
EditCommunityPageComponent,
|
||||
DeleteCommunityPageComponent,
|
||||
CommunityFormComponent
|
||||
],
|
||||
exports: [
|
||||
CommunityFormComponent
|
||||
]
|
||||
})
|
||||
|
||||
|
@@ -7,5 +7,5 @@
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
<ds-community-form (submitForm)="onSubmit($event)"></ds-community-form>
|
||||
<ds-community-form (submitForm)="onSubmit($event)" (finish)="navigateToNewPage()"></ds-community-form>
|
||||
</div>
|
||||
|
@@ -10,6 +10,8 @@ import { CollectionDataService } from '../../core/data/collection-data.service';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||
import { CreateCommunityPageComponent } from './create-community-page.component';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { NotificationsServiceStub } from '../../shared/testing/notifications-service-stub';
|
||||
|
||||
describe('CreateCommunityPageComponent', () => {
|
||||
let comp: CreateCommunityPageComponent;
|
||||
@@ -23,6 +25,7 @@ describe('CreateCommunityPageComponent', () => {
|
||||
{ provide: CommunityDataService, useValue: { findById: () => observableOf({}) } },
|
||||
{ provide: RouteService, useValue: { getQueryParameterValue: () => observableOf('1234') } },
|
||||
{ provide: Router, useValue: {} },
|
||||
{ provide: NotificationsService, useValue: new NotificationsServiceStub() }
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents();
|
||||
|
@@ -4,6 +4,8 @@ import { CommunityDataService } from '../../core/data/community-data.service';
|
||||
import { RouteService } from '../../core/services/route.service';
|
||||
import { Router } from '@angular/router';
|
||||
import { CreateComColPageComponent } from '../../shared/comcol-forms/create-comcol-page/create-comcol-page.component';
|
||||
import { 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
|
||||
@@ -15,12 +17,15 @@ import { CreateComColPageComponent } from '../../shared/comcol-forms/create-comc
|
||||
})
|
||||
export class CreateCommunityPageComponent extends CreateComColPageComponent<Community> {
|
||||
protected frontendURL = '/communities/';
|
||||
protected type = Community.type;
|
||||
|
||||
public constructor(
|
||||
protected communityDataService: CommunityDataService,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
/**
|
||||
* Component for managing a community's curation tasks
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-community-curate',
|
||||
templateUrl: './community-curate.component.html',
|
||||
})
|
||||
export class CommunityCurateComponent {
|
||||
/* TODO: Implement Community Edit - Curate */
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
<ds-community-form (submitForm)="onSubmit($event)"
|
||||
[dso]="(dsoRD$ | async)?.payload"
|
||||
(finish)="navigateToHomePage()"></ds-community-form>
|
||||
<a class="btn btn-danger"
|
||||
[routerLink]="'/communities/' + (dsoRD$ | async)?.payload.uuid + '/delete'">{{'community.edit.delete'
|
||||
| translate}}</a>
|
@@ -0,0 +1,42 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { SharedModule } from '../../../shared/shared.module';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { of as observableOf } from 'rxjs/internal/observable/of';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { CommunityMetadataComponent } from './community-metadata.component';
|
||||
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', () => {
|
||||
let comp: CommunityMetadataComponent;
|
||||
let fixture: ComponentFixture<CommunityMetadataComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
||||
declarations: [CommunityMetadataComponent],
|
||||
providers: [
|
||||
{ provide: CommunityDataService, useValue: {} },
|
||||
{ provide: ActivatedRoute, useValue: { parent: { data: observableOf({ dso: { payload: {} } }) } } },
|
||||
{ provide: NotificationsService, useValue: new NotificationsServiceStub() }
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CommunityMetadataComponent);
|
||||
comp = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
describe('frontendURL', () => {
|
||||
it('should have the right frontendURL set', () => {
|
||||
expect((comp as any).frontendURL).toEqual('/communities/');
|
||||
})
|
||||
});
|
||||
});
|
@@ -0,0 +1,29 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ComcolMetadataComponent } from '../../../shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Community } from '../../../core/shared/community.model';
|
||||
import { CommunityDataService } from '../../../core/data/community-data.service';
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
/**
|
||||
* Component for editing a community's metadata
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-community-metadata',
|
||||
templateUrl: './community-metadata.component.html',
|
||||
})
|
||||
export class CommunityMetadataComponent extends ComcolMetadataComponent<Community> {
|
||||
protected frontendURL = '/communities/';
|
||||
protected type = Community.type;
|
||||
|
||||
public constructor(
|
||||
protected communityDataService: CommunityDataService,
|
||||
protected router: Router,
|
||||
protected route: ActivatedRoute,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected translate: TranslateService
|
||||
) {
|
||||
super(communityDataService, router, route, notificationsService, translate);
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
/**
|
||||
* Component for managing a community's roles
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-community-roles',
|
||||
templateUrl: './community-roles.component.html',
|
||||
})
|
||||
export class CommunityRolesComponent {
|
||||
/* TODO: Implement Community Edit - Roles */
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12 pb-4">
|
||||
<h2 id="header" class="border-bottom pb-2">{{ 'community.edit.head' | translate }}</h2>
|
||||
<ds-community-form (submitForm)="onSubmit($event)"
|
||||
[dso]="(dsoRD$ | async)?.payload"></ds-community-form>
|
||||
<a class="btn btn-danger"
|
||||
[routerLink]="'/communities/' + (dsoRD$ | async)?.payload.uuid + '/delete'">{{'community.edit.delete'
|
||||
| translate}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -1 +0,0 @@
|
||||
|
@@ -13,13 +13,29 @@ describe('EditCommunityPageComponent', () => {
|
||||
let comp: EditCommunityPageComponent;
|
||||
let fixture: ComponentFixture<EditCommunityPageComponent>;
|
||||
|
||||
const routeStub = {
|
||||
data: observableOf({
|
||||
dso: { payload: {} }
|
||||
}),
|
||||
routeConfig: {
|
||||
children: []
|
||||
},
|
||||
snapshot: {
|
||||
firstChild: {
|
||||
routeConfig: {
|
||||
path: 'mockUrl'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
||||
declarations: [EditCommunityPageComponent],
|
||||
providers: [
|
||||
{ provide: CommunityDataService, useValue: {} },
|
||||
{ provide: ActivatedRoute, useValue: { data: observableOf({ dso: { payload: {} } }) } },
|
||||
{ provide: ActivatedRoute, useValue: routeStub },
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents();
|
||||
@@ -31,9 +47,9 @@ describe('EditCommunityPageComponent', () => {
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
describe('frontendURL', () => {
|
||||
it('should have the right frontendURL set', () => {
|
||||
expect((comp as any).frontendURL).toEqual('/communities/');
|
||||
describe('type', () => {
|
||||
it('should have the right type set', () => {
|
||||
expect((comp as any).type).toEqual('community');
|
||||
})
|
||||
});
|
||||
});
|
||||
|
@@ -1,25 +1,31 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Community } from '../../core/shared/community.model';
|
||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { EditComColPageComponent } from '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component';
|
||||
import { getCommunityPageRoute } from '../community-page-routing.module';
|
||||
|
||||
/**
|
||||
* Component that represents the page where a user can edit an existing Community
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-edit-community',
|
||||
styleUrls: ['./edit-community-page.component.scss'],
|
||||
templateUrl: './edit-community-page.component.html'
|
||||
templateUrl: '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html'
|
||||
})
|
||||
export class EditCommunityPageComponent extends EditComColPageComponent<Community> {
|
||||
protected frontendURL = '/communities/';
|
||||
type = 'community';
|
||||
|
||||
public constructor(
|
||||
protected communityDataService: CommunityDataService,
|
||||
protected router: Router,
|
||||
protected route: ActivatedRoute
|
||||
) {
|
||||
super(communityDataService, router, route);
|
||||
super(router, route);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the community page url
|
||||
* @param community The community for which the url is requested
|
||||
*/
|
||||
getPageUrl(community: Community): string {
|
||||
return getCommunityPageRoute(community.id)
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,30 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
import { EditCommunityPageRoutingModule } from './edit-community-page.routing.module';
|
||||
import { CommunityPageModule } from '../community-page.module';
|
||||
import { EditCommunityPageComponent } from './edit-community-page.component';
|
||||
import { CommunityCurateComponent } from './community-curate/community-curate.component';
|
||||
import { CommunityMetadataComponent } from './community-metadata/community-metadata.component';
|
||||
import { CommunityRolesComponent } from './community-roles/community-roles.component';
|
||||
|
||||
/**
|
||||
* Module that contains all components related to the Edit Community page administrator functionality
|
||||
*/
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
EditCommunityPageRoutingModule,
|
||||
CommunityPageModule
|
||||
],
|
||||
declarations: [
|
||||
EditCommunityPageComponent,
|
||||
CommunityCurateComponent,
|
||||
CommunityMetadataComponent,
|
||||
CommunityRolesComponent
|
||||
]
|
||||
})
|
||||
export class EditCommunityPageModule {
|
||||
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
import { CommunityPageResolver } from '../community-page.resolver';
|
||||
import { EditCommunityPageComponent } from './edit-community-page.component';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommunityMetadataComponent } from './community-metadata/community-metadata.component';
|
||||
import { CommunityRolesComponent } from './community-roles/community-roles.component';
|
||||
import { CommunityCurateComponent } from './community-curate/community-curate.component';
|
||||
|
||||
/**
|
||||
* Routing module that handles the routing for the Edit Community page administrator functionality
|
||||
*/
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forChild([
|
||||
{
|
||||
path: '',
|
||||
component: EditCommunityPageComponent,
|
||||
resolve: {
|
||||
dso: CommunityPageResolver
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'metadata',
|
||||
pathMatch: 'full'
|
||||
},
|
||||
{
|
||||
path: 'metadata',
|
||||
component: CommunityMetadataComponent,
|
||||
data: {
|
||||
title: 'community.edit.tabs.metadata.title',
|
||||
hideReturnButton: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'roles',
|
||||
component: CommunityRolesComponent,
|
||||
data: { title: 'community.edit.tabs.roles.title' }
|
||||
},
|
||||
{
|
||||
path: 'curate',
|
||||
component: CommunityCurateComponent,
|
||||
data: { title: 'community.edit.tabs.curate.title' }
|
||||
}
|
||||
]
|
||||
}
|
||||
])
|
||||
],
|
||||
providers: [
|
||||
CommunityPageResolver,
|
||||
]
|
||||
})
|
||||
export class EditCommunityPageRoutingModule {
|
||||
|
||||
}
|
@@ -33,12 +33,7 @@ export class MyDSpaceNewSubmissionComponent implements OnDestroy, OnInit {
|
||||
/**
|
||||
* The UploaderOptions object
|
||||
*/
|
||||
public uploadFilesOptions: UploaderOptions = {
|
||||
url: '',
|
||||
authToken: null,
|
||||
disableMultipart: false,
|
||||
itemAlias: null
|
||||
};
|
||||
public uploadFilesOptions: UploaderOptions = new UploaderOptions();
|
||||
|
||||
/**
|
||||
* Subscription to unsubscribe from
|
||||
|
@@ -1,32 +1,41 @@
|
||||
import {
|
||||
distinctUntilChanged,
|
||||
filter, first,
|
||||
map,
|
||||
mergeMap,
|
||||
share,
|
||||
switchMap,
|
||||
filter, first,map, mergeMap, share, switchMap,
|
||||
take,
|
||||
tap
|
||||
} 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 { NormalizedCommunity } from '../cache/models/normalized-community.model';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { CommunityDataService } from './community-data.service';
|
||||
|
||||
import { DataService } from './data.service';
|
||||
import { DeleteRequest, FindListOptions, FindByIDRequest, RestRequest } from './request.models';
|
||||
import { PaginatedList } from './paginated-list';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { FindListOptions, FindByIDRequest } from './request.models';
|
||||
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 { 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> {
|
||||
protected abstract cds: CommunityDataService;
|
||||
protected abstract objectCache: ObjectCacheService;
|
||||
protected abstract halService: HALEndpointService;
|
||||
|
||||
/**
|
||||
* Linkpath of endpoint to delete the logo
|
||||
*/
|
||||
protected logoDeleteLinkpath = 'bitstreams';
|
||||
|
||||
/**
|
||||
* Get the scoped endpoint URL by fetching the object with
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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"
|
||||
[formId]="'comcol-form-id'"
|
||||
[formModel]="formModel" (submitForm)="onSubmit()" (cancel)="onCancel()"></ds-form>
|
||||
|
@@ -9,6 +9,19 @@ import { Community } from '../../../core/shared/community.model';
|
||||
import { ComColFormComponent } from './comcol-form.component';
|
||||
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||
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', () => {
|
||||
let comp: ComColFormComponent<DSpaceObject>;
|
||||
@@ -47,71 +60,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 */
|
||||
const locationStub = jasmine.createSpyObj('location', ['back']);
|
||||
/* tslint:enable:no-empty */
|
||||
|
||||
const requestServiceStub = jasmine.createSpyObj({
|
||||
removeByHrefSubstring: {}
|
||||
});
|
||||
const objectCacheStub = jasmine.createSpyObj({
|
||||
remove: {}
|
||||
});
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), RouterTestingModule],
|
||||
declarations: [ComColFormComponent],
|
||||
declarations: [ComColFormComponent, VarDirective],
|
||||
providers: [
|
||||
{ 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]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ComColFormComponent);
|
||||
comp = fixture.componentInstance;
|
||||
comp.formModel = [];
|
||||
comp.dso = new Community();
|
||||
fixture.detectChanges();
|
||||
location = (comp as any).location;
|
||||
});
|
||||
|
||||
describe('onSubmit', () => {
|
||||
describe('when the dso doesn\'t contain an ID (newly created)', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(comp.submitForm, 'emit');
|
||||
comp.formModel = formModel;
|
||||
initComponent(new Community());
|
||||
});
|
||||
|
||||
it('should emit the new version of the community', () => {
|
||||
comp.dso = Object.assign(
|
||||
new Community(),
|
||||
{
|
||||
metadata: {
|
||||
...titleMD,
|
||||
...randomMD
|
||||
}
|
||||
}
|
||||
);
|
||||
it('should initialize the uploadFilesOptions with a placeholder url', () => {
|
||||
expect(comp.uploadFilesOptions.url.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
comp.onSubmit();
|
||||
describe('onSubmit', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(comp.submitForm, 'emit');
|
||||
comp.formModel = formModel;
|
||||
});
|
||||
|
||||
expect(comp.submitForm.emit).toHaveBeenCalledWith(
|
||||
Object.assign(
|
||||
{},
|
||||
it('should emit the new version of the community', () => {
|
||||
comp.dso = Object.assign(
|
||||
new Community(),
|
||||
{
|
||||
metadata: {
|
||||
...newTitleMD,
|
||||
...randomMD,
|
||||
...abstractMD
|
||||
},
|
||||
type: Community.type
|
||||
},
|
||||
)
|
||||
);
|
||||
})
|
||||
});
|
||||
...titleMD,
|
||||
...randomMD
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
describe('onCancel', () => {
|
||||
it('should call the back method on the Location service', () => {
|
||||
comp.onSubmit();
|
||||
|
||||
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();
|
||||
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,4 +1,4 @@
|
||||
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 {
|
||||
DynamicFormControlModel,
|
||||
@@ -11,8 +11,24 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||
import { MetadataMap, MetadataValue } from '../../../core/shared/metadata.models';
|
||||
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 { 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
|
||||
@@ -22,7 +38,13 @@ import { Community } from '../../../core/shared/community.model';
|
||||
styleUrls: ['./comcol-form.component.scss'],
|
||||
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
|
||||
*/
|
||||
@@ -31,7 +53,7 @@ export class ComColFormComponent<T extends DSpaceObject> implements OnInit {
|
||||
/**
|
||||
* Type of DSpaceObject that the form represents
|
||||
*/
|
||||
protected type: ResourceType;
|
||||
type: ResourceType;
|
||||
|
||||
/**
|
||||
* @type {string} Key prefix used to generate form labels
|
||||
@@ -54,14 +76,56 @@ export class ComColFormComponent<T extends DSpaceObject> implements OnInit {
|
||||
formGroup: FormGroup;
|
||||
|
||||
/**
|
||||
* Emits DSO when the form is submitted
|
||||
* @type {EventEmitter<any>}
|
||||
* The uploader configuration options
|
||||
* @type {UploaderOptions}
|
||||
*/
|
||||
@Output() submitForm: EventEmitter<any> = new EventEmitter();
|
||||
uploadFilesOptions: UploaderOptions = Object.assign(new UploaderOptions(), {
|
||||
autoUpload: false
|
||||
});
|
||||
|
||||
public constructor(private location: Location,
|
||||
private formService: DynamicFormService,
|
||||
private translate: TranslateService) {
|
||||
/**
|
||||
* Emits DSO and Uploader when the form is submitted
|
||||
*/
|
||||
@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 {
|
||||
@@ -77,13 +141,56 @@ export class ComColFormComponent<T extends DSpaceObject> implements OnInit {
|
||||
.subscribe(() => {
|
||||
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
|
||||
*/
|
||||
onSubmit() {
|
||||
const formMetadata = {} as MetadataMap;
|
||||
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 = {} as MetadataMap;
|
||||
this.formModel.forEach((fieldModel: DynamicInputModel) => {
|
||||
const value: MetadataValue = {
|
||||
value: fieldModel.value as string,
|
||||
@@ -103,7 +210,11 @@ export class ComColFormComponent<T extends DSpaceObject> implements OnInit {
|
||||
},
|
||||
type: Community.type
|
||||
});
|
||||
this.submitForm.emit(updatedDSO);
|
||||
this.submitForm.emit({
|
||||
dso: updatedDSO,
|
||||
uploader: hasValue(this.uploaderComponent) ? this.uploaderComponent.uploader : undefined,
|
||||
deleteLogo: this.markLogoForDeletion
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,7 +234,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() {
|
||||
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 { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||
import { CreateComColPageComponent } from './create-comcol-page.component';
|
||||
import { DataService } from '../../../core/data/data.service';
|
||||
import {
|
||||
createFailedRemoteDataObject$,
|
||||
createSuccessfulRemoteDataObject$
|
||||
} 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', () => {
|
||||
let comp: CreateComColPageComponent<DSpaceObject>;
|
||||
@@ -31,6 +33,8 @@ describe('CreateComColPageComponent', () => {
|
||||
let routeServiceStub;
|
||||
let routerStub;
|
||||
|
||||
const logoEndpoint = 'rest/api/logo/endpoint';
|
||||
|
||||
function initializeVars() {
|
||||
community = Object.assign(new Community(), {
|
||||
uuid: 'a20da287-e174-466a-9926-f66b9300d347',
|
||||
@@ -56,8 +60,8 @@ describe('CreateComColPageComponent', () => {
|
||||
value: community.name
|
||||
}]
|
||||
})),
|
||||
create: (com, uuid?) => createSuccessfulRemoteDataObject$(newCommunity)
|
||||
|
||||
create: (com, uuid?) => createSuccessfulRemoteDataObject$(newCommunity),
|
||||
getLogoEndpoint: () => observableOf(logoEndpoint)
|
||||
};
|
||||
|
||||
routeServiceStub = {
|
||||
@@ -74,10 +78,11 @@ describe('CreateComColPageComponent', () => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
||||
providers: [
|
||||
{ provide: DataService, useValue: communityDataServiceStub },
|
||||
{ provide: ComColDataService, useValue: communityDataServiceStub },
|
||||
{ provide: CommunityDataService, useValue: communityDataServiceStub },
|
||||
{ provide: RouteService, useValue: routeServiceStub },
|
||||
{ provide: Router, useValue: routerStub },
|
||||
{ provide: NotificationsService, useValue: new NotificationsServiceStub() }
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents();
|
||||
@@ -86,6 +91,7 @@ describe('CreateComColPageComponent', () => {
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CreateComColPageComponent);
|
||||
comp = fixture.componentInstance;
|
||||
(comp as any).type = Community.type;
|
||||
fixture.detectChanges();
|
||||
dsoDataService = (comp as any).dsoDataService;
|
||||
communityDataService = (comp as any).communityDataService;
|
||||
@@ -95,27 +101,86 @@ describe('CreateComColPageComponent', () => {
|
||||
|
||||
describe('onSubmit', () => {
|
||||
let data;
|
||||
beforeEach(() => {
|
||||
data = Object.assign(new Community(), {
|
||||
metadata: [{
|
||||
key: 'dc.title',
|
||||
value: 'test'
|
||||
}]
|
||||
|
||||
describe('with an empty queue in the uploader', () => {
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
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', () => {
|
||||
spyOn(router, 'navigate');
|
||||
spyOn(dsoDataService, 'create').and.returnValue(createFailedRemoteDataObject$(newCommunity));
|
||||
comp.onSubmit(data);
|
||||
fixture.detectChanges();
|
||||
expect(router.navigate).not.toHaveBeenCalled();
|
||||
describe('with at least one item in the uploader\'s queue', () => {
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
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 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 { Observable } from 'rxjs';
|
||||
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 { isNotEmpty, isNotUndefined } from '../../empty.util';
|
||||
import { hasValue, isNotEmpty, isNotUndefined } from '../../empty.util';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { getSucceededRemoteData } from '../../../core/shared/operators';
|
||||
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||
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
|
||||
@@ -34,11 +38,23 @@ export class CreateComColPageComponent<TDomain extends DSpaceObject> implements
|
||||
*/
|
||||
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(
|
||||
protected dsoDataService: DataService<TDomain>,
|
||||
protected dsoDataService: ComColDataService<TDomain>,
|
||||
protected parentDataService: CommunityDataService,
|
||||
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
|
||||
* @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.dsoDataService.create(dso, uuid)
|
||||
.pipe(getSucceededRemoteData())
|
||||
.subscribe((dsoRD: RemoteData<TDomain>) => {
|
||||
if (isNotUndefined(dsoRD)) {
|
||||
const newUUID = dsoRD.payload.uuid;
|
||||
this.router.navigate([this.frontendURL + newUUID]);
|
||||
this.newUUID = dsoRD.payload.uuid;
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,189 @@
|
||||
import { DSpaceObject } from '../../../../core/shared/dspace-object.model';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { CommunityDataService } from '../../../../core/data/community-data.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Community } from '../../../../core/shared/community.model';
|
||||
import { of as observableOf } from 'rxjs/internal/observable/of';
|
||||
import { RemoteData } from '../../../../core/data/remote-data';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { SharedModule } from '../../../shared.module';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { DataService } from '../../../../core/data/data.service';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
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', () => {
|
||||
let comp: ComcolMetadataComponent<DSpaceObject>;
|
||||
let fixture: ComponentFixture<ComcolMetadataComponent<DSpaceObject>>;
|
||||
let dsoDataService: CommunityDataService;
|
||||
let router: Router;
|
||||
|
||||
let community;
|
||||
let newCommunity;
|
||||
let communityDataServiceStub;
|
||||
let routerStub;
|
||||
let routeStub;
|
||||
|
||||
const logoEndpoint = 'rest/api/logo/endpoint';
|
||||
|
||||
function initializeVars() {
|
||||
community = Object.assign(new Community(), {
|
||||
uuid: 'a20da287-e174-466a-9926-f66b9300d347',
|
||||
metadata: [{
|
||||
key: 'dc.title',
|
||||
value: 'test community'
|
||||
}]
|
||||
});
|
||||
|
||||
newCommunity = Object.assign(new Community(), {
|
||||
uuid: '1ff59938-a69a-4e62-b9a4-718569c55d48',
|
||||
metadata: [{
|
||||
key: 'dc.title',
|
||||
value: 'new community'
|
||||
}]
|
||||
});
|
||||
|
||||
communityDataServiceStub = {
|
||||
update: (com, uuid?) => createSuccessfulRemoteDataObject$(newCommunity),
|
||||
getLogoEndpoint: () => observableOf(logoEndpoint)
|
||||
};
|
||||
|
||||
routerStub = {
|
||||
navigate: (commands) => commands
|
||||
};
|
||||
|
||||
routeStub = {
|
||||
parent: {
|
||||
data: observableOf({
|
||||
dso: new RemoteData(false, false, true, null, community)
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
beforeEach(async(() => {
|
||||
initializeVars();
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
||||
providers: [
|
||||
{ provide: ComColDataService, useValue: communityDataServiceStub },
|
||||
{ provide: Router, useValue: routerStub },
|
||||
{ provide: ActivatedRoute, useValue: routeStub },
|
||||
{ provide: NotificationsService, useValue: new NotificationsServiceStub() }
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ComcolMetadataComponent);
|
||||
comp = fixture.componentInstance;
|
||||
(comp as any).type = Community.type;
|
||||
fixture.detectChanges();
|
||||
dsoDataService = (comp as any).dsoDataService;
|
||||
router = (comp as any).router;
|
||||
});
|
||||
|
||||
describe('onSubmit', () => {
|
||||
let data;
|
||||
|
||||
describe('with an empty queue in the uploader', () => {
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
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();
|
||||
});
|
||||
});
|
||||
|
||||
describe('with at least one item in the uploader\'s queue', () => {
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
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 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();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@@ -0,0 +1,85 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { DSpaceObject } from '../../../../core/shared/dspace-object.model';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { RemoteData } from '../../../../core/data/remote-data';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { first, map, take } from 'rxjs/operators';
|
||||
import { getSucceededRemoteData } from '../../../../core/shared/operators';
|
||||
import { hasValue, isNotUndefined } from '../../../empty.util';
|
||||
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({
|
||||
selector: 'ds-comcol-metadata',
|
||||
template: ''
|
||||
})
|
||||
export class ComcolMetadataComponent<TDomain extends DSpaceObject> implements OnInit {
|
||||
/**
|
||||
* Frontend endpoint for this type of DSO
|
||||
*/
|
||||
protected frontendURL: string;
|
||||
/**
|
||||
* The initial DSO object
|
||||
*/
|
||||
public dsoRD$: Observable<RemoteData<TDomain>>;
|
||||
|
||||
/**
|
||||
* The type of the dso
|
||||
*/
|
||||
protected type: ResourceType;
|
||||
|
||||
public constructor(
|
||||
protected dsoDataService: ComColDataService<TDomain>,
|
||||
protected router: Router,
|
||||
protected route: ActivatedRoute,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected translate: TranslateService
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.dsoRD$ = this.route.parent.data.pipe(first(), map((data) => data.dso));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(event) {
|
||||
const dso = event.dso;
|
||||
const uploader = event.uploader;
|
||||
const deleteLogo = event.deleteLogo;
|
||||
|
||||
this.dsoDataService.update(dso)
|
||||
.pipe(getSucceededRemoteData())
|
||||
.subscribe((dsoRD: RemoteData<TDomain>) => {
|
||||
if (isNotUndefined(dsoRD)) {
|
||||
const newUUID = dsoRD.payload.uuid;
|
||||
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]);
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="border-bottom">{{ type + '.edit.head' | translate }}</h2>
|
||||
<div class="pt-2">
|
||||
<ul class="nav nav-tabs justify-content-start mb-2">
|
||||
<li *ngFor="let page of pages" class="nav-item">
|
||||
<a class="nav-link"
|
||||
[ngClass]="{'active' : page === currentPage}"
|
||||
[routerLink]="['./' + page]">
|
||||
{{ type + '.edit.tabs.' + page + '.head' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-pane active">
|
||||
<div class="mb-4">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
<a *ngIf="!hideReturnButton" [routerLink]="getPageUrl((dsoRD$ | async)?.payload)" class="btn btn-outline-secondary">{{ type + '.edit.return' | translate }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -1,5 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { CommunityDataService } from '../../../core/data/community-data.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
@@ -10,21 +9,13 @@ import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||
import { EditComColPageComponent } from './edit-comcol-page.component';
|
||||
import { DataService } from '../../../core/data/data.service';
|
||||
import {
|
||||
createFailedRemoteDataObject$,
|
||||
createSuccessfulRemoteDataObject$
|
||||
} from '../../testing/utils';
|
||||
|
||||
describe('EditComColPageComponent', () => {
|
||||
let comp: EditComColPageComponent<DSpaceObject>;
|
||||
let fixture: ComponentFixture<EditComColPageComponent<DSpaceObject>>;
|
||||
let dsoDataService: CommunityDataService;
|
||||
let router: Router;
|
||||
|
||||
let community;
|
||||
let newCommunity;
|
||||
let communityDataServiceStub;
|
||||
let routerStub;
|
||||
let routeStub;
|
||||
|
||||
@@ -37,25 +28,33 @@ describe('EditComColPageComponent', () => {
|
||||
}]
|
||||
});
|
||||
|
||||
newCommunity = Object.assign(new Community(), {
|
||||
uuid: '1ff59938-a69a-4e62-b9a4-718569c55d48',
|
||||
metadata: [{
|
||||
key: 'dc.title',
|
||||
value: 'new community'
|
||||
}]
|
||||
});
|
||||
|
||||
communityDataServiceStub = {
|
||||
update: (com, uuid?) => createSuccessfulRemoteDataObject$(newCommunity)
|
||||
|
||||
};
|
||||
|
||||
routerStub = {
|
||||
navigate: (commands) => commands
|
||||
navigate: (commands) => commands,
|
||||
events: observableOf({}),
|
||||
url: 'mockUrl'
|
||||
};
|
||||
|
||||
routeStub = {
|
||||
data: observableOf(community)
|
||||
data: observableOf({
|
||||
dso: community
|
||||
}),
|
||||
routeConfig: {
|
||||
children: [
|
||||
{
|
||||
path: 'mockUrl',
|
||||
data: {
|
||||
hideReturnButton: false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
snapshot: {
|
||||
firstChild: {
|
||||
routeConfig: {
|
||||
path: 'mockUrl'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -65,7 +64,6 @@ describe('EditComColPageComponent', () => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
||||
providers: [
|
||||
{ provide: DataService, useValue: communityDataServiceStub },
|
||||
{ provide: Router, useValue: routerStub },
|
||||
{ provide: ActivatedRoute, useValue: routeStub },
|
||||
],
|
||||
@@ -77,33 +75,16 @@ describe('EditComColPageComponent', () => {
|
||||
fixture = TestBed.createComponent(EditComColPageComponent);
|
||||
comp = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
dsoDataService = (comp as any).dsoDataService;
|
||||
router = (comp as any).router;
|
||||
});
|
||||
|
||||
describe('onSubmit', () => {
|
||||
let data;
|
||||
describe('getPageUrl', () => {
|
||||
let url;
|
||||
beforeEach(() => {
|
||||
data = Object.assign(new Community(), {
|
||||
metadata: [{
|
||||
key: 'dc.title',
|
||||
value: 'test'
|
||||
}]
|
||||
});
|
||||
url = comp.getPageUrl(community);
|
||||
});
|
||||
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 return the current url as a fallback', () => {
|
||||
expect(url).toEqual(routerStub.url);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { RemoteData } from '../../../core/data/remote-data';
|
||||
import { isNotUndefined } from '../../empty.util';
|
||||
import { isNotEmpty, isNotUndefined } from '../../empty.util';
|
||||
import { first, map } from 'rxjs/operators';
|
||||
import { getSucceededRemoteData } from '../../../core/shared/operators';
|
||||
import { DataService } from '../../../core/data/data.service';
|
||||
@@ -17,37 +17,54 @@ import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||
})
|
||||
export class EditComColPageComponent<TDomain extends DSpaceObject> implements OnInit {
|
||||
/**
|
||||
* Frontend endpoint for this type of DSO
|
||||
* The type of DSpaceObject (used to create i18n messages)
|
||||
*/
|
||||
protected frontendURL: string;
|
||||
public type: string;
|
||||
|
||||
/**
|
||||
* The initial DSO object
|
||||
* The current page outlet string
|
||||
*/
|
||||
public currentPage: string;
|
||||
|
||||
/**
|
||||
* All possible page outlet strings
|
||||
*/
|
||||
public pages: string[];
|
||||
|
||||
/**
|
||||
* The DSO to render the edit page for
|
||||
*/
|
||||
public dsoRD$: Observable<RemoteData<TDomain>>;
|
||||
|
||||
/**
|
||||
* Hide the default return button?
|
||||
*/
|
||||
public hideReturnButton: boolean;
|
||||
|
||||
public constructor(
|
||||
protected dsoDataService: DataService<TDomain>,
|
||||
protected router: Router,
|
||||
protected route: ActivatedRoute
|
||||
) {
|
||||
this.router.events.subscribe(() => {
|
||||
this.currentPage = this.route.snapshot.firstChild.routeConfig.path;
|
||||
this.hideReturnButton = this.route.routeConfig.children
|
||||
.find((child: any) => child.path === this.currentPage).data.hideReturnButton;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.pages = this.route.routeConfig.children
|
||||
.map((child: any) => child.path)
|
||||
.filter((path: string) => isNotEmpty(path)); // ignore reroutes
|
||||
this.dsoRD$ = this.route.data.pipe(first(), map((data) => data.dso));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TDomain} dso The updated version of the DSO
|
||||
* Updates an existing DSO based on the submitted user data and navigates to the edited object's home page
|
||||
* Get the dso's page url
|
||||
* This method is expected to be overridden in the edit community/collection page components
|
||||
* @param dso The DSpaceObject for which the url is requested
|
||||
*/
|
||||
onSubmit(dso: TDomain) {
|
||||
this.dsoDataService.update(dso)
|
||||
.pipe(getSucceededRemoteData())
|
||||
.subscribe((dsoRD: RemoteData<TDomain>) => {
|
||||
if (isNotUndefined(dsoRD)) {
|
||||
const newUUID = dsoRD.payload.uuid;
|
||||
this.router.navigate([this.frontendURL + newUUID]);
|
||||
}
|
||||
});
|
||||
getPageUrl(dso: TDomain): string {
|
||||
return this.router.url;
|
||||
}
|
||||
}
|
||||
|
@@ -3,4 +3,7 @@ export class AuthServiceMock {
|
||||
public checksAuthenticationToken() {
|
||||
return
|
||||
}
|
||||
public buildAuthHeader() {
|
||||
return 'auth-header';
|
||||
}
|
||||
}
|
||||
|
@@ -154,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 { 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 { 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 { CollectionSelectComponent } from './object-select/collection-select/collection-select.component';
|
||||
import { FilterInputSuggestionsComponent } from './input-suggestions/filter-suggestions/filter-input-suggestions.component';
|
||||
@@ -326,6 +328,8 @@ const COMPONENTS = [
|
||||
CollectionGridElementComponent,
|
||||
CommunityGridElementComponent,
|
||||
BrowseByComponent,
|
||||
AbstractTrackableComponent,
|
||||
ComcolMetadataComponent,
|
||||
ItemTypeBadgeComponent,
|
||||
ItemSelectComponent,
|
||||
CollectionSelectComponent,
|
||||
@@ -402,6 +406,7 @@ const SHARED_ITEM_PAGE_COMPONENTS = [
|
||||
const PROVIDERS = [
|
||||
TruncatableService,
|
||||
MockAdminGuard,
|
||||
AbstractTrackableComponent,
|
||||
{
|
||||
provide: DYNAMIC_FORM_CONTROL_MAP_FN,
|
||||
useValue: dsDynamicFormControlMapFn
|
||||
|
101
src/app/shared/trackable/abstract-trackable.component.spec.ts
Normal file
101
src/app/shared/trackable/abstract-trackable.component.spec.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { AbstractTrackableComponent } from './abstract-trackable.component';
|
||||
import { INotification, Notification } from '../notifications/models/notification.model';
|
||||
import { NotificationType } from '../notifications/models/notification-type';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ObjectUpdatesService } from '../../core/data/object-updates/object-updates.service';
|
||||
import { NotificationsService } from '../notifications/notifications.service';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { TestScheduler } from 'rxjs/testing';
|
||||
import { getTestScheduler } from 'jasmine-marbles';
|
||||
|
||||
describe('AbstractTrackableComponent', () => {
|
||||
let comp: AbstractTrackableComponent;
|
||||
let fixture: ComponentFixture<AbstractTrackableComponent>;
|
||||
let objectUpdatesService;
|
||||
let scheduler: TestScheduler;
|
||||
|
||||
const infoNotification: INotification = new Notification('id', NotificationType.Info, 'info');
|
||||
const warningNotification: INotification = new Notification('id', NotificationType.Warning, 'warning');
|
||||
const successNotification: INotification = new Notification('id', NotificationType.Success, 'success');
|
||||
|
||||
const notificationsService = jasmine.createSpyObj('notificationsService',
|
||||
{
|
||||
info: infoNotification,
|
||||
warning: warningNotification,
|
||||
success: successNotification
|
||||
}
|
||||
);
|
||||
|
||||
const url = 'http://test-url.com/test-url';
|
||||
|
||||
beforeEach(async(() => {
|
||||
objectUpdatesService = jasmine.createSpyObj('objectUpdatesService',
|
||||
{
|
||||
saveAddFieldUpdate: {},
|
||||
discardFieldUpdates: {},
|
||||
reinstateFieldUpdates: observableOf(true),
|
||||
initialize: {},
|
||||
hasUpdates: observableOf(true),
|
||||
isReinstatable: observableOf(false), // should always return something --> its in ngOnInit
|
||||
isValidPage: observableOf(true)
|
||||
}
|
||||
);
|
||||
|
||||
scheduler = getTestScheduler();
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot()],
|
||||
declarations: [AbstractTrackableComponent],
|
||||
providers: [
|
||||
{provide: ObjectUpdatesService, useValue: objectUpdatesService},
|
||||
{provide: NotificationsService, useValue: notificationsService},
|
||||
], schemas: [
|
||||
NO_ERRORS_SCHEMA
|
||||
]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AbstractTrackableComponent);
|
||||
comp = fixture.componentInstance;
|
||||
comp.url = url;
|
||||
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should discard object updates', () => {
|
||||
comp.discard();
|
||||
|
||||
expect(objectUpdatesService.discardFieldUpdates).toHaveBeenCalledWith(url, infoNotification);
|
||||
});
|
||||
it('should undo the discard of object updates', () => {
|
||||
comp.reinstate();
|
||||
|
||||
expect(objectUpdatesService.reinstateFieldUpdates).toHaveBeenCalledWith(url);
|
||||
});
|
||||
|
||||
describe('isReinstatable', () => {
|
||||
beforeEach(() => {
|
||||
objectUpdatesService.isReinstatable.and.returnValue(observableOf(true));
|
||||
});
|
||||
|
||||
it('should return an observable that emits true', () => {
|
||||
const expected = '(a|)';
|
||||
scheduler.expectObservable(comp.isReinstatable()).toBe(expected, {a: true});
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasChanges', () => {
|
||||
beforeEach(() => {
|
||||
objectUpdatesService.hasUpdates.and.returnValue(observableOf(true));
|
||||
});
|
||||
|
||||
it('should return an observable that emits true', () => {
|
||||
const expected = '(a|)';
|
||||
scheduler.expectObservable(comp.hasChanges()).toBe(expected, {a: true});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
78
src/app/shared/trackable/abstract-trackable.component.ts
Normal file
78
src/app/shared/trackable/abstract-trackable.component.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { ObjectUpdatesService } from '../../core/data/object-updates/object-updates.service';
|
||||
import { NotificationsService } from '../notifications/notifications.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
/**
|
||||
* Abstract Component that is able to track changes made in the inheriting component using the ObjectUpdateService
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-abstract-trackable',
|
||||
template: ''
|
||||
})
|
||||
export class AbstractTrackableComponent {
|
||||
|
||||
/**
|
||||
* The time span for being able to undo discarding changes
|
||||
*/
|
||||
public discardTimeOut: number;
|
||||
public message: string;
|
||||
public url: string;
|
||||
public notificationsPrefix = 'static-pages.form.notification';
|
||||
|
||||
constructor(
|
||||
public objectUpdatesService: ObjectUpdatesService,
|
||||
public notificationsService: NotificationsService,
|
||||
public translateService: TranslateService,
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the object updates service to discard all current changes to this item
|
||||
* Shows a notification to remind the user that they can undo this
|
||||
*/
|
||||
discard() {
|
||||
const undoNotification = this.notificationsService.info(this.getNotificationTitle('discarded'), this.getNotificationContent('discarded'), {timeOut: this.discardTimeOut});
|
||||
this.objectUpdatesService.discardFieldUpdates(this.url, undoNotification);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the object updates service to undo discarding all changes to this item
|
||||
*/
|
||||
reinstate() {
|
||||
this.objectUpdatesService.reinstateFieldUpdates(this.url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not the object is currently reinstatable
|
||||
*/
|
||||
isReinstatable(): Observable<boolean> {
|
||||
return this.objectUpdatesService.isReinstatable(this.url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not there are currently updates for this object
|
||||
*/
|
||||
hasChanges(): Observable<boolean> {
|
||||
return this.objectUpdatesService.hasUpdates(this.url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get translated notification title
|
||||
* @param key
|
||||
*/
|
||||
private getNotificationTitle(key: string) {
|
||||
return this.translateService.instant(this.notificationsPrefix + key + '.title');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get translated notification content
|
||||
* @param key
|
||||
*/
|
||||
private getNotificationContent(key: string) {
|
||||
return this.translateService.instant(this.notificationsPrefix + key + '.content');
|
||||
|
||||
}
|
||||
}
|
@@ -1,3 +1,4 @@
|
||||
import { RestRequestMethod } from '../../core/data/rest-request-method';
|
||||
|
||||
export class UploaderOptions {
|
||||
/**
|
||||
@@ -9,5 +10,15 @@ export class UploaderOptions {
|
||||
|
||||
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)"
|
||||
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">
|
||||
<span><i class="fas fa-cloud-upload" aria-hidden="true"></i> {{dropMsg | translate}} {{'uploader.or' | translate}}
|
||||
<label class="btn btn-link m-0 p-0">
|
||||
<input class="d-none" type="file" ng2FileSelect [uploader]="uploader" multiple />
|
||||
{{'uploader.browse' | translate}}
|
||||
</label>
|
||||
</span>
|
||||
<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 ml-1">
|
||||
<input class="d-none" type="file" ng2FileSelect [uploader]="uploader" multiple />
|
||||
{{'uploader.browse' | translate}}
|
||||
</label>
|
||||
</p>
|
||||
<div *ngIf="(isOverBaseDropZone | async) || uploader?.queue?.length !== 0">
|
||||
<div class="m-1">
|
||||
<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">
|
||||
<button type="button" class="btn btn-danger" (click)="uploader.clearQueue()" [disabled]="!uploader.queue.length">
|
||||
<i class="fas fa-trash" aria-hidden="true"></i>
|
||||
</button>
|
||||
</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>
|
||||
</div>
|
||||
<div class="ds-base-drop-zone-progress clearfix mt-2">
|
||||
|
@@ -64,12 +64,12 @@ describe('Chips component', () => {
|
||||
template: ``
|
||||
})
|
||||
class TestComponent {
|
||||
public uploadFilesOptions: UploaderOptions = {
|
||||
public uploadFilesOptions: UploaderOptions = Object.assign(new UploaderOptions(), {
|
||||
url: 'http://test',
|
||||
authToken: null,
|
||||
disableMultipart: false,
|
||||
itemAlias: null
|
||||
};
|
||||
});
|
||||
|
||||
/* tslint:disable:no-empty */
|
||||
public onBeforeUpload = () => {
|
||||
|
@@ -95,7 +95,8 @@ export class UploaderComponent {
|
||||
disableMultipart: this.uploadFilesOptions.disableMultipart,
|
||||
itemAlias: this.uploadFilesOptions.itemAlias,
|
||||
removeAfterUpload: true,
|
||||
autoUpload: true
|
||||
autoUpload: this.uploadFilesOptions.autoUpload,
|
||||
method: this.uploadFilesOptions.method
|
||||
});
|
||||
|
||||
if (isUndefined(this.enableDragOverDocument)) {
|
||||
@@ -117,7 +118,10 @@ export class UploaderComponent {
|
||||
if (isUndefined(this.onBeforeUpload)) {
|
||||
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.isOverDocumentDropZone = observableOf(false);
|
||||
|
||||
|
@@ -77,12 +77,7 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
|
||||
* The uploader configuration options
|
||||
* @type {UploaderOptions}
|
||||
*/
|
||||
public uploadFilesOptions: UploaderOptions = {
|
||||
url: '',
|
||||
authToken: null,
|
||||
disableMultipart: false,
|
||||
itemAlias: null
|
||||
};
|
||||
public uploadFilesOptions: UploaderOptions = new UploaderOptions();
|
||||
|
||||
/**
|
||||
* 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 { SharedModule } from '../../../shared/shared.module';
|
||||
import { createTestComponent } from '../../../shared/testing/utils';
|
||||
import { UploaderOptions } from '../../../shared/uploader/uploader-options.model';
|
||||
|
||||
describe('SubmissionUploadFilesComponent Component', () => {
|
||||
|
||||
@@ -112,12 +113,12 @@ describe('SubmissionUploadFilesComponent Component', () => {
|
||||
comp.submissionId = submissionId;
|
||||
comp.collectionId = collectionId;
|
||||
comp.sectionId = 'upload';
|
||||
comp.uploadFilesOptions = {
|
||||
comp.uploadFilesOptions = Object.assign(new UploaderOptions(),{
|
||||
url: '',
|
||||
authToken: null,
|
||||
disableMultipart: false,
|
||||
itemAlias: null
|
||||
};
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -208,11 +209,11 @@ class TestComponent {
|
||||
submissionId = mockSubmissionId;
|
||||
collectionId = mockSubmissionCollectionId;
|
||||
sectionId = 'upload';
|
||||
uploadFilesOptions = {
|
||||
uploadFilesOptions = Object.assign(new UploaderOptions(), {
|
||||
url: '',
|
||||
authToken: null,
|
||||
disableMultipart: false,
|
||||
itemAlias: null
|
||||
};
|
||||
});
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user