mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
62769: Bitstream format registry
This commit is contained in:
@@ -721,19 +721,77 @@
|
|||||||
"title": "DSpace Angular :: Bitstream Format Registry",
|
"title": "DSpace Angular :: Bitstream Format Registry",
|
||||||
"head": "Bitstream Format Registry",
|
"head": "Bitstream Format Registry",
|
||||||
"description": "This list of bitstream formats provides information about known formats and their support level.",
|
"description": "This list of bitstream formats provides information about known formats and their support level.",
|
||||||
"formats": {
|
"create": {
|
||||||
"table": {
|
"new": "Add a new bitstream format",
|
||||||
"name": "Name",
|
"head": "Create Bitstream format",
|
||||||
"mimetype": "MIME Type",
|
"success" : {
|
||||||
"supportLevel": {
|
"head": "Success",
|
||||||
"head": "Support Level",
|
"content": "The new bitstream format was successfully created."
|
||||||
"0": "Unknown",
|
|
||||||
"1": "Known",
|
|
||||||
"2": "Support"
|
|
||||||
},
|
|
||||||
"internal": "internal"
|
|
||||||
},
|
},
|
||||||
"no-items": "No bitstream formats to show."
|
"failure" : {
|
||||||
|
"head": "Failure",
|
||||||
|
"content": "An error occurred while creating the new bitstream format."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"table": {
|
||||||
|
"name": "Name",
|
||||||
|
"mimetype": "MIME Type",
|
||||||
|
"supportLevel": {
|
||||||
|
"head": "Support Level",
|
||||||
|
"UNKNOWN": "Unknown",
|
||||||
|
"KNOWN": "Known",
|
||||||
|
"SUPPORTED": "Supported"
|
||||||
|
},
|
||||||
|
"internal": "internal",
|
||||||
|
"delete": "Delete selected",
|
||||||
|
"return": "Return",
|
||||||
|
"deselect-all": "Deselect all"
|
||||||
|
},
|
||||||
|
"no-items": "No bitstream formats to show.",
|
||||||
|
"edit": {
|
||||||
|
"head": "Bitstream format: {{ format }}",
|
||||||
|
"shortDescription": {
|
||||||
|
"label": "Name",
|
||||||
|
"hint": "A unique name for this format, (e.g. Microsoft Word XP or Microsoft Word 2000)"
|
||||||
|
},
|
||||||
|
"mimetype": {
|
||||||
|
"label": "MIME Type",
|
||||||
|
"hint": "The MIME type associated with this format, does not have to be unique."
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"label": "Description",
|
||||||
|
"hint": ""
|
||||||
|
},
|
||||||
|
"supportLevel": {
|
||||||
|
"label": "Support level",
|
||||||
|
"hint": "The level of support your institution pledges for this format."
|
||||||
|
},
|
||||||
|
"internal": {
|
||||||
|
"label": "Internal",
|
||||||
|
"hint": "Formats marked as internal are are hidden from the user, and used for administrative purposes."
|
||||||
|
},
|
||||||
|
"extensions": {
|
||||||
|
"label": "File extensions",
|
||||||
|
"hint": "Extensions are file extensions that are used to automatically identify the format of uploaded files. You can enter several extensions for each format."
|
||||||
|
},
|
||||||
|
"success" : {
|
||||||
|
"head": "Success",
|
||||||
|
"content": "The bitstream format was successfully edited."
|
||||||
|
},
|
||||||
|
"failure" : {
|
||||||
|
"head": "Failure",
|
||||||
|
"content": "An error occurred while editing the bitstream format."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"success":{
|
||||||
|
"head": "Success",
|
||||||
|
"amount": "The following amount of bitstream formats have been successfully deleted: {{ amount }}"
|
||||||
|
},
|
||||||
|
"failure": {
|
||||||
|
"head": "Failure",
|
||||||
|
"amount": "The following amount of bitstream formats could not be deleted: {{ amount }} "
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,14 +2,29 @@ import { MetadataRegistryComponent } from './metadata-registry/metadata-registry
|
|||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { MetadataSchemaComponent } from './metadata-schema/metadata-schema.component';
|
import { MetadataSchemaComponent } from './metadata-schema/metadata-schema.component';
|
||||||
import { BitstreamFormatsComponent } from './bitstream-formats/bitstream-formats.component';
|
import { URLCombiner } from '../../core/url-combiner/url-combiner';
|
||||||
|
import { getRegistriesModulePath } from '../admin-routing.module';
|
||||||
|
|
||||||
|
const BITSTREAMFORMATS_MODULE_PATH = 'bitstream-formats';
|
||||||
|
|
||||||
|
export function getBitstreamFormatsModulePath() {
|
||||||
|
return new URLCombiner(getRegistriesModulePath(), BITSTREAMFORMATS_MODULE_PATH).toString();
|
||||||
|
}
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
RouterModule.forChild([
|
RouterModule.forChild([
|
||||||
{ path: 'metadata', component: MetadataRegistryComponent, data: { title: 'admin.registries.metadata.title' } },
|
{path: 'metadata', component: MetadataRegistryComponent, data: {title: 'admin.registries.metadata.title'}},
|
||||||
{ path: 'metadata/:schemaName', component: MetadataSchemaComponent, data: { title: 'admin.registries.schema.title' } },
|
{
|
||||||
{ path: 'bitstream-formats', component: BitstreamFormatsComponent, data: { title: 'admin.registries.bitstream-formats.title' } },
|
path: 'metadata/:schemaName',
|
||||||
|
component: MetadataSchemaComponent,
|
||||||
|
data: {title: 'admin.registries.schema.title'}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: BITSTREAMFORMATS_MODULE_PATH,
|
||||||
|
loadChildren: './bitstream-formats/bitstream-formats.module#BitstreamFormatsModule',
|
||||||
|
data: {title: 'admin.registries.bitstream-formats.title'}
|
||||||
|
},
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@@ -5,10 +5,10 @@ import { CommonModule } from '@angular/common';
|
|||||||
import { MetadataSchemaComponent } from './metadata-schema/metadata-schema.component';
|
import { MetadataSchemaComponent } from './metadata-schema/metadata-schema.component';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { BitstreamFormatsComponent } from './bitstream-formats/bitstream-formats.component';
|
|
||||||
import { SharedModule } from '../../shared/shared.module';
|
import { SharedModule } from '../../shared/shared.module';
|
||||||
import { MetadataSchemaFormComponent } from './metadata-registry/metadata-schema-form/metadata-schema-form.component';
|
import { MetadataSchemaFormComponent } from './metadata-registry/metadata-schema-form/metadata-schema-form.component';
|
||||||
import {MetadataFieldFormComponent} from './metadata-schema/metadata-field-form/metadata-field-form.component';
|
import { MetadataFieldFormComponent } from './metadata-schema/metadata-field-form/metadata-field-form.component';
|
||||||
|
import { BitstreamFormatsModule } from './bitstream-formats/bitstream-formats.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -16,12 +16,12 @@ import {MetadataFieldFormComponent} from './metadata-schema/metadata-field-form/
|
|||||||
SharedModule,
|
SharedModule,
|
||||||
RouterModule,
|
RouterModule,
|
||||||
TranslateModule,
|
TranslateModule,
|
||||||
|
BitstreamFormatsModule,
|
||||||
AdminRegistriesRoutingModule
|
AdminRegistriesRoutingModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
MetadataRegistryComponent,
|
MetadataRegistryComponent,
|
||||||
MetadataSchemaComponent,
|
MetadataSchemaComponent,
|
||||||
BitstreamFormatsComponent,
|
|
||||||
MetadataSchemaFormComponent,
|
MetadataSchemaFormComponent,
|
||||||
MetadataFieldFormComponent
|
MetadataFieldFormComponent
|
||||||
],
|
],
|
||||||
|
@@ -0,0 +1,11 @@
|
|||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 pb-4">
|
||||||
|
<h2 id="sub-header"
|
||||||
|
class="border-bottom pb-2">{{ 'admin.registries.bitstream-formats.create.new' | translate }}</h2>
|
||||||
|
|
||||||
|
<ds-bitstream-format-form (updatedFormat)="createBitstreamFormat($event)"></ds-bitstream-format-form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@@ -0,0 +1,109 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||||
|
import { RouterStub } from '../../../../shared/testing/router-stub';
|
||||||
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
||||||
|
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service-stub';
|
||||||
|
import { BitstreamFormatDataService } from '../../../../core/data/bitstream-format-data.service';
|
||||||
|
import { RestResponse } from '../../../../core/cache/response.models';
|
||||||
|
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
|
||||||
|
import { BitstreamFormatSupportLevel } from '../../../../core/shared/bitstream-format-support-level';
|
||||||
|
import { ResourceType } from '../../../../core/shared/resource-type';
|
||||||
|
import { AddBitstreamFormatComponent } from './add-bitstream-format.component';
|
||||||
|
|
||||||
|
describe('AddBitstreamFormatComponent', () => {
|
||||||
|
let comp: AddBitstreamFormatComponent;
|
||||||
|
let fixture: ComponentFixture<AddBitstreamFormatComponent>;
|
||||||
|
|
||||||
|
const bitstreamFormat: BitstreamFormat = {
|
||||||
|
uuid: 'test-uuid',
|
||||||
|
id: 'test-uuid',
|
||||||
|
shortDescription: 'Adobe PDF',
|
||||||
|
description: 'Adobe Portable Document Format',
|
||||||
|
mimetype: 'application/pdf',
|
||||||
|
supportLevel: BitstreamFormatSupportLevel.Unknown,
|
||||||
|
internal: false,
|
||||||
|
extensions: ['pdf', 'also-pdf'],
|
||||||
|
type: ResourceType.BitstreamFormat,
|
||||||
|
self: 'self-link'
|
||||||
|
};
|
||||||
|
|
||||||
|
let router;
|
||||||
|
let notificationService: NotificationsServiceStub;
|
||||||
|
let bitstreamFormatDataService: BitstreamFormatDataService;
|
||||||
|
|
||||||
|
const initAsync = () => {
|
||||||
|
router = new RouterStub();
|
||||||
|
notificationService = new NotificationsServiceStub();
|
||||||
|
bitstreamFormatDataService = jasmine.createSpyObj('bitstreamFormatDataService', {
|
||||||
|
createBitstreamFormat: observableOf(new RestResponse(true, 200, 'Success')),
|
||||||
|
clearBitStreamFormatRequests: observableOf(null)
|
||||||
|
});
|
||||||
|
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
|
||||||
|
declarations: [AddBitstreamFormatComponent],
|
||||||
|
providers: [
|
||||||
|
{provide: Router, useValue: router},
|
||||||
|
{provide: NotificationsService, useValue: notificationService},
|
||||||
|
{provide: BitstreamFormatDataService, useValue: bitstreamFormatDataService},
|
||||||
|
],
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
};
|
||||||
|
|
||||||
|
const initBeforeEach = () => {
|
||||||
|
fixture = TestBed.createComponent(AddBitstreamFormatComponent);
|
||||||
|
comp = fixture.componentInstance;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('createBitstreamFormat success', () => {
|
||||||
|
beforeEach(async(initAsync));
|
||||||
|
beforeEach(initBeforeEach);
|
||||||
|
it('should send the updated form to the service, show a notification and navigate to ', () => {
|
||||||
|
comp.createBitstreamFormat(bitstreamFormat);
|
||||||
|
|
||||||
|
expect(bitstreamFormatDataService.createBitstreamFormat).toHaveBeenCalledWith(bitstreamFormat);
|
||||||
|
expect(notificationService.success).toHaveBeenCalled();
|
||||||
|
expect(router.navigate).toHaveBeenCalledWith(['/admin/registries/bitstream-formats']);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('createBitstreamFormat error', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
router = new RouterStub();
|
||||||
|
notificationService = new NotificationsServiceStub();
|
||||||
|
bitstreamFormatDataService = jasmine.createSpyObj('bitstreamFormatDataService', {
|
||||||
|
createBitstreamFormat: observableOf(new RestResponse(false, 400, 'Bad Request')),
|
||||||
|
clearBitStreamFormatRequests: observableOf(null)
|
||||||
|
});
|
||||||
|
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
|
||||||
|
declarations: [AddBitstreamFormatComponent],
|
||||||
|
providers: [
|
||||||
|
{provide: Router, useValue: router},
|
||||||
|
{provide: NotificationsService, useValue: notificationService},
|
||||||
|
{provide: BitstreamFormatDataService, useValue: bitstreamFormatDataService},
|
||||||
|
],
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
beforeEach(initBeforeEach);
|
||||||
|
it('should send the updated form to the service, show a notification and navigate to ', () => {
|
||||||
|
comp.createBitstreamFormat(bitstreamFormat);
|
||||||
|
|
||||||
|
expect(bitstreamFormatDataService.createBitstreamFormat).toHaveBeenCalledWith(bitstreamFormat);
|
||||||
|
expect(notificationService.error).toHaveBeenCalled();
|
||||||
|
expect(router.navigate).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,49 @@
|
|||||||
|
import { take } from 'rxjs/operators';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
|
||||||
|
import { BitstreamFormatDataService } from '../../../../core/data/bitstream-format-data.service';
|
||||||
|
import { RestResponse } from '../../../../core/cache/response.models';
|
||||||
|
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
||||||
|
import { getBitstreamFormatsModulePath } from '../../admin-registries-routing.module';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component renders the page to create a new bitstream format.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-add-bitstream-format',
|
||||||
|
templateUrl: './add-bitstream-format.component.html',
|
||||||
|
})
|
||||||
|
export class AddBitstreamFormatComponent {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private router: Router,
|
||||||
|
private notificationService: NotificationsService,
|
||||||
|
private translateService: TranslateService,
|
||||||
|
private bitstreamFormatDataService: BitstreamFormatDataService,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new bitstream format based on the provided bitstream format emitted by the form.
|
||||||
|
* When successful, a success notification will be shown and the user will be navigated back to the overview page.
|
||||||
|
* When failed, an error notification will be shown.
|
||||||
|
* @param bitstreamFormat
|
||||||
|
*/
|
||||||
|
createBitstreamFormat(bitstreamFormat: BitstreamFormat) {
|
||||||
|
this.bitstreamFormatDataService.createBitstreamFormat(bitstreamFormat).pipe(take(1)
|
||||||
|
).subscribe((response: RestResponse) => {
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
this.notificationService.success(this.translateService.get('admin.registries.bitstream-formats.create.success.head'),
|
||||||
|
this.translateService.get('admin.registries.bitstream-formats.create.success.content'));
|
||||||
|
this.router.navigate([getBitstreamFormatsModulePath()]);
|
||||||
|
this.bitstreamFormatDataService.clearBitStreamFormatRequests().subscribe();
|
||||||
|
} else {
|
||||||
|
this.notificationService.error(this.translateService.get('admin.registries.bitstream-formats.create.failure.head'),
|
||||||
|
this.translateService.get('admin.registries.bitstream-formats.create.failure.content'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,64 @@
|
|||||||
|
import { Action } from '@ngrx/store';
|
||||||
|
import { type } from '../../../shared/ngrx/type';
|
||||||
|
import { BitstreamFormat } from '../../../core/shared/bitstream-format.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For each action type in an action group, make a simple
|
||||||
|
* enum object for all of this group's action types.
|
||||||
|
*
|
||||||
|
* The 'type' utility function coerces strings into string
|
||||||
|
* literal types and runs a simple check to guarantee all
|
||||||
|
* action types in the application are unique.
|
||||||
|
*/
|
||||||
|
export const BitstreamFormatsRegistryActionTypes = {
|
||||||
|
|
||||||
|
SELECT_FORMAT: type('dspace/bitstream-formats-registry/SELECT_FORMAT'),
|
||||||
|
DESELECT_FORMAT: type('dspace/bitstream-formats-registry/DESELECT_FORMAT'),
|
||||||
|
DESELECT_ALL_FORMAT: type('dspace/bitstream-formats-registry/DESELECT_ALL_FORMAT')
|
||||||
|
};
|
||||||
|
|
||||||
|
/* tslint:disable:max-classes-per-file */
|
||||||
|
/**
|
||||||
|
* Used to select a single bitstream format in the bitstream format registry
|
||||||
|
*/
|
||||||
|
export class BitstreamFormatsRegistrySelectAction implements Action {
|
||||||
|
type = BitstreamFormatsRegistryActionTypes.SELECT_FORMAT;
|
||||||
|
|
||||||
|
bitstreamFormat: BitstreamFormat;
|
||||||
|
|
||||||
|
constructor(bitstreamFormat: BitstreamFormat) {
|
||||||
|
this.bitstreamFormat = bitstreamFormat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to deselect a single bitstream format in the bitstream format registry
|
||||||
|
*/
|
||||||
|
export class BitstreamFormatsRegistryDeselectAction implements Action {
|
||||||
|
type = BitstreamFormatsRegistryActionTypes.DESELECT_FORMAT;
|
||||||
|
|
||||||
|
bitstreamFormat: BitstreamFormat;
|
||||||
|
|
||||||
|
constructor(bitstreamFormat: BitstreamFormat) {
|
||||||
|
this.bitstreamFormat = bitstreamFormat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to deselect all bitstream formats in the bitstream format registry
|
||||||
|
*/
|
||||||
|
export class BitstreamFormatsRegistryDeselectAllAction implements Action {
|
||||||
|
type = BitstreamFormatsRegistryActionTypes.DESELECT_ALL_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tslint:enable:max-classes-per-file */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export a type alias of all actions in this action group
|
||||||
|
* so that reducers can easily compose action types
|
||||||
|
* These are all the actions to perform on the bitstream format registry state
|
||||||
|
*/
|
||||||
|
export type BitstreamFormatsRegistryAction
|
||||||
|
= BitstreamFormatsRegistrySelectAction
|
||||||
|
| BitstreamFormatsRegistryDeselectAction
|
||||||
|
| BitstreamFormatsRegistryDeselectAllAction
|
@@ -0,0 +1,83 @@
|
|||||||
|
import { Action } from '@ngrx/store';
|
||||||
|
import { BitstreamFormat } from '../../../core/shared/bitstream-format.model';
|
||||||
|
import { bitstreamFormatReducer, BitstreamFormatRegistryState } from './bitstream-format.reducers';
|
||||||
|
import {
|
||||||
|
BitstreamFormatsRegistryDeselectAction,
|
||||||
|
BitstreamFormatsRegistryDeselectAllAction,
|
||||||
|
BitstreamFormatsRegistrySelectAction
|
||||||
|
} from './bitstream-format.actions';
|
||||||
|
|
||||||
|
const bitstreamFormat1: BitstreamFormat = new BitstreamFormat();
|
||||||
|
bitstreamFormat1.id = 'test-uuid-1';
|
||||||
|
bitstreamFormat1.shortDescription = 'test-short-1';
|
||||||
|
|
||||||
|
const bitstreamFormat2: BitstreamFormat = new BitstreamFormat();
|
||||||
|
bitstreamFormat2.id = 'test-uuid-2';
|
||||||
|
bitstreamFormat2.shortDescription = 'test-short-2';
|
||||||
|
|
||||||
|
const initialState: BitstreamFormatRegistryState = {
|
||||||
|
selectedBitstreamFormats: []
|
||||||
|
};
|
||||||
|
|
||||||
|
const bitstream1SelectedState: BitstreamFormatRegistryState = {
|
||||||
|
selectedBitstreamFormats: [bitstreamFormat1]
|
||||||
|
};
|
||||||
|
|
||||||
|
const bitstream1and2SelectedState: BitstreamFormatRegistryState = {
|
||||||
|
selectedBitstreamFormats: [bitstreamFormat1, bitstreamFormat2]
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('BitstreamFormatReducer', () => {
|
||||||
|
describe('BitstreamFormatsRegistryActionTypes.SELECT_FORMAT', () => {
|
||||||
|
it('should add the format to the list of selected formats when initial list is empty', () => {
|
||||||
|
const state = initialState;
|
||||||
|
const action = new BitstreamFormatsRegistrySelectAction(bitstreamFormat1);
|
||||||
|
const newState = bitstreamFormatReducer(state, action);
|
||||||
|
|
||||||
|
expect(newState).toEqual(bitstream1SelectedState);
|
||||||
|
});
|
||||||
|
it('should add the format to the list of selected formats when formats are already present', () => {
|
||||||
|
const state = bitstream1SelectedState;
|
||||||
|
const action = new BitstreamFormatsRegistrySelectAction(bitstreamFormat2);
|
||||||
|
const newState = bitstreamFormatReducer(state, action);
|
||||||
|
|
||||||
|
expect(newState).toEqual(bitstream1and2SelectedState);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('BitstreamFormatsRegistryActionTypes.DESELECT_FORMAT', () => {
|
||||||
|
it('should deselect a format', () => {
|
||||||
|
const state = bitstream1and2SelectedState;
|
||||||
|
const action = new BitstreamFormatsRegistryDeselectAction(bitstreamFormat2);
|
||||||
|
const newState = bitstreamFormatReducer(state, action);
|
||||||
|
|
||||||
|
expect(newState).toEqual(bitstream1SelectedState);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('BitstreamFormatsRegistryActionTypes.DESELECT_ALL_FORMAT', () => {
|
||||||
|
it('should deselect all formats', () => {
|
||||||
|
const state = bitstream1and2SelectedState;
|
||||||
|
const action = new BitstreamFormatsRegistryDeselectAllAction();
|
||||||
|
const newState = bitstreamFormatReducer(state, action);
|
||||||
|
|
||||||
|
expect(newState).toEqual(initialState);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('Invalid action', () => {
|
||||||
|
it('should return the current state', () => {
|
||||||
|
const state = initialState;
|
||||||
|
const action = new NullAction();
|
||||||
|
|
||||||
|
const newState = bitstreamFormatReducer(state, action);
|
||||||
|
|
||||||
|
expect(newState).toEqual(state);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
class NullAction implements Action {
|
||||||
|
type = null;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
// empty constructor
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,55 @@
|
|||||||
|
import { BitstreamFormat } from '../../../core/shared/bitstream-format.model';
|
||||||
|
import {
|
||||||
|
BitstreamFormatsRegistryAction,
|
||||||
|
BitstreamFormatsRegistryActionTypes,
|
||||||
|
BitstreamFormatsRegistryDeselectAction,
|
||||||
|
BitstreamFormatsRegistrySelectAction
|
||||||
|
} from './bitstream-format.actions';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bitstream format registry state.
|
||||||
|
* @interface BitstreamFormatRegistryState
|
||||||
|
*/
|
||||||
|
export interface BitstreamFormatRegistryState {
|
||||||
|
selectedBitstreamFormats: BitstreamFormat[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The initial state.
|
||||||
|
*/
|
||||||
|
const initialState: BitstreamFormatRegistryState = {
|
||||||
|
selectedBitstreamFormats: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reducer that handles BitstreamFormatsRegistryActions to modify the bitstream format registry state
|
||||||
|
* @param state The current BitstreamFormatRegistryState
|
||||||
|
* @param action The BitstreamFormatsRegistryAction to perform on the state
|
||||||
|
*/
|
||||||
|
export function bitstreamFormatReducer(state = initialState, action: BitstreamFormatsRegistryAction): BitstreamFormatRegistryState {
|
||||||
|
|
||||||
|
switch (action.type) {
|
||||||
|
|
||||||
|
case BitstreamFormatsRegistryActionTypes.SELECT_FORMAT: {
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
selectedBitstreamFormats: [...state.selectedBitstreamFormats, (action as BitstreamFormatsRegistrySelectAction).bitstreamFormat]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
case BitstreamFormatsRegistryActionTypes.DESELECT_FORMAT: {
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
selectedBitstreamFormats: state.selectedBitstreamFormats.filter(
|
||||||
|
(selectedBitstreamFormats) => selectedBitstreamFormats !== (action as BitstreamFormatsRegistryDeselectAction).bitstreamFormat
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
case BitstreamFormatsRegistryActionTypes.DESELECT_ALL_FORMAT: {
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
selectedBitstreamFormats: []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,37 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
import { BitstreamFormatsResolver } from './bitstream-formats.resolver';
|
||||||
|
import { EditBitstreamFormatComponent } from './edit-bitstream-format/edit-bitstream-format.component';
|
||||||
|
import { BitstreamFormatsComponent } from './bitstream-formats.component';
|
||||||
|
import { AddBitstreamFormatComponent } from './add-bitstream-format/add-bitstream-format.component';
|
||||||
|
|
||||||
|
const BITSTREAMFORMAT_EDIT_PATH = ':id/edit';
|
||||||
|
const BITSTREAMFORMAT_ADD_PATH = 'add';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
RouterModule.forChild([
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: BitstreamFormatsComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: BITSTREAMFORMAT_ADD_PATH,
|
||||||
|
component: AddBitstreamFormatComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: BITSTREAMFORMAT_EDIT_PATH,
|
||||||
|
component: EditBitstreamFormatComponent,
|
||||||
|
resolve: {
|
||||||
|
bitstreamFormat: BitstreamFormatsResolver
|
||||||
|
}
|
||||||
|
},
|
||||||
|
])
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
BitstreamFormatsResolver,
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class BitstreamFormatsRoutingModule {
|
||||||
|
|
||||||
|
}
|
@@ -4,11 +4,13 @@
|
|||||||
|
|
||||||
<h2 id="header" class="border-bottom pb-2">{{'admin.registries.bitstream-formats.head' | translate}}</h2>
|
<h2 id="header" class="border-bottom pb-2">{{'admin.registries.bitstream-formats.head' | translate}}</h2>
|
||||||
|
|
||||||
<p id="description" class="pb-2">{{'admin.registries.bitstream-formats.description' | translate}}</p>
|
<p id="description">{{'admin.registries.bitstream-formats.description' | translate}}</p>
|
||||||
|
<p id="create-new" class="pb-2"><a [routerLink]="'add'">{{'admin.registries.bitstream-formats.create.new' | translate}}</a></p>
|
||||||
|
|
||||||
|
|
||||||
<ds-pagination
|
<ds-pagination
|
||||||
*ngIf="(bitstreamFormats | async)?.payload?.totalElements > 0"
|
*ngIf="(bitstreamFormats | async)?.payload?.totalElements > 0"
|
||||||
[paginationOptions]="config"
|
[paginationOptions]="pageConfig"
|
||||||
[pageInfoState]="(bitstreamFormats | async)?.payload"
|
[pageInfoState]="(bitstreamFormats | async)?.payload"
|
||||||
[collectionSize]="(bitstreamFormats | async)?.payload?.totalElements"
|
[collectionSize]="(bitstreamFormats | async)?.payload?.totalElements"
|
||||||
[hideGear]="true"
|
[hideGear]="true"
|
||||||
@@ -18,25 +20,38 @@
|
|||||||
<table id="formats" class="table table-striped table-hover">
|
<table id="formats" class="table table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">{{'admin.registries.bitstream-formats.formats.table.name' | translate}}</th>
|
<th scope="col"></th>
|
||||||
<th scope="col">{{'admin.registries.bitstream-formats.formats.table.mimetype' | translate}}</th>
|
<th scope="col">{{'admin.registries.bitstream-formats.table.name' | translate}}</th>
|
||||||
<th scope="col">{{'admin.registries.bitstream-formats.formats.table.supportLevel.head' | translate}}</th>
|
<th scope="col">{{'admin.registries.bitstream-formats.table.mimetype' | translate}}</th>
|
||||||
|
<th scope="col">{{'admin.registries.bitstream-formats.table.supportLevel.head' | translate}}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr *ngFor="let bitstreamFormat of (bitstreamFormats | async)?.payload?.page">
|
<tr *ngFor="let bitstreamFormat of (bitstreamFormats | async)?.payload?.page">
|
||||||
<td>{{bitstreamFormat.shortDescription}}</td>
|
<td>
|
||||||
<td>{{bitstreamFormat.mimetype}} <span *ngIf="bitstreamFormat.internal">({{'admin.registries.bitstream-formats.formats.table.internal' | translate}})</span></td>
|
<label>
|
||||||
<td>{{'admin.registries.bitstream-formats.formats.table.supportLevel.'+bitstreamFormat.supportLevel | translate}}</td>
|
<input type="checkbox"
|
||||||
|
[checked]="isSelected(bitstreamFormat) | async"
|
||||||
|
(change)="selectBitStreamFormat(bitstreamFormat, $event)"
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
<td><a [routerLink]="['/admin/registries/bitstream-formats', bitstreamFormat.id, 'edit']">{{bitstreamFormat.shortDescription}}</a></td>
|
||||||
|
<td><a [routerLink]="['/admin/registries/bitstream-formats', bitstreamFormat.id, 'edit']">{{bitstreamFormat.mimetype}} <span *ngIf="bitstreamFormat.internal">({{'admin.registries.bitstream-formats.table.internal' | translate}})</span></a></td>
|
||||||
|
<td><a [routerLink]="['/admin/registries/bitstream-formats', bitstreamFormat.id, 'edit']">{{'admin.registries.bitstream-formats.table.supportLevel.'+bitstreamFormat.supportLevel | translate}}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</ds-pagination>
|
</ds-pagination>
|
||||||
<div *ngIf="(bitstreamFormats | async)?.payload?.totalElements == 0" class="alert alert-info" role="alert">
|
<div *ngIf="(bitstreamFormats | async)?.payload?.totalElements == 0" class="alert alert-info" role="alert">
|
||||||
{{'admin.registries.bitstream-formats.formats.no-items' | translate}}
|
{{'admin.registries.bitstream-formats.no-items' | translate}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button *ngIf="(bitstreamFormats | async)?.payload?.page?.length > 0" class="btn btn-primary deselect" (click)="deselectAll()">{{'admin.registries.bitstream-formats.table.deselect-all' | translate}}</button>
|
||||||
|
<button *ngIf="(bitstreamFormats | async)?.payload?.page?.length > 0" type="submit" class="btn btn-danger float-right" (click)="deleteFormats()">{{'admin.registries.bitstream-formats.table.delete' | translate}}</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import { BitstreamFormatsComponent } from './bitstream-formats.component';
|
import { BitstreamFormatsComponent } from './bitstream-formats.component';
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { RegistryService } from '../../../core/registry/registry.service';
|
|
||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
import { RemoteData } from '../../../core/data/remote-data';
|
import { RemoteData } from '../../../core/data/remote-data';
|
||||||
import { PaginatedList } from '../../../core/data/paginated-list';
|
import { PaginatedList } from '../../../core/data/paginated-list';
|
||||||
@@ -13,85 +12,288 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
|||||||
import { EnumKeysPipe } from '../../../shared/utils/enum-keys-pipe';
|
import { EnumKeysPipe } from '../../../shared/utils/enum-keys-pipe';
|
||||||
import { HostWindowService } from '../../../shared/host-window.service';
|
import { HostWindowService } from '../../../shared/host-window.service';
|
||||||
import { HostWindowServiceStub } from '../../../shared/testing/host-window-service-stub';
|
import { HostWindowServiceStub } from '../../../shared/testing/host-window-service-stub';
|
||||||
|
import { BitstreamFormatDataService } from '../../../core/data/bitstream-format-data.service';
|
||||||
|
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||||
|
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub';
|
||||||
|
import { BitstreamFormat } from '../../../core/shared/bitstream-format.model';
|
||||||
|
import { ResourceType } from '../../../core/shared/resource-type';
|
||||||
|
import { BitstreamFormatSupportLevel } from '../../../core/shared/bitstream-format-support-level';
|
||||||
|
import { cold, getTestScheduler, hot } from 'jasmine-marbles';
|
||||||
|
import { TestScheduler } from 'rxjs/testing';
|
||||||
|
|
||||||
describe('BitstreamFormatsComponent', () => {
|
describe('BitstreamFormatsComponent', () => {
|
||||||
let comp: BitstreamFormatsComponent;
|
let comp: BitstreamFormatsComponent;
|
||||||
let fixture: ComponentFixture<BitstreamFormatsComponent>;
|
let fixture: ComponentFixture<BitstreamFormatsComponent>;
|
||||||
let registryService: RegistryService;
|
let bitstreamFormatService;
|
||||||
const mockFormatsList = [
|
let scheduler: TestScheduler;
|
||||||
{
|
let notificationsServiceStub;
|
||||||
shortDescription: 'Unknown',
|
|
||||||
description: 'Unknown data format',
|
const bitstreamFormat1: BitstreamFormat = {
|
||||||
mimetype: 'application/octet-stream',
|
uuid: 'test-uuid-1',
|
||||||
supportLevel: 0,
|
id: 'test-uuid-1',
|
||||||
internal: false,
|
shortDescription: 'Unknown',
|
||||||
extensions: null
|
description: 'Unknown data format',
|
||||||
},
|
mimetype: 'application/octet-stream',
|
||||||
{
|
supportLevel: BitstreamFormatSupportLevel.Unknown,
|
||||||
shortDescription: 'License',
|
internal: false,
|
||||||
description: 'Item-specific license agreed upon to submission',
|
extensions: null,
|
||||||
mimetype: 'text/plain; charset=utf-8',
|
type: ResourceType.BitstreamFormat,
|
||||||
supportLevel: 1,
|
self: 'self-link'
|
||||||
internal: true,
|
};
|
||||||
extensions: null
|
const bitstreamFormat2: BitstreamFormat = {
|
||||||
},
|
uuid: 'test-uuid-2',
|
||||||
{
|
id: 'test-uuid-2',
|
||||||
shortDescription: 'CC License',
|
shortDescription: 'License',
|
||||||
description: 'Item-specific Creative Commons license agreed upon to submission',
|
description: 'Item-specific license agreed upon to submission',
|
||||||
mimetype: 'text/html; charset=utf-8',
|
mimetype: 'text/plain; charset=utf-8',
|
||||||
supportLevel: 2,
|
supportLevel: BitstreamFormatSupportLevel.Known,
|
||||||
internal: true,
|
internal: true,
|
||||||
extensions: null
|
extensions: null,
|
||||||
},
|
type: ResourceType.BitstreamFormat,
|
||||||
{
|
self: 'self-link'
|
||||||
shortDescription: 'Adobe PDF',
|
};
|
||||||
description: 'Adobe Portable Document Format',
|
const bitstreamFormat3: BitstreamFormat = {
|
||||||
mimetype: 'application/pdf',
|
uuid: 'test-uuid-3',
|
||||||
supportLevel: 0,
|
id: 'test-uuid-3',
|
||||||
internal: false,
|
shortDescription: 'CC License',
|
||||||
extensions: null
|
description: 'Item-specific Creative Commons license agreed upon to submission',
|
||||||
}
|
mimetype: 'text/html; charset=utf-8',
|
||||||
];
|
supportLevel: BitstreamFormatSupportLevel.Supported,
|
||||||
const mockFormats = observableOf(new RemoteData(false, false, true, undefined, new PaginatedList(null, mockFormatsList)));
|
internal: true,
|
||||||
const registryServiceStub = {
|
extensions: null,
|
||||||
getBitstreamFormats: () => mockFormats
|
type: ResourceType.BitstreamFormat,
|
||||||
|
self: 'self-link'
|
||||||
|
};
|
||||||
|
const bitstreamFormat4: BitstreamFormat = {
|
||||||
|
uuid: 'test-uuid-4',
|
||||||
|
id: 'test-uuid-4',
|
||||||
|
shortDescription: 'Adobe PDF',
|
||||||
|
description: 'Adobe Portable Document Format',
|
||||||
|
mimetype: 'application/pdf',
|
||||||
|
supportLevel: BitstreamFormatSupportLevel.Unknown,
|
||||||
|
internal: false,
|
||||||
|
extensions: null,
|
||||||
|
type: ResourceType.BitstreamFormat,
|
||||||
|
self: 'self-link'
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(async(() => {
|
const mockFormatsList: BitstreamFormat[] = [
|
||||||
|
bitstreamFormat1,
|
||||||
|
bitstreamFormat2,
|
||||||
|
bitstreamFormat3,
|
||||||
|
bitstreamFormat4
|
||||||
|
];
|
||||||
|
const mockFormatsRD = new RemoteData(false, false, true, undefined, new PaginatedList(null, mockFormatsList));
|
||||||
|
|
||||||
|
const initAsync = () => {
|
||||||
|
notificationsServiceStub = new NotificationsServiceStub();
|
||||||
|
|
||||||
|
scheduler = getTestScheduler();
|
||||||
|
|
||||||
|
bitstreamFormatService = jasmine.createSpyObj('bitstreamFormatService', {
|
||||||
|
findAll: observableOf(mockFormatsRD),
|
||||||
|
find: observableOf(new RemoteData(false, false, true, undefined, mockFormatsList[0])),
|
||||||
|
getSelectedBitstreamFormats: hot('a', {a: mockFormatsList}),
|
||||||
|
selectBitstreamFormat: {},
|
||||||
|
deselectBitstreamFormat: {},
|
||||||
|
deselectAllBitstreamFormats: {},
|
||||||
|
delete: observableOf(true),
|
||||||
|
clearBitStreamFormatRequests: observableOf('cleared')
|
||||||
|
});
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
|
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
|
||||||
declarations: [BitstreamFormatsComponent, PaginationComponent, EnumKeysPipe],
|
declarations: [BitstreamFormatsComponent, PaginationComponent, EnumKeysPipe],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: RegistryService, useValue: registryServiceStub },
|
{provide: BitstreamFormatDataService, useValue: bitstreamFormatService},
|
||||||
{ provide: HostWindowService, useValue: new HostWindowServiceStub(0) }
|
{provide: HostWindowService, useValue: new HostWindowServiceStub(0)},
|
||||||
|
{provide: NotificationsService, useValue: notificationsServiceStub}
|
||||||
]
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
const initBeforeEach = () => {
|
||||||
fixture = TestBed.createComponent(BitstreamFormatsComponent);
|
fixture = TestBed.createComponent(BitstreamFormatsComponent);
|
||||||
comp = fixture.componentInstance;
|
comp = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
registryService = (comp as any).service;
|
};
|
||||||
|
|
||||||
|
describe('Bitstream format page content', () => {
|
||||||
|
beforeEach(async(initAsync));
|
||||||
|
beforeEach(initBeforeEach);
|
||||||
|
|
||||||
|
it('should contain four formats', () => {
|
||||||
|
const tbody: HTMLElement = fixture.debugElement.query(By.css('#formats>tbody')).nativeElement;
|
||||||
|
expect(tbody.children.length).toBe(4);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain the correct formats', () => {
|
||||||
|
const unknownName: HTMLElement = fixture.debugElement.query(By.css('#formats tr:nth-child(1) td:nth-child(2)')).nativeElement;
|
||||||
|
expect(unknownName.textContent).toBe('Unknown');
|
||||||
|
|
||||||
|
const licenseName: HTMLElement = fixture.debugElement.query(By.css('#formats tr:nth-child(2) td:nth-child(2)')).nativeElement;
|
||||||
|
expect(licenseName.textContent).toBe('License');
|
||||||
|
|
||||||
|
const ccLicenseName: HTMLElement = fixture.debugElement.query(By.css('#formats tr:nth-child(3) td:nth-child(2)')).nativeElement;
|
||||||
|
expect(ccLicenseName.textContent).toBe('CC License');
|
||||||
|
|
||||||
|
const adobeName: HTMLElement = fixture.debugElement.query(By.css('#formats tr:nth-child(4) td:nth-child(2)')).nativeElement;
|
||||||
|
expect(adobeName.textContent).toBe('Adobe PDF');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should contain four formats', () => {
|
describe('selectBitStreamFormat', () => {
|
||||||
const tbody: HTMLElement = fixture.debugElement.query(By.css('#formats>tbody')).nativeElement;
|
beforeEach(async(initAsync));
|
||||||
expect(tbody.children.length).toBe(4);
|
beforeEach(initBeforeEach);
|
||||||
|
it('should select a bitstreamFormat if it was selected in the event', () => {
|
||||||
|
const event = {target: {checked: true}};
|
||||||
|
|
||||||
|
comp.selectBitStreamFormat(bitstreamFormat1, event);
|
||||||
|
|
||||||
|
expect(bitstreamFormatService.selectBitstreamFormat).toHaveBeenCalledWith(bitstreamFormat1);
|
||||||
|
});
|
||||||
|
it('should deselect a bitstreamFormat if it is deselected in the event', () => {
|
||||||
|
const event = {target: {checked: false}};
|
||||||
|
|
||||||
|
comp.selectBitStreamFormat(bitstreamFormat1, event);
|
||||||
|
|
||||||
|
expect(bitstreamFormatService.deselectBitstreamFormat).toHaveBeenCalledWith(bitstreamFormat1);
|
||||||
|
});
|
||||||
|
it('should be called when a user clicks a checkbox', () => {
|
||||||
|
spyOn(comp, 'selectBitStreamFormat');
|
||||||
|
const unknownFormat = fixture.debugElement.query(By.css('#formats tr:nth-child(1) input'));
|
||||||
|
|
||||||
|
const event = {target: {checked: true}};
|
||||||
|
unknownFormat.triggerEventHandler('change', event);
|
||||||
|
|
||||||
|
expect(comp.selectBitStreamFormat).toHaveBeenCalledWith(bitstreamFormat1, event);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should contain the correct formats', () => {
|
describe('isSelected', () => {
|
||||||
const unknownName: HTMLElement = fixture.debugElement.query(By.css('#formats tr:nth-child(1) td:nth-child(1)')).nativeElement;
|
beforeEach(async(initAsync));
|
||||||
expect(unknownName.textContent).toBe('Unknown');
|
beforeEach(initBeforeEach);
|
||||||
|
it('should return an observable of true if the provided bistream is in the list returned by the service', () => {
|
||||||
|
const result = comp.isSelected(bitstreamFormat1);
|
||||||
|
|
||||||
const licenseName: HTMLElement = fixture.debugElement.query(By.css('#formats tr:nth-child(2) td:nth-child(1)')).nativeElement;
|
expect(result).toBeObservable(cold('b', {b: true}));
|
||||||
expect(licenseName.textContent).toBe('License');
|
});
|
||||||
|
it('should return an observable of false if the provided bistream is not in the list returned by the service', () => {
|
||||||
|
const format = new BitstreamFormat();
|
||||||
|
format.uuid = 'new';
|
||||||
|
|
||||||
const ccLicenseName: HTMLElement = fixture.debugElement.query(By.css('#formats tr:nth-child(3) td:nth-child(1)')).nativeElement;
|
const result = comp.isSelected(format);
|
||||||
expect(ccLicenseName.textContent).toBe('CC License');
|
|
||||||
|
|
||||||
const adobeName: HTMLElement = fixture.debugElement.query(By.css('#formats tr:nth-child(4) td:nth-child(1)')).nativeElement;
|
expect(result).toBeObservable(cold('b', {b: false}));
|
||||||
expect(adobeName.textContent).toBe('Adobe PDF');
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('deselectAll', () => {
|
||||||
|
beforeEach(async(initAsync));
|
||||||
|
beforeEach(initBeforeEach);
|
||||||
|
it('should deselect all bitstreamFormats', () => {
|
||||||
|
comp.deselectAll();
|
||||||
|
expect(bitstreamFormatService.deselectAllBitstreamFormats).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be called when the deselect all button is clicked', () => {
|
||||||
|
spyOn(comp, 'deselectAll');
|
||||||
|
const deselectAllButton = fixture.debugElement.query(By.css('button.deselect'));
|
||||||
|
deselectAllButton.triggerEventHandler('click', null);
|
||||||
|
|
||||||
|
expect(comp.deselectAll).toHaveBeenCalled();
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('deleteFormats success', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
notificationsServiceStub = new NotificationsServiceStub();
|
||||||
|
|
||||||
|
scheduler = getTestScheduler();
|
||||||
|
|
||||||
|
bitstreamFormatService = jasmine.createSpyObj('bitstreamFormatService', {
|
||||||
|
findAll: observableOf(mockFormatsRD),
|
||||||
|
find: observableOf(new RemoteData(false, false, true, undefined, mockFormatsList[0])),
|
||||||
|
getSelectedBitstreamFormats: observableOf(mockFormatsList),
|
||||||
|
selectBitstreamFormat: {},
|
||||||
|
deselectBitstreamFormat: {},
|
||||||
|
deselectAllBitstreamFormats: {},
|
||||||
|
delete: observableOf(true),
|
||||||
|
clearBitStreamFormatRequests: observableOf('cleared')
|
||||||
|
});
|
||||||
|
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
|
||||||
|
declarations: [BitstreamFormatsComponent, PaginationComponent, EnumKeysPipe],
|
||||||
|
providers: [
|
||||||
|
{provide: BitstreamFormatDataService, useValue: bitstreamFormatService},
|
||||||
|
{provide: HostWindowService, useValue: new HostWindowServiceStub(0)},
|
||||||
|
{provide: NotificationsService, useValue: notificationsServiceStub}
|
||||||
|
]
|
||||||
|
}).compileComponents();
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
beforeEach(initBeforeEach);
|
||||||
|
it('should clear bitstream formats ', () => {
|
||||||
|
comp.deleteFormats();
|
||||||
|
|
||||||
|
expect(bitstreamFormatService.clearBitStreamFormatRequests).toHaveBeenCalled();
|
||||||
|
expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat1);
|
||||||
|
expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat2);
|
||||||
|
expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat3);
|
||||||
|
expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat4);
|
||||||
|
|
||||||
|
expect(notificationsServiceStub.success).toHaveBeenCalledWith('admin.registries.bitstream-formats.delete.success.head',
|
||||||
|
'admin.registries.bitstream-formats.delete.success.amount');
|
||||||
|
expect(notificationsServiceStub.error).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('deleteFormats error', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
notificationsServiceStub = new NotificationsServiceStub();
|
||||||
|
|
||||||
|
scheduler = getTestScheduler();
|
||||||
|
|
||||||
|
bitstreamFormatService = jasmine.createSpyObj('bitstreamFormatService', {
|
||||||
|
findAll: observableOf(mockFormatsRD),
|
||||||
|
find: observableOf(new RemoteData(false, false, true, undefined, mockFormatsList[0])),
|
||||||
|
getSelectedBitstreamFormats: observableOf(mockFormatsList),
|
||||||
|
selectBitstreamFormat: {},
|
||||||
|
deselectBitstreamFormat: {},
|
||||||
|
deselectAllBitstreamFormats: {},
|
||||||
|
delete: observableOf(false),
|
||||||
|
clearBitStreamFormatRequests: observableOf('cleared')
|
||||||
|
});
|
||||||
|
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
|
||||||
|
declarations: [BitstreamFormatsComponent, PaginationComponent, EnumKeysPipe],
|
||||||
|
providers: [
|
||||||
|
{provide: BitstreamFormatDataService, useValue: bitstreamFormatService},
|
||||||
|
{provide: HostWindowService, useValue: new HostWindowServiceStub(0)},
|
||||||
|
{provide: NotificationsService, useValue: notificationsServiceStub}
|
||||||
|
]
|
||||||
|
}).compileComponents();
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
beforeEach(initBeforeEach);
|
||||||
|
it('should clear bitstream formats ', () => {
|
||||||
|
comp.deleteFormats();
|
||||||
|
|
||||||
|
expect(bitstreamFormatService.clearBitStreamFormatRequests).toHaveBeenCalled();
|
||||||
|
expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat1);
|
||||||
|
expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat2);
|
||||||
|
expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat3);
|
||||||
|
expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat4);
|
||||||
|
|
||||||
|
expect(notificationsServiceStub.error).toHaveBeenCalledWith('admin.registries.bitstream-formats.delete.failure.head',
|
||||||
|
'admin.registries.bitstream-formats.delete.failure.amount');
|
||||||
|
expect(notificationsServiceStub.success).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,10 +1,16 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { RegistryService } from '../../../core/registry/registry.service';
|
import { BehaviorSubject, combineLatest as observableCombineLatest, Observable, zip } from 'rxjs';
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { RemoteData } from '../../../core/data/remote-data';
|
import { RemoteData } from '../../../core/data/remote-data';
|
||||||
import { PaginatedList } from '../../../core/data/paginated-list';
|
import { PaginatedList } from '../../../core/data/paginated-list';
|
||||||
import { BitstreamFormat } from '../../../core/registry/mock-bitstream-format.model';
|
|
||||||
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
|
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
|
||||||
|
import { BitstreamFormat } from '../../../core/shared/bitstream-format.model';
|
||||||
|
import { BitstreamFormatDataService } from '../../../core/data/bitstream-format-data.service';
|
||||||
|
import { FindAllOptions } from '../../../core/data/request.models';
|
||||||
|
import { map, switchMap, take } from 'rxjs/operators';
|
||||||
|
import { hasValue } from '../../../shared/empty.util';
|
||||||
|
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component renders a list of bitstream formats
|
* This component renders a list of bitstream formats
|
||||||
@@ -13,24 +19,122 @@ import { PaginationComponentOptions } from '../../../shared/pagination/paginatio
|
|||||||
selector: 'ds-bitstream-formats',
|
selector: 'ds-bitstream-formats',
|
||||||
templateUrl: './bitstream-formats.component.html'
|
templateUrl: './bitstream-formats.component.html'
|
||||||
})
|
})
|
||||||
export class BitstreamFormatsComponent {
|
export class BitstreamFormatsComponent implements OnInit {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A paginated list of bitstream formats to be shown on the page
|
* A paginated list of bitstream formats to be shown on the page
|
||||||
*/
|
*/
|
||||||
bitstreamFormats: Observable<RemoteData<PaginatedList<BitstreamFormat>>>;
|
bitstreamFormats: Observable<RemoteData<PaginatedList<BitstreamFormat>>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A BehaviourSubject that keeps track of the pageState used to update the currently displayed bitstreamFormats
|
||||||
|
*/
|
||||||
|
pageState: BehaviorSubject<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current pagination configuration for the page used by the FindAll method
|
||||||
|
* Currently simply renders all bitstream formats
|
||||||
|
*/
|
||||||
|
config: FindAllOptions = Object.assign(new FindAllOptions(), {
|
||||||
|
elementsPerPage: 10000
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current pagination configuration for the page
|
* The current pagination configuration for the page
|
||||||
* Currently simply renders all bitstream formats
|
* Currently simply renders all bitstream formats
|
||||||
*/
|
*/
|
||||||
config: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
|
pageConfig: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
|
||||||
id: 'registry-bitstreamformats-pagination',
|
id: 'registry-bitstreamformats-pagination',
|
||||||
pageSize: 10000
|
pageSize: 10000
|
||||||
});
|
});
|
||||||
|
|
||||||
constructor(private registryService: RegistryService) {
|
constructor(private notificationsService: NotificationsService,
|
||||||
this.updateFormats();
|
private router: Router,
|
||||||
|
private translateService: TranslateService,
|
||||||
|
private bitstreamFormatService: BitstreamFormatDataService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the currently selected formats from the registry and updates the presented list
|
||||||
|
*/
|
||||||
|
deleteFormats() {
|
||||||
|
this.bitstreamFormatService.clearBitStreamFormatRequests().subscribe();
|
||||||
|
this.bitstreamFormatService.getSelectedBitstreamFormats().pipe(take(1)).subscribe(
|
||||||
|
(formats) => {
|
||||||
|
const tasks$ = [];
|
||||||
|
for (const format of formats) {
|
||||||
|
if (hasValue(format.id)) {
|
||||||
|
tasks$.push(this.bitstreamFormatService.delete(format));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zip(...tasks$).subscribe((results: boolean[]) => {
|
||||||
|
const successResponses = results.filter((result: boolean) => result);
|
||||||
|
const failedResponses = results.filter((result: boolean) => !result);
|
||||||
|
if (successResponses.length > 0) {
|
||||||
|
this.showNotification(true, successResponses.length);
|
||||||
|
}
|
||||||
|
if (failedResponses.length > 0) {
|
||||||
|
this.showNotification(false, failedResponses.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.deselectAll();
|
||||||
|
this.pageState.next('update-on-delete');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deselects all selecetd bitstream formats
|
||||||
|
*/
|
||||||
|
deselectAll() {
|
||||||
|
this.bitstreamFormatService.deselectAllBitstreamFormats();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a given bitstream format is selected in the list (checkbox)
|
||||||
|
* @param bitstreamFormat
|
||||||
|
*/
|
||||||
|
isSelected(bitstreamFormat: BitstreamFormat): Observable<boolean> {
|
||||||
|
return this.bitstreamFormatService.getSelectedBitstreamFormats().pipe(
|
||||||
|
map((bitstreamFormats: BitstreamFormat[]) => {
|
||||||
|
return bitstreamFormats.find((selectedFormat) => selectedFormat.id === bitstreamFormat.id) != null;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects or deselects a bitstream format based on the checkbox state
|
||||||
|
* @param bitstreamFormat
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
selectBitStreamFormat(bitstreamFormat: BitstreamFormat, event) {
|
||||||
|
event.target.checked ?
|
||||||
|
this.bitstreamFormatService.selectBitstreamFormat(bitstreamFormat) :
|
||||||
|
this.bitstreamFormatService.deselectBitstreamFormat(bitstreamFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show notifications for an amount of deleted bitstream formats
|
||||||
|
* @param success Whether or not the notification should be a success message (error message when false)
|
||||||
|
* @param amount The amount of deleted bitstream formats
|
||||||
|
*/
|
||||||
|
private showNotification(success: boolean, amount: number) {
|
||||||
|
const prefix = 'admin.registries.bitstream-formats.delete';
|
||||||
|
const suffix = success ? 'success' : 'failure';
|
||||||
|
|
||||||
|
const messages = observableCombineLatest(
|
||||||
|
this.translateService.get(`${prefix}.${suffix}.head`),
|
||||||
|
this.translateService.get(`${prefix}.${suffix}.amount`, {amount: amount})
|
||||||
|
);
|
||||||
|
messages.subscribe(([head, content]) => {
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
this.notificationsService.success(head, content);
|
||||||
|
} else {
|
||||||
|
this.notificationsService.error(head, content);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,13 +143,23 @@ export class BitstreamFormatsComponent {
|
|||||||
*/
|
*/
|
||||||
onPageChange(event) {
|
onPageChange(event) {
|
||||||
this.config.currentPage = event;
|
this.config.currentPage = event;
|
||||||
|
this.pageConfig.currentPage = event;
|
||||||
this.updateFormats();
|
this.updateFormats();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.pageState = new BehaviorSubject('init');
|
||||||
|
this.bitstreamFormats = this.pageState.pipe(
|
||||||
|
switchMap(() => {
|
||||||
|
return this.updateFormats()
|
||||||
|
;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to update the bitstream formats that are shown
|
* Finds all formats based on the current config
|
||||||
*/
|
*/
|
||||||
private updateFormats() {
|
private updateFormats() {
|
||||||
this.bitstreamFormats = this.registryService.getBitstreamFormats(this.config);
|
return this.bitstreamFormatService.findAll(this.config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,30 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { BitstreamFormatsComponent } from './bitstream-formats.component';
|
||||||
|
import { SharedModule } from '../../../shared/shared.module';
|
||||||
|
import { FormatFormComponent } from './format-form/format-form.component';
|
||||||
|
import { EditBitstreamFormatComponent } from './edit-bitstream-format/edit-bitstream-format.component';
|
||||||
|
import { BitstreamFormatsRoutingModule } from './bitstream-formats-routing.module';
|
||||||
|
import { AddBitstreamFormatComponent } from './add-bitstream-format/add-bitstream-format.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
SharedModule,
|
||||||
|
RouterModule,
|
||||||
|
TranslateModule,
|
||||||
|
BitstreamFormatsRoutingModule
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
BitstreamFormatsComponent,
|
||||||
|
EditBitstreamFormatComponent,
|
||||||
|
AddBitstreamFormatComponent,
|
||||||
|
FormatFormComponent
|
||||||
|
],
|
||||||
|
entryComponents: []
|
||||||
|
})
|
||||||
|
export class BitstreamFormatsModule {
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,31 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { find } from 'rxjs/operators';
|
||||||
|
import { RemoteData } from '../../../core/data/remote-data';
|
||||||
|
import { BitstreamFormat } from '../../../core/shared/bitstream-format.model';
|
||||||
|
import { BitstreamFormatDataService } from '../../../core/data/bitstream-format-data.service';
|
||||||
|
import { hasValue } from '../../../shared/empty.util';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents a resolver that requests a specific bitstreamFormat before the route is activated
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class BitstreamFormatsResolver implements Resolve<RemoteData<BitstreamFormat>> {
|
||||||
|
constructor(private bitstreamFormatDataService: BitstreamFormatDataService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method for resolving an bitstreamFormat based on the parameters in the current route
|
||||||
|
* @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot
|
||||||
|
* @param {RouterStateSnapshot} state The current RouterStateSnapshot
|
||||||
|
* @returns Observable<<RemoteData<BitstreamFormat>> Emits the found bitstreamFormat based on the parameters in the current route,
|
||||||
|
* or an error if something went wrong
|
||||||
|
*/
|
||||||
|
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<RemoteData<BitstreamFormat>> {
|
||||||
|
return this.bitstreamFormatDataService.findById(route.params.id)
|
||||||
|
.pipe(
|
||||||
|
find((RD) => hasValue(RD.error) || RD.hasSucceeded),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,11 @@
|
|||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 pb-4">
|
||||||
|
<h2 id="sub-header"
|
||||||
|
class="border-bottom pb-2">{{'admin.registries.bitstream-formats.edit.head' | translate:{format: (bitstreamFormatRD$ | async)?.payload.shortDescription} }}</h2>
|
||||||
|
|
||||||
|
<ds-bitstream-format-form [bitstreamFormat]="(bitstreamFormatRD$ | async)?.payload" (updatedFormat)="updateFormat($event)"></ds-bitstream-format-form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@@ -0,0 +1,126 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||||
|
import { RouterStub } from '../../../../shared/testing/router-stub';
|
||||||
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { RemoteData } from '../../../../core/data/remote-data';
|
||||||
|
import { EditBitstreamFormatComponent } from './edit-bitstream-format.component';
|
||||||
|
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
||||||
|
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service-stub';
|
||||||
|
import { BitstreamFormatDataService } from '../../../../core/data/bitstream-format-data.service';
|
||||||
|
import { RestResponse } from '../../../../core/cache/response.models';
|
||||||
|
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
|
||||||
|
import { BitstreamFormatSupportLevel } from '../../../../core/shared/bitstream-format-support-level';
|
||||||
|
import { ResourceType } from '../../../../core/shared/resource-type';
|
||||||
|
|
||||||
|
describe('EditBitstreamFormatComponent', () => {
|
||||||
|
let comp: EditBitstreamFormatComponent;
|
||||||
|
let fixture: ComponentFixture<EditBitstreamFormatComponent>;
|
||||||
|
|
||||||
|
const bitstreamFormat: BitstreamFormat = {
|
||||||
|
uuid: 'test-uuid',
|
||||||
|
id: 'test-uuid',
|
||||||
|
shortDescription: 'Adobe PDF',
|
||||||
|
description: 'Adobe Portable Document Format',
|
||||||
|
mimetype: 'application/pdf',
|
||||||
|
supportLevel: BitstreamFormatSupportLevel.Unknown,
|
||||||
|
internal: false,
|
||||||
|
extensions: ['pdf', 'also-pdf'],
|
||||||
|
type: ResourceType.BitstreamFormat,
|
||||||
|
self: 'self-link'
|
||||||
|
};
|
||||||
|
|
||||||
|
const routeStub = {
|
||||||
|
data: observableOf({
|
||||||
|
bitstreamFormat: new RemoteData(false, false, true, null, bitstreamFormat)
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let router;
|
||||||
|
let notificationService: NotificationsServiceStub;
|
||||||
|
let bitstreamFormatDataService: BitstreamFormatDataService;
|
||||||
|
|
||||||
|
const initAsync = () => {
|
||||||
|
router = new RouterStub();
|
||||||
|
notificationService = new NotificationsServiceStub();
|
||||||
|
bitstreamFormatDataService = jasmine.createSpyObj('bitstreamFormatDataService', {
|
||||||
|
updateBitstreamFormat: observableOf(new RestResponse(true, 200, 'Success'))
|
||||||
|
});
|
||||||
|
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
|
||||||
|
declarations: [EditBitstreamFormatComponent],
|
||||||
|
providers: [
|
||||||
|
{provide: ActivatedRoute, useValue: routeStub},
|
||||||
|
{provide: Router, useValue: router},
|
||||||
|
{provide: NotificationsService, useValue: notificationService},
|
||||||
|
{provide: BitstreamFormatDataService, useValue: bitstreamFormatDataService},
|
||||||
|
],
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
};
|
||||||
|
|
||||||
|
const initBeforeEach = () => {
|
||||||
|
fixture = TestBed.createComponent(EditBitstreamFormatComponent);
|
||||||
|
comp = fixture.componentInstance;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('init', () => {
|
||||||
|
beforeEach(async(initAsync));
|
||||||
|
beforeEach(initBeforeEach);
|
||||||
|
it('should initialise the bitstreamFormat based on the route', () => {
|
||||||
|
|
||||||
|
comp.bitstreamFormatRD$.subscribe((format: RemoteData<BitstreamFormat>) => {
|
||||||
|
expect(format).toEqual(new RemoteData(false, false, true, null, bitstreamFormat));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('updateFormat success', () => {
|
||||||
|
beforeEach(async(initAsync));
|
||||||
|
beforeEach(initBeforeEach);
|
||||||
|
it('should send the updated form to the service, show a notification and navigate to ', () => {
|
||||||
|
comp.updateFormat(bitstreamFormat);
|
||||||
|
|
||||||
|
expect(bitstreamFormatDataService.updateBitstreamFormat).toHaveBeenCalledWith(bitstreamFormat);
|
||||||
|
expect(notificationService.success).toHaveBeenCalled();
|
||||||
|
expect(router.navigate).toHaveBeenCalledWith(['/admin/registries/bitstream-formats']);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('updateFormat error', () => {
|
||||||
|
beforeEach(async( () => {
|
||||||
|
router = new RouterStub();
|
||||||
|
notificationService = new NotificationsServiceStub();
|
||||||
|
bitstreamFormatDataService = jasmine.createSpyObj('bitstreamFormatDataService', {
|
||||||
|
updateBitstreamFormat: observableOf(new RestResponse(false, 400, 'Bad Request'))
|
||||||
|
});
|
||||||
|
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
|
||||||
|
declarations: [EditBitstreamFormatComponent],
|
||||||
|
providers: [
|
||||||
|
{provide: ActivatedRoute, useValue: routeStub},
|
||||||
|
{provide: Router, useValue: router},
|
||||||
|
{provide: NotificationsService, useValue: notificationService},
|
||||||
|
{provide: BitstreamFormatDataService, useValue: bitstreamFormatDataService},
|
||||||
|
],
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
beforeEach(initBeforeEach);
|
||||||
|
it('should send the updated form to the service, show a notification and navigate to ', () => {
|
||||||
|
comp.updateFormat(bitstreamFormat);
|
||||||
|
|
||||||
|
expect(bitstreamFormatDataService.updateBitstreamFormat).toHaveBeenCalledWith(bitstreamFormat);
|
||||||
|
expect(notificationService.error).toHaveBeenCalled();
|
||||||
|
expect(router.navigate).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,62 @@
|
|||||||
|
import { map, take } from 'rxjs/operators';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { RemoteData } from '../../../../core/data/remote-data';
|
||||||
|
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
|
||||||
|
import { BitstreamFormatDataService } from '../../../../core/data/bitstream-format-data.service';
|
||||||
|
import { RestResponse } from '../../../../core/cache/response.models';
|
||||||
|
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
||||||
|
import { getBitstreamFormatsModulePath } from '../../admin-registries-routing.module';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component renders the edit page of a bitstream format.
|
||||||
|
* The route parameter 'id' is used to request the bitstream format.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-edit-bitstream-format',
|
||||||
|
templateUrl: './edit-bitstream-format.component.html',
|
||||||
|
})
|
||||||
|
export class EditBitstreamFormatComponent implements OnInit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bitstream format wrapped in a remote-data object
|
||||||
|
*/
|
||||||
|
bitstreamFormatRD$: Observable<RemoteData<BitstreamFormat>>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private router: Router,
|
||||||
|
private notificationService: NotificationsService,
|
||||||
|
private translateService: TranslateService,
|
||||||
|
private bitstreamFormatDataService: BitstreamFormatDataService,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.bitstreamFormatRD$ = this.route.data.pipe(
|
||||||
|
map((data) => data.bitstreamFormat as RemoteData<BitstreamFormat>)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the bitstream format based on the provided bitstream format emitted by the form.
|
||||||
|
* When successful, a success notification will be shown and the user will be navigated back to the overview page.
|
||||||
|
* When failed, an error notification will be shown.
|
||||||
|
*/
|
||||||
|
updateFormat(bitstreamFormat: BitstreamFormat) {
|
||||||
|
this.bitstreamFormatDataService.updateBitstreamFormat(bitstreamFormat).pipe(take(1)
|
||||||
|
).subscribe((response: RestResponse) => {
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
this.notificationService.success(this.translateService.get('admin.registries.bitstream-formats.edit.success.head'),
|
||||||
|
this.translateService.get('admin.registries.bitstream-formats.edit.success.content'));
|
||||||
|
this.router.navigate([getBitstreamFormatsModulePath()]);
|
||||||
|
} else {
|
||||||
|
this.notificationService.error('admin.registries.bitstream-formats.edit.failure.head',
|
||||||
|
'admin.registries.bitstream-formats.create.edit.content');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,3 @@
|
|||||||
|
<ds-form *ngIf="formModel"
|
||||||
|
[formId]="'comcol-form-id'"
|
||||||
|
[formModel]="formModel" (submitForm)="onSubmit()" (cancel)="onCancel()"></ds-form>
|
@@ -0,0 +1,108 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import { RouterStub } from '../../../../shared/testing/router-stub';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { FormatFormComponent } from './format-form.component';
|
||||||
|
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
|
||||||
|
import { BitstreamFormatSupportLevel } from '../../../../core/shared/bitstream-format-support-level';
|
||||||
|
import { ResourceType } from '../../../../core/shared/resource-type';
|
||||||
|
import { DynamicCheckboxModel, DynamicFormArrayModel, DynamicInputModel } from '@ng-dynamic-forms/core';
|
||||||
|
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||||
|
import { isEmpty } from '../../../../shared/empty.util';
|
||||||
|
|
||||||
|
describe('FormatFormComponent', () => {
|
||||||
|
let comp: FormatFormComponent;
|
||||||
|
let fixture: ComponentFixture<FormatFormComponent>;
|
||||||
|
|
||||||
|
const router = new RouterStub();
|
||||||
|
|
||||||
|
const bitstreamFormat: BitstreamFormat = {
|
||||||
|
uuid: 'test-uuid',
|
||||||
|
id: 'test-uuid',
|
||||||
|
shortDescription: 'Adobe PDF',
|
||||||
|
description: 'Adobe Portable Document Format',
|
||||||
|
mimetype: 'application/pdf',
|
||||||
|
supportLevel: BitstreamFormatSupportLevel.Unknown,
|
||||||
|
internal: false,
|
||||||
|
extensions: ['pdf', 'also-pdf'],
|
||||||
|
type: ResourceType.BitstreamFormat,
|
||||||
|
self: 'self-link'
|
||||||
|
};
|
||||||
|
|
||||||
|
const submittedBitstreamFormat = new BitstreamFormat();
|
||||||
|
submittedBitstreamFormat.id = bitstreamFormat.id;
|
||||||
|
submittedBitstreamFormat.shortDescription = bitstreamFormat.shortDescription;
|
||||||
|
submittedBitstreamFormat.mimetype = bitstreamFormat.mimetype;
|
||||||
|
submittedBitstreamFormat.description = bitstreamFormat.description;
|
||||||
|
submittedBitstreamFormat.supportLevel = bitstreamFormat.supportLevel;
|
||||||
|
submittedBitstreamFormat.internal = bitstreamFormat.internal;
|
||||||
|
submittedBitstreamFormat.extensions = bitstreamFormat.extensions;
|
||||||
|
|
||||||
|
const initAsync = () => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [CommonModule, RouterTestingModule.withRoutes([]), ReactiveFormsModule, FormsModule, TranslateModule.forRoot(), NgbModule.forRoot()],
|
||||||
|
declarations: [FormatFormComponent],
|
||||||
|
providers: [
|
||||||
|
{provide: Router, useValue: router},
|
||||||
|
],
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
};
|
||||||
|
|
||||||
|
const initBeforeEach = () => {
|
||||||
|
fixture = TestBed.createComponent(FormatFormComponent);
|
||||||
|
comp = fixture.componentInstance;
|
||||||
|
|
||||||
|
comp.bitstreamFormat = bitstreamFormat;
|
||||||
|
fixture.detectChanges();
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('initialise', () => {
|
||||||
|
beforeEach(async(initAsync));
|
||||||
|
beforeEach(initBeforeEach);
|
||||||
|
it('should initialises the values in the form', () => {
|
||||||
|
|
||||||
|
expect((comp.formModel[0] as DynamicInputModel).value).toBe(bitstreamFormat.shortDescription);
|
||||||
|
expect((comp.formModel[1] as DynamicInputModel).value).toBe(bitstreamFormat.mimetype);
|
||||||
|
expect((comp.formModel[2] as DynamicInputModel).value).toBe(bitstreamFormat.description);
|
||||||
|
expect((comp.formModel[3] as DynamicInputModel).value).toBe(bitstreamFormat.supportLevel);
|
||||||
|
expect((comp.formModel[4] as DynamicCheckboxModel).value).toBe(bitstreamFormat.internal);
|
||||||
|
|
||||||
|
const formArray = (comp.formModel[5] as DynamicFormArrayModel);
|
||||||
|
const extensions = [];
|
||||||
|
for (let i = 0; i < formArray.groups.length; i++) {
|
||||||
|
const value = (formArray.get(i).get(0) as DynamicInputModel).value;
|
||||||
|
if (!isEmpty(value)) {
|
||||||
|
extensions.push((formArray.get(i).get(0) as DynamicInputModel).value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(extensions).toEqual(bitstreamFormat.extensions);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('onSubmit', () => {
|
||||||
|
beforeEach(async(initAsync));
|
||||||
|
beforeEach(initBeforeEach);
|
||||||
|
|
||||||
|
it('should emit the bitstreamFormat currently present in the form', () => {
|
||||||
|
spyOn(comp.updatedFormat, 'emit');
|
||||||
|
comp.onSubmit();
|
||||||
|
|
||||||
|
expect(comp.updatedFormat.emit).toHaveBeenCalledWith(submittedBitstreamFormat);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('onCancel', () => {
|
||||||
|
beforeEach(async(initAsync));
|
||||||
|
beforeEach(initBeforeEach);
|
||||||
|
|
||||||
|
it('should navigate back to the bitstream overview', () => {
|
||||||
|
comp.onCancel();
|
||||||
|
expect(router.navigate).toHaveBeenCalledWith(['/admin/registries/bitstream-formats']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,193 @@
|
|||||||
|
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||||
|
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
|
||||||
|
import { BitstreamFormatSupportLevel } from '../../../../core/shared/bitstream-format-support-level';
|
||||||
|
import {
|
||||||
|
DynamicCheckboxModel,
|
||||||
|
DynamicFormArrayModel,
|
||||||
|
DynamicFormControlLayout,
|
||||||
|
DynamicFormControlModel,
|
||||||
|
DynamicFormService,
|
||||||
|
DynamicInputModel,
|
||||||
|
DynamicSelectModel,
|
||||||
|
DynamicTextAreaModel
|
||||||
|
} from '@ng-dynamic-forms/core';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { getBitstreamFormatsModulePath } from '../../admin-registries-routing.module';
|
||||||
|
import { hasValue, isEmpty } from '../../../../shared/empty.util';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The component responsible for rendering the form to create/edit a bitstream format
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-bitstream-format-form',
|
||||||
|
templateUrl: './format-form.component.html'
|
||||||
|
})
|
||||||
|
export class FormatFormComponent implements OnInit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current bitstream format
|
||||||
|
* This can either be and existing one or a new one
|
||||||
|
*/
|
||||||
|
@Input() bitstreamFormat: BitstreamFormat = new BitstreamFormat();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EventEmitter that will emit the updated bitstream format
|
||||||
|
*/
|
||||||
|
@Output() updatedFormat: EventEmitter<BitstreamFormat> = new EventEmitter<BitstreamFormat>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The different supported support level of the bitstream format
|
||||||
|
*/
|
||||||
|
supportLevelOptions = [{label: BitstreamFormatSupportLevel.Known, value: BitstreamFormatSupportLevel.Known},
|
||||||
|
{label: BitstreamFormatSupportLevel.Unknown, value: BitstreamFormatSupportLevel.Unknown},
|
||||||
|
{label: BitstreamFormatSupportLevel.Supported, value: BitstreamFormatSupportLevel.Supported}];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styling element for repeatable field
|
||||||
|
*/
|
||||||
|
arrayElementLayout: DynamicFormControlLayout = {
|
||||||
|
grid: {
|
||||||
|
group: 'form-row',
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styling element for element of repeatable field
|
||||||
|
*/
|
||||||
|
arrayInputElementLayout: DynamicFormControlLayout = {
|
||||||
|
grid: {
|
||||||
|
host: 'col'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The form model representing the bitstream format
|
||||||
|
*/
|
||||||
|
formModel: DynamicFormControlModel[] = [
|
||||||
|
new DynamicInputModel({
|
||||||
|
id: 'shortDescription',
|
||||||
|
name: 'shortDescription',
|
||||||
|
label: 'admin.registries.bitstream-formats.edit.shortDescription.label',
|
||||||
|
hint: 'admin.registries.bitstream-formats.edit.shortDescription.hint',
|
||||||
|
required: true,
|
||||||
|
validators: {
|
||||||
|
required: null
|
||||||
|
},
|
||||||
|
errorMessages: {
|
||||||
|
required: 'Please enter a name for this bitstream format'
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
new DynamicInputModel({
|
||||||
|
id: 'mimetype',
|
||||||
|
name: 'mimetype',
|
||||||
|
label: 'admin.registries.bitstream-formats.edit.mimetype.label',
|
||||||
|
hint: 'admin.registries.bitstream-formats.edit.mimetype.hint',
|
||||||
|
|
||||||
|
}),
|
||||||
|
new DynamicTextAreaModel({
|
||||||
|
id: 'description',
|
||||||
|
name: 'description',
|
||||||
|
label: 'admin.registries.bitstream-formats.edit.description.label',
|
||||||
|
hint: 'admin.registries.bitstream-formats.edit.description.hint',
|
||||||
|
|
||||||
|
}),
|
||||||
|
new DynamicSelectModel({
|
||||||
|
id: 'supportLevel',
|
||||||
|
name: 'supportLevel',
|
||||||
|
options: this.supportLevelOptions,
|
||||||
|
label: 'admin.registries.bitstream-formats.edit.supportLevel.label',
|
||||||
|
hint: 'admin.registries.bitstream-formats.edit.supportLevel.hint',
|
||||||
|
value: this.supportLevelOptions[0].value
|
||||||
|
|
||||||
|
}),
|
||||||
|
new DynamicCheckboxModel({
|
||||||
|
id: 'internal',
|
||||||
|
name: 'internal',
|
||||||
|
label: 'Internal',
|
||||||
|
hint: 'admin.registries.bitstream-formats.edit.internal.hint',
|
||||||
|
}),
|
||||||
|
new DynamicFormArrayModel({
|
||||||
|
id: 'extensions',
|
||||||
|
name: 'extensions',
|
||||||
|
label: 'admin.registries.bitstream-formats.edit.extensions.label',
|
||||||
|
groupFactory: () => [
|
||||||
|
new DynamicInputModel({
|
||||||
|
id: 'extension',
|
||||||
|
}, this.arrayInputElementLayout)
|
||||||
|
]
|
||||||
|
}, this.arrayElementLayout),
|
||||||
|
];
|
||||||
|
|
||||||
|
constructor(private dynamicFormService: DynamicFormService,
|
||||||
|
private translateService: TranslateService,
|
||||||
|
private router: Router) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
|
||||||
|
this.initValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the form based on the provided bitstream format
|
||||||
|
*/
|
||||||
|
initValues() {
|
||||||
|
this.formModel.forEach(
|
||||||
|
(fieldModel: DynamicFormControlModel) => {
|
||||||
|
if (fieldModel.name === 'extensions') {
|
||||||
|
if (hasValue(this.bitstreamFormat.extensions)) {
|
||||||
|
const extenstions = this.bitstreamFormat.extensions;
|
||||||
|
const formArray = (fieldModel as DynamicFormArrayModel);
|
||||||
|
for (let i = 0; i < extenstions.length; i++) {
|
||||||
|
formArray.insertGroup(i).group[0] = new DynamicInputModel({
|
||||||
|
id: `extension-${i}`,
|
||||||
|
value: extenstions[i]
|
||||||
|
}, this.arrayInputElementLayout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (hasValue(this.bitstreamFormat[fieldModel.name])) {
|
||||||
|
(fieldModel as DynamicInputModel).value = this.bitstreamFormat[fieldModel.name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an updated bistream format based on the current values in the form
|
||||||
|
* Emits the updated bitstream format trouhg the updatedFormat emitter
|
||||||
|
*/
|
||||||
|
onSubmit() {
|
||||||
|
const updatedBitstreamFormat = Object.assign(new BitstreamFormat(),
|
||||||
|
{
|
||||||
|
id: this.bitstreamFormat.id
|
||||||
|
});
|
||||||
|
|
||||||
|
this.formModel.forEach(
|
||||||
|
(fieldModel: DynamicFormControlModel) => {
|
||||||
|
if (fieldModel.name === 'extensions') {
|
||||||
|
const formArray = (fieldModel as DynamicFormArrayModel);
|
||||||
|
const extensions = [];
|
||||||
|
for (let i = 0; i < formArray.groups.length; i++) {
|
||||||
|
const value = (formArray.get(i).get(0) as DynamicInputModel).value;
|
||||||
|
if (!isEmpty(value)) {
|
||||||
|
extensions.push((formArray.get(i).get(0) as DynamicInputModel).value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updatedBitstreamFormat.extensions = extensions;
|
||||||
|
} else {
|
||||||
|
updatedBitstreamFormat[fieldModel.name] = (fieldModel as DynamicInputModel).value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.updatedFormat.emit(updatedBitstreamFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels the edit/create action of the bitstream format and navigates back to the bitstream format registry
|
||||||
|
*/
|
||||||
|
onCancel() {
|
||||||
|
this.router.navigate([getBitstreamFormatsModulePath()]);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,11 +1,19 @@
|
|||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
|
import { URLCombiner } from '../core/url-combiner/url-combiner';
|
||||||
|
import { getAdminModulePath } from '../app-routing.module';
|
||||||
|
|
||||||
|
const REGISTRIES_MODULE_PATH = 'registries';
|
||||||
|
|
||||||
|
export function getRegistriesModulePath() {
|
||||||
|
return new URLCombiner(getAdminModulePath(), REGISTRIES_MODULE_PATH).toString();
|
||||||
|
}
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
RouterModule.forChild([
|
RouterModule.forChild([
|
||||||
{
|
{
|
||||||
path: 'registries',
|
path: REGISTRIES_MODULE_PATH,
|
||||||
loadChildren: './admin-registries/admin-registries.module#AdminRegistriesModule'
|
loadChildren: './admin-registries/admin-registries.module#AdminRegistriesModule'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
@@ -16,6 +16,12 @@ const COMMUNITY_MODULE_PATH = 'communities';
|
|||||||
export function getCommunityModulePath() {
|
export function getCommunityModulePath() {
|
||||||
return `/${COMMUNITY_MODULE_PATH}`;
|
return `/${COMMUNITY_MODULE_PATH}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ADMIN_MODULE_PATH = 'admin';
|
||||||
|
export function getAdminModulePath() {
|
||||||
|
return `/${ADMIN_MODULE_PATH}`;
|
||||||
|
}
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
RouterModule.forRoot([
|
RouterModule.forRoot([
|
||||||
@@ -27,7 +33,7 @@ export function getCommunityModulePath() {
|
|||||||
{ path: 'mydspace', loadChildren: './+my-dspace-page/my-dspace-page.module#MyDSpacePageModule', canActivate: [AuthenticatedGuard] },
|
{ path: 'mydspace', loadChildren: './+my-dspace-page/my-dspace-page.module#MyDSpacePageModule', canActivate: [AuthenticatedGuard] },
|
||||||
{ path: 'search', loadChildren: './+search-page/search-page.module#SearchPageModule' },
|
{ path: 'search', loadChildren: './+search-page/search-page.module#SearchPageModule' },
|
||||||
{ path: 'browse', loadChildren: './+browse-by/browse-by.module#BrowseByModule' },
|
{ path: 'browse', loadChildren: './+browse-by/browse-by.module#BrowseByModule' },
|
||||||
{ path: 'admin', loadChildren: './+admin/admin.module#AdminModule', canActivate: [AuthenticatedGuard] },
|
{ path: ADMIN_MODULE_PATH, loadChildren: './+admin/admin.module#AdminModule', canActivate: [AuthenticatedGuard] },
|
||||||
{ path: 'login', loadChildren: './+login-page/login-page.module#LoginPageModule' },
|
{ path: 'login', loadChildren: './+login-page/login-page.module#LoginPageModule' },
|
||||||
{ path: 'logout', loadChildren: './+logout-page/logout-page.module#LogoutPageModule' },
|
{ path: 'logout', loadChildren: './+logout-page/logout-page.module#LogoutPageModule' },
|
||||||
{ path: 'submit', loadChildren: './+submit-page/submit-page.module#SubmitPageModule' },
|
{ path: 'submit', loadChildren: './+submit-page/submit-page.module#SubmitPageModule' },
|
||||||
|
@@ -23,6 +23,10 @@ import { hasValue } from './shared/empty.util';
|
|||||||
import { cssVariablesReducer, CSSVariablesState } from './shared/sass-helper/sass-helper.reducer';
|
import { cssVariablesReducer, CSSVariablesState } from './shared/sass-helper/sass-helper.reducer';
|
||||||
import { menusReducer, MenusState } from './shared/menu/menu.reducer';
|
import { menusReducer, MenusState } from './shared/menu/menu.reducer';
|
||||||
import { historyReducer, HistoryState } from './shared/history/history.reducer';
|
import { historyReducer, HistoryState } from './shared/history/history.reducer';
|
||||||
|
import {
|
||||||
|
bitstreamFormatReducer,
|
||||||
|
BitstreamFormatRegistryState
|
||||||
|
} from './+admin/admin-registries/bitstream-formats/bitstream-format.reducers';
|
||||||
|
|
||||||
export interface AppState {
|
export interface AppState {
|
||||||
router: fromRouter.RouterReducerState;
|
router: fromRouter.RouterReducerState;
|
||||||
@@ -30,6 +34,7 @@ export interface AppState {
|
|||||||
hostWindow: HostWindowState;
|
hostWindow: HostWindowState;
|
||||||
forms: FormState;
|
forms: FormState;
|
||||||
metadataRegistry: MetadataRegistryState;
|
metadataRegistry: MetadataRegistryState;
|
||||||
|
bitstreamFormats: BitstreamFormatRegistryState;
|
||||||
notifications: NotificationsState;
|
notifications: NotificationsState;
|
||||||
searchSidebar: SearchSidebarState;
|
searchSidebar: SearchSidebarState;
|
||||||
searchFilter: SearchFiltersState;
|
searchFilter: SearchFiltersState;
|
||||||
@@ -44,6 +49,7 @@ export const appReducers: ActionReducerMap<AppState> = {
|
|||||||
hostWindow: hostWindowReducer,
|
hostWindow: hostWindowReducer,
|
||||||
forms: formReducer,
|
forms: formReducer,
|
||||||
metadataRegistry: metadataRegistryReducer,
|
metadataRegistry: metadataRegistryReducer,
|
||||||
|
bitstreamFormats: bitstreamFormatReducer,
|
||||||
notifications: notificationsReducer,
|
notifications: notificationsReducer,
|
||||||
searchSidebar: sidebarReducer,
|
searchSidebar: sidebarReducer,
|
||||||
searchFilter: filterReducer,
|
searchFilter: filterReducer,
|
||||||
|
@@ -4,7 +4,7 @@ import { BitstreamFormat } from '../../shared/bitstream-format.model';
|
|||||||
import { mapsTo } from '../builders/build-decorators';
|
import { mapsTo } from '../builders/build-decorators';
|
||||||
import { IDToUUIDSerializer } from '../id-to-uuid-serializer';
|
import { IDToUUIDSerializer } from '../id-to-uuid-serializer';
|
||||||
import { NormalizedObject } from './normalized-object.model';
|
import { NormalizedObject } from './normalized-object.model';
|
||||||
import { SupportLevel } from './support-level.model';
|
import { BitstreamFormatSupportLevel } from '../../shared/bitstream-format-support-level';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalized model class for a Bitstream Format
|
* Normalized model class for a Bitstream Format
|
||||||
@@ -35,7 +35,7 @@ export class NormalizedBitstreamFormat extends NormalizedObject<BitstreamFormat>
|
|||||||
* The level of support the system offers for this Bitstream Format
|
* The level of support the system offers for this Bitstream Format
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserialize
|
||||||
supportLevel: SupportLevel;
|
supportLevel: BitstreamFormatSupportLevel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if the Bitstream Format is used to store system information, rather than the content of items in the system
|
* True if the Bitstream Format is used to store system information, rather than the content of items in the system
|
||||||
@@ -47,7 +47,7 @@ export class NormalizedBitstreamFormat extends NormalizedObject<BitstreamFormat>
|
|||||||
* String representing this Bitstream Format's file extension
|
* String representing this Bitstream Format's file extension
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserialize
|
||||||
extensions: string;
|
extensions: string[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifier for this Bitstream Format
|
* Identifier for this Bitstream Format
|
||||||
|
@@ -87,6 +87,7 @@ import { MyDSpaceResponseParsingService } from './data/mydspace-response-parsing
|
|||||||
import { ClaimedTaskDataService } from './tasks/claimed-task-data.service';
|
import { ClaimedTaskDataService } from './tasks/claimed-task-data.service';
|
||||||
import { PoolTaskDataService } from './tasks/pool-task-data.service';
|
import { PoolTaskDataService } from './tasks/pool-task-data.service';
|
||||||
import { TaskResponseParsingService } from './tasks/task-response-parsing.service';
|
import { TaskResponseParsingService } from './tasks/task-response-parsing.service';
|
||||||
|
import { BitstreamFormatDataService } from './data/bitstream-format-data.service';
|
||||||
|
|
||||||
const IMPORTS = [
|
const IMPORTS = [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@@ -126,6 +127,7 @@ const PROVIDERS = [
|
|||||||
ObjectCacheService,
|
ObjectCacheService,
|
||||||
PaginationComponentOptions,
|
PaginationComponentOptions,
|
||||||
RegistryService,
|
RegistryService,
|
||||||
|
BitstreamFormatDataService,
|
||||||
NormalizedObjectBuildService,
|
NormalizedObjectBuildService,
|
||||||
RemoteDataBuildService,
|
RemoteDataBuildService,
|
||||||
RequestService,
|
RequestService,
|
||||||
|
293
src/app/core/data/bitstream-format-data.service.spec.ts
Normal file
293
src/app/core/data/bitstream-format-data.service.spec.ts
Normal file
@@ -0,0 +1,293 @@
|
|||||||
|
import { BitstreamFormatDataService } from './bitstream-format-data.service';
|
||||||
|
import { RequestEntry } from './request.reducer';
|
||||||
|
import { RestResponse } from '../cache/response.models';
|
||||||
|
import { Observable, of as observableOf } from 'rxjs';
|
||||||
|
import { Action, Store } from '@ngrx/store';
|
||||||
|
import { CoreState } from '../core.reducers';
|
||||||
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
|
import { cold, getTestScheduler, hot } from 'jasmine-marbles';
|
||||||
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
|
||||||
|
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||||
|
import { BitstreamFormat } from '../shared/bitstream-format.model';
|
||||||
|
import { async } from '@angular/core/testing';
|
||||||
|
import {
|
||||||
|
BitstreamFormatsRegistryDeselectAction,
|
||||||
|
BitstreamFormatsRegistryDeselectAllAction,
|
||||||
|
BitstreamFormatsRegistrySelectAction
|
||||||
|
} from '../../+admin/admin-registries/bitstream-formats/bitstream-format.actions';
|
||||||
|
import { TestScheduler } from 'rxjs/testing';
|
||||||
|
|
||||||
|
describe('BitstreamFormatDataService', () => {
|
||||||
|
let service: BitstreamFormatDataService;
|
||||||
|
let requestService;
|
||||||
|
let scheduler: TestScheduler;
|
||||||
|
|
||||||
|
const bitstreamFormatsEndpoint = 'https://rest.api/core/bitstream-formats';
|
||||||
|
const bitstreamFormatsIdEndpoint = 'https://rest.api/core/bitstream-formats/format-id';
|
||||||
|
|
||||||
|
const responseCacheEntry = new RequestEntry();
|
||||||
|
responseCacheEntry.response = new RestResponse(true, 200, 'Success');
|
||||||
|
responseCacheEntry.completed = true;
|
||||||
|
|
||||||
|
const store = {
|
||||||
|
dispatch(action: Action) {
|
||||||
|
// Do Nothing
|
||||||
|
}
|
||||||
|
} as Store<CoreState>;
|
||||||
|
|
||||||
|
const objectCache = {} as ObjectCacheService;
|
||||||
|
const halEndpointService = {
|
||||||
|
getEndpoint(linkPath: string): Observable<string> {
|
||||||
|
return cold('a', {a: bitstreamFormatsEndpoint});
|
||||||
|
}
|
||||||
|
} as HALEndpointService;
|
||||||
|
|
||||||
|
const notificationsService = {} as NotificationsService;
|
||||||
|
const http = {} as HttpClient;
|
||||||
|
const comparator = {} as any;
|
||||||
|
const dataBuildService = {} as NormalizedObjectBuildService;
|
||||||
|
const rdbService = {} as RemoteDataBuildService;
|
||||||
|
|
||||||
|
function initTestService(halService) {
|
||||||
|
return new BitstreamFormatDataService(
|
||||||
|
requestService,
|
||||||
|
rdbService,
|
||||||
|
dataBuildService,
|
||||||
|
store,
|
||||||
|
objectCache,
|
||||||
|
halService,
|
||||||
|
notificationsService,
|
||||||
|
http,
|
||||||
|
comparator
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('getBrowseEndpoint', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
scheduler = getTestScheduler();
|
||||||
|
requestService = jasmine.createSpyObj('requestService', {
|
||||||
|
configure: {},
|
||||||
|
getByHref: observableOf(responseCacheEntry),
|
||||||
|
getByUUID: cold('a', {a: responseCacheEntry}),
|
||||||
|
generateRequestId: 'request-id',
|
||||||
|
removeByHrefSubstring: {}
|
||||||
|
});
|
||||||
|
service = initTestService(halEndpointService);
|
||||||
|
}));
|
||||||
|
it('should get the browse endpoint', () => {
|
||||||
|
const result = service.getBrowseEndpoint();
|
||||||
|
const expected = cold('b', {b: bitstreamFormatsEndpoint});
|
||||||
|
|
||||||
|
expect(result).toBeObservable(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getUpdateEndpoint', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
scheduler = getTestScheduler();
|
||||||
|
requestService = jasmine.createSpyObj('requestService', {
|
||||||
|
configure: {},
|
||||||
|
getByHref: observableOf(responseCacheEntry),
|
||||||
|
getByUUID: cold('a', {a: responseCacheEntry}),
|
||||||
|
generateRequestId: 'request-id',
|
||||||
|
removeByHrefSubstring: {}
|
||||||
|
});
|
||||||
|
service = initTestService(halEndpointService);
|
||||||
|
}));
|
||||||
|
it('should get the update endpoint', () => {
|
||||||
|
const formatId = 'format-id';
|
||||||
|
|
||||||
|
const result = service.getUpdateEndpoint(formatId);
|
||||||
|
const expected = cold('b', {b: bitstreamFormatsIdEndpoint});
|
||||||
|
|
||||||
|
expect(result).toBeObservable(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getCreateEndpoint', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
scheduler = getTestScheduler();
|
||||||
|
requestService = jasmine.createSpyObj('requestService', {
|
||||||
|
configure: {},
|
||||||
|
getByHref: observableOf(responseCacheEntry),
|
||||||
|
getByUUID: cold('a', {a: responseCacheEntry}),
|
||||||
|
generateRequestId: 'request-id',
|
||||||
|
removeByHrefSubstring: {}
|
||||||
|
});
|
||||||
|
service = initTestService(halEndpointService);
|
||||||
|
}));
|
||||||
|
it('should get the create endpoint ', () => {
|
||||||
|
|
||||||
|
const result = service.getCreateEndpoint();
|
||||||
|
const expected = cold('b', {b: bitstreamFormatsEndpoint});
|
||||||
|
|
||||||
|
expect(result).toBeObservable(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('updateBitstreamFormat', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
scheduler = getTestScheduler();
|
||||||
|
requestService = jasmine.createSpyObj('requestService', {
|
||||||
|
configure: {},
|
||||||
|
getByHref: observableOf(responseCacheEntry),
|
||||||
|
getByUUID: cold('a', {a: responseCacheEntry}),
|
||||||
|
generateRequestId: 'request-id',
|
||||||
|
removeByHrefSubstring: {}
|
||||||
|
});
|
||||||
|
service = initTestService(halEndpointService);
|
||||||
|
}));
|
||||||
|
it('should update the bitstream format', () => {
|
||||||
|
const updatedBistreamFormat = new BitstreamFormat();
|
||||||
|
updatedBistreamFormat.uuid = 'updated-uuid';
|
||||||
|
|
||||||
|
const expected = cold('(b)', {b: new RestResponse(true, 200, 'Success')});
|
||||||
|
const result = service.updateBitstreamFormat(updatedBistreamFormat);
|
||||||
|
|
||||||
|
expect(result).toBeObservable(expected);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('createBitstreamFormat', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
scheduler = getTestScheduler();
|
||||||
|
requestService = jasmine.createSpyObj('requestService', {
|
||||||
|
configure: {},
|
||||||
|
getByHref: observableOf(responseCacheEntry),
|
||||||
|
getByUUID: cold('a', {a: responseCacheEntry}),
|
||||||
|
generateRequestId: 'request-id',
|
||||||
|
removeByHrefSubstring: {}
|
||||||
|
});
|
||||||
|
service = initTestService(halEndpointService);
|
||||||
|
}));
|
||||||
|
it('should create a new bitstream format', () => {
|
||||||
|
const newFormat = new BitstreamFormat();
|
||||||
|
newFormat.uuid = 'new-uuid';
|
||||||
|
|
||||||
|
const expected = cold('(b)', {b: new RestResponse(true, 200, 'Success')});
|
||||||
|
const result = service.createBitstreamFormat(newFormat);
|
||||||
|
|
||||||
|
expect(result).toBeObservable(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('clearBitStreamFormatRequests', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
scheduler = getTestScheduler();
|
||||||
|
requestService = jasmine.createSpyObj('requestService', {
|
||||||
|
configure: {},
|
||||||
|
getByHref: observableOf(responseCacheEntry),
|
||||||
|
getByUUID: cold('a', {a: responseCacheEntry}),
|
||||||
|
generateRequestId: 'request-id',
|
||||||
|
removeByHrefSubstring: {}
|
||||||
|
});
|
||||||
|
const halService = {
|
||||||
|
getEndpoint(linkPath: string): Observable<string> {
|
||||||
|
return observableOf(bitstreamFormatsEndpoint);
|
||||||
|
}
|
||||||
|
} as HALEndpointService;
|
||||||
|
service = initTestService(halService);
|
||||||
|
service.clearBitStreamFormatRequests().subscribe();
|
||||||
|
}));
|
||||||
|
it('should remove the bitstream format hrefs in the request service', () => {
|
||||||
|
expect(requestService.removeByHrefSubstring).toHaveBeenCalledWith(bitstreamFormatsEndpoint);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('selectBitstreamFormat', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
scheduler = getTestScheduler();
|
||||||
|
requestService = jasmine.createSpyObj('requestService', {
|
||||||
|
configure: {},
|
||||||
|
getByHref: observableOf(responseCacheEntry),
|
||||||
|
getByUUID: cold('a', {a: responseCacheEntry}),
|
||||||
|
generateRequestId: 'request-id',
|
||||||
|
removeByHrefSubstring: {}
|
||||||
|
});
|
||||||
|
service = initTestService(halEndpointService);
|
||||||
|
spyOn(store, 'dispatch');
|
||||||
|
}));
|
||||||
|
it('should add a selected bitstream to the store', () => {
|
||||||
|
const format = new BitstreamFormat();
|
||||||
|
format.uuid = 'uuid';
|
||||||
|
|
||||||
|
service.selectBitstreamFormat(format);
|
||||||
|
expect(store.dispatch).toHaveBeenCalledWith(new BitstreamFormatsRegistrySelectAction(format));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('deselectBitstreamFormat', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
scheduler = getTestScheduler();
|
||||||
|
requestService = jasmine.createSpyObj('requestService', {
|
||||||
|
configure: {},
|
||||||
|
getByHref: observableOf(responseCacheEntry),
|
||||||
|
getByUUID: cold('a', {a: responseCacheEntry}),
|
||||||
|
generateRequestId: 'request-id',
|
||||||
|
removeByHrefSubstring: {}
|
||||||
|
});
|
||||||
|
service = initTestService(halEndpointService);
|
||||||
|
spyOn(store, 'dispatch');
|
||||||
|
}));
|
||||||
|
it('should remove a bitstream from the store', () => {
|
||||||
|
const format = new BitstreamFormat();
|
||||||
|
format.uuid = 'uuid';
|
||||||
|
|
||||||
|
service.deselectBitstreamFormat(format);
|
||||||
|
expect(store.dispatch).toHaveBeenCalledWith(new BitstreamFormatsRegistryDeselectAction(format));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('deselectAllBitstreamFormats', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
scheduler = getTestScheduler();
|
||||||
|
requestService = jasmine.createSpyObj('requestService', {
|
||||||
|
configure: {},
|
||||||
|
getByHref: observableOf(responseCacheEntry),
|
||||||
|
getByUUID: cold('a', {a: responseCacheEntry}),
|
||||||
|
generateRequestId: 'request-id',
|
||||||
|
removeByHrefSubstring: {}
|
||||||
|
});
|
||||||
|
service = initTestService(halEndpointService);
|
||||||
|
spyOn(store, 'dispatch');
|
||||||
|
|
||||||
|
}));
|
||||||
|
it('should remove all bitstreamFormats from the store', () => {
|
||||||
|
service.deselectAllBitstreamFormats();
|
||||||
|
expect(store.dispatch).toHaveBeenCalledWith(new BitstreamFormatsRegistryDeselectAllAction());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('delete', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
scheduler = getTestScheduler();
|
||||||
|
requestService = jasmine.createSpyObj('requestService', {
|
||||||
|
configure: {},
|
||||||
|
getByHref: observableOf(responseCacheEntry),
|
||||||
|
getByUUID: hot('a', {a: responseCacheEntry}),
|
||||||
|
generateRequestId: 'request-id',
|
||||||
|
removeByHrefSubstring: {}
|
||||||
|
});
|
||||||
|
const halService = {
|
||||||
|
getEndpoint(linkPath: string): Observable<string> {
|
||||||
|
return observableOf(bitstreamFormatsEndpoint);
|
||||||
|
}
|
||||||
|
} as HALEndpointService;
|
||||||
|
service = initTestService(halService);
|
||||||
|
}));
|
||||||
|
it('should delete a bitstream format', () => {
|
||||||
|
const format = new BitstreamFormat();
|
||||||
|
format.uuid = 'format-uuid';
|
||||||
|
format.id = 'format-id';
|
||||||
|
|
||||||
|
const expected = cold('(b|)', {b: true});
|
||||||
|
const result = service.delete(format);
|
||||||
|
|
||||||
|
expect(result).toBeObservable(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
183
src/app/core/data/bitstream-format-data.service.ts
Normal file
183
src/app/core/data/bitstream-format-data.service.ts
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { DataService } from './data.service';
|
||||||
|
import { BitstreamFormat } from '../shared/bitstream-format.model';
|
||||||
|
import { RequestService } from './request.service';
|
||||||
|
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||||
|
import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
|
||||||
|
import { createSelector, select, Store } from '@ngrx/store';
|
||||||
|
import { CoreState } from '../core.reducers';
|
||||||
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||||
|
import { DeleteByIDRequest, FindAllOptions, PostRequest, PutRequest } from './request.models';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { find, map, tap } from 'rxjs/operators';
|
||||||
|
import { configureRequest, getResponseFromEntry } from '../shared/operators';
|
||||||
|
import { distinctUntilChanged } from 'rxjs/internal/operators/distinctUntilChanged';
|
||||||
|
import { RestResponse } from '../cache/response.models';
|
||||||
|
import { AppState } from '../../app.reducer';
|
||||||
|
import { BitstreamFormatRegistryState } from '../../+admin/admin-registries/bitstream-formats/bitstream-format.reducers';
|
||||||
|
import {
|
||||||
|
BitstreamFormatsRegistryDeselectAction,
|
||||||
|
BitstreamFormatsRegistryDeselectAllAction,
|
||||||
|
BitstreamFormatsRegistrySelectAction
|
||||||
|
} from '../../+admin/admin-registries/bitstream-formats/bitstream-format.actions';
|
||||||
|
import { hasValue } from '../../shared/empty.util';
|
||||||
|
import { RequestEntry } from './request.reducer';
|
||||||
|
|
||||||
|
const bitstreamFormatsStateSelector = (state: AppState) => state.bitstreamFormats;
|
||||||
|
const selectedBitstreamFormatSelector = createSelector(bitstreamFormatsStateSelector,
|
||||||
|
(bitstreamFormatRegistryState: BitstreamFormatRegistryState) => bitstreamFormatRegistryState.selectedBitstreamFormats);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A service responsible for fetching/sending data from/to the REST API on the bitstreamformats endpoint
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class BitstreamFormatDataService extends DataService<BitstreamFormat> {
|
||||||
|
|
||||||
|
protected linkPath = 'bitstreamformats';
|
||||||
|
protected forceBypassCache = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected requestService: RequestService,
|
||||||
|
protected rdbService: RemoteDataBuildService,
|
||||||
|
protected dataBuildService: NormalizedObjectBuildService,
|
||||||
|
protected store: Store<CoreState>,
|
||||||
|
protected objectCache: ObjectCacheService,
|
||||||
|
protected halService: HALEndpointService,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected http: HttpClient,
|
||||||
|
protected comparator: DefaultChangeAnalyzer<BitstreamFormat>) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the endpoint for browsing bitstream formats
|
||||||
|
* @param {FindAllOptions} options
|
||||||
|
* @returns {Observable<string>}
|
||||||
|
*/
|
||||||
|
getBrowseEndpoint(options: FindAllOptions = {}, linkPath?: string): Observable<string> {
|
||||||
|
return this.halService.getEndpoint(this.linkPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the endpoint to update an existing bitstream format
|
||||||
|
* @param formatId
|
||||||
|
*/
|
||||||
|
public getUpdateEndpoint(formatId: string): Observable<string> {
|
||||||
|
return this.getBrowseEndpoint().pipe(
|
||||||
|
map((endpoint: string) => this.getIDHref(endpoint, formatId))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the endpoint to create a new bitstream format
|
||||||
|
*/
|
||||||
|
public getCreateEndpoint(): Observable<string> {
|
||||||
|
return this.getBrowseEndpoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an existing bitstreamFormat
|
||||||
|
* @param bitstreamFormat
|
||||||
|
*/
|
||||||
|
updateBitstreamFormat(bitstreamFormat: BitstreamFormat): Observable<RestResponse> {
|
||||||
|
const requestId = this.requestService.generateRequestId();
|
||||||
|
|
||||||
|
this.getUpdateEndpoint(bitstreamFormat.id).pipe(
|
||||||
|
distinctUntilChanged(),
|
||||||
|
map((endpointURL: string) =>
|
||||||
|
new PutRequest(requestId, endpointURL, bitstreamFormat)),
|
||||||
|
configureRequest(this.requestService)).subscribe();
|
||||||
|
|
||||||
|
return this.requestService.getByUUID(requestId).pipe(
|
||||||
|
getResponseFromEntry()
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new BitstreamFormat
|
||||||
|
* @param BitstreamFormat
|
||||||
|
*/
|
||||||
|
public createBitstreamFormat(bitstreamFormat: BitstreamFormat): Observable<RestResponse> {
|
||||||
|
const requestId = this.requestService.generateRequestId();
|
||||||
|
|
||||||
|
this.getCreateEndpoint().pipe(
|
||||||
|
map((endpointURL: string) => {
|
||||||
|
return new PostRequest(requestId, endpointURL, bitstreamFormat);
|
||||||
|
}),
|
||||||
|
configureRequest(this.requestService)
|
||||||
|
).subscribe();
|
||||||
|
|
||||||
|
return this.requestService.getByUUID(requestId).pipe(
|
||||||
|
getResponseFromEntry()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the cache of the list of BitstreamFormats
|
||||||
|
*/
|
||||||
|
public clearBitStreamFormatRequests(): Observable<string> {
|
||||||
|
return this.getBrowseEndpoint().pipe(
|
||||||
|
tap((href: string) => this.requestService.removeByHrefSubstring(href))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all the selected BitstreamFormats from the store
|
||||||
|
*/
|
||||||
|
public getSelectedBitstreamFormats(): Observable<BitstreamFormat[]> {
|
||||||
|
return this.store.pipe(select(selectedBitstreamFormatSelector));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a BistreamFormat to the selected BitstreamFormats in the store
|
||||||
|
* @param bitstreamFormat
|
||||||
|
*/
|
||||||
|
public selectBitstreamFormat(bitstreamFormat: BitstreamFormat) {
|
||||||
|
this.store.dispatch(new BitstreamFormatsRegistrySelectAction(bitstreamFormat));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a BistreamFormat from the list of selected BitstreamFormats in the store
|
||||||
|
* @param bitstreamFormat
|
||||||
|
*/
|
||||||
|
public deselectBitstreamFormat(bitstreamFormat: BitstreamFormat) {
|
||||||
|
this.store.dispatch(new BitstreamFormatsRegistryDeselectAction(bitstreamFormat));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all BitstreamFormats from the list of selected BitstreamFormats in the store
|
||||||
|
*/
|
||||||
|
public deselectAllBitstreamFormats() {
|
||||||
|
this.store.dispatch(new BitstreamFormatsRegistryDeselectAllAction());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete an existing DSpace Object on the server
|
||||||
|
* @param format The DSpace Object to be removed
|
||||||
|
* Return an observable that emits true when the deletion was successful, false when it failed
|
||||||
|
*/
|
||||||
|
delete(format: BitstreamFormat): Observable<boolean> {
|
||||||
|
const requestId = this.requestService.generateRequestId();
|
||||||
|
|
||||||
|
const hrefObs = this.halService.getEndpoint(this.linkPath).pipe(
|
||||||
|
map((endpoint: string) => this.getIDHref(endpoint, format.id)));
|
||||||
|
|
||||||
|
hrefObs.pipe(
|
||||||
|
find((href: string) => hasValue(href)),
|
||||||
|
map((href: string) => {
|
||||||
|
const request = new DeleteByIDRequest(requestId, href, format.id);
|
||||||
|
this.requestService.configure(request);
|
||||||
|
})
|
||||||
|
).subscribe();
|
||||||
|
|
||||||
|
return this.requestService.getByUUID(requestId).pipe(
|
||||||
|
find((request: RequestEntry) => request.completed),
|
||||||
|
map((request: RequestEntry) => request.response.isSuccessful)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,8 +0,0 @@
|
|||||||
export class BitstreamFormat {
|
|
||||||
shortDescription: string;
|
|
||||||
description: string;
|
|
||||||
mimetype: string;
|
|
||||||
supportLevel: number;
|
|
||||||
internal: boolean;
|
|
||||||
extensions: string;
|
|
||||||
}
|
|
@@ -1,10 +1,10 @@
|
|||||||
import { autoserialize, autoserializeAs } from 'cerialize';
|
import { autoserialize, autoserializeAs } from 'cerialize';
|
||||||
import { PageInfo } from '../shared/page-info.model';
|
import { PageInfo } from '../shared/page-info.model';
|
||||||
import { BitstreamFormat } from '../shared/bitstream-format.model';
|
import { NormalizedBitstreamFormat } from '../cache/models/normalized-bitstream-format.model';
|
||||||
|
|
||||||
export class RegistryBitstreamformatsResponse {
|
export class RegistryBitstreamformatsResponse {
|
||||||
@autoserializeAs(BitstreamFormat)
|
@autoserializeAs(NormalizedBitstreamFormat)
|
||||||
bitstreamformats: BitstreamFormat[];
|
bitstreamformats: NormalizedBitstreamFormat[];
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
page: PageInfo;
|
page: PageInfo;
|
||||||
|
@@ -12,7 +12,6 @@ import { PageInfo } from '../shared/page-info.model';
|
|||||||
import { getMockRequestService } from '../../shared/mocks/mock-request.service';
|
import { getMockRequestService } from '../../shared/mocks/mock-request.service';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
RegistryBitstreamformatsSuccessResponse,
|
|
||||||
RegistryMetadatafieldsSuccessResponse,
|
RegistryMetadatafieldsSuccessResponse,
|
||||||
RegistryMetadataschemasSuccessResponse,
|
RegistryMetadataschemasSuccessResponse,
|
||||||
RestResponse
|
RestResponse
|
||||||
@@ -20,7 +19,6 @@ import {
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { RegistryMetadataschemasResponse } from './registry-metadataschemas-response.model';
|
import { RegistryMetadataschemasResponse } from './registry-metadataschemas-response.model';
|
||||||
import { RegistryMetadatafieldsResponse } from './registry-metadatafields-response.model';
|
import { RegistryMetadatafieldsResponse } from './registry-metadatafields-response.model';
|
||||||
import { RegistryBitstreamformatsResponse } from './registry-bitstreamformats-response.model';
|
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
import { Store, StoreModule } from '@ngrx/store';
|
import { Store, StoreModule } from '@ngrx/store';
|
||||||
import { MockStore } from '../../shared/testing/mock-store';
|
import { MockStore } from '../../shared/testing/mock-store';
|
||||||
@@ -42,7 +40,7 @@ import {
|
|||||||
import { MetadataSchema } from '../metadata/metadataschema.model';
|
import { MetadataSchema } from '../metadata/metadataschema.model';
|
||||||
import { MetadataField } from '../metadata/metadatafield.model';
|
import { MetadataField } from '../metadata/metadatafield.model';
|
||||||
|
|
||||||
@Component({ template: '' })
|
@Component({template: ''})
|
||||||
class DummyComponent {
|
class DummyComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +117,7 @@ describe('RegistryService', () => {
|
|||||||
toRemoteDataObservable: (requestEntryObs: Observable<RequestEntry>, payloadObs: Observable<any>) => {
|
toRemoteDataObservable: (requestEntryObs: Observable<RequestEntry>, payloadObs: Observable<any>) => {
|
||||||
return observableCombineLatest(requestEntryObs,
|
return observableCombineLatest(requestEntryObs,
|
||||||
payloadObs).pipe(map(([req, pay]) => {
|
payloadObs).pipe(map(([req, pay]) => {
|
||||||
return { req, pay };
|
return {req, pay};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -135,11 +133,11 @@ describe('RegistryService', () => {
|
|||||||
DummyComponent
|
DummyComponent
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: RequestService, useValue: getMockRequestService() },
|
{provide: RequestService, useValue: getMockRequestService()},
|
||||||
{ provide: RemoteDataBuildService, useValue: rdbStub },
|
{provide: RemoteDataBuildService, useValue: rdbStub},
|
||||||
{ provide: HALEndpointService, useValue: halServiceStub },
|
{provide: HALEndpointService, useValue: halServiceStub},
|
||||||
{ provide: Store, useClass: MockStore },
|
{provide: Store, useClass: MockStore},
|
||||||
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
|
{provide: NotificationsService, useValue: new NotificationsServiceStub()},
|
||||||
RegistryService
|
RegistryService
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@@ -154,7 +152,7 @@ describe('RegistryService', () => {
|
|||||||
page: pageInfo
|
page: pageInfo
|
||||||
});
|
});
|
||||||
const response = new RegistryMetadataschemasSuccessResponse(queryResponse, 200, 'OK', pageInfo);
|
const response = new RegistryMetadataschemasSuccessResponse(queryResponse, 200, 'OK', pageInfo);
|
||||||
const responseEntry = Object.assign(new RequestEntry(), { response: response });
|
const responseEntry = Object.assign(new RequestEntry(), {response: response});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
(registryService as any).requestService.getByHref.and.returnValue(observableOf(responseEntry));
|
(registryService as any).requestService.getByHref.and.returnValue(observableOf(responseEntry));
|
||||||
@@ -183,7 +181,7 @@ describe('RegistryService', () => {
|
|||||||
page: pageInfo
|
page: pageInfo
|
||||||
});
|
});
|
||||||
const response = new RegistryMetadataschemasSuccessResponse(queryResponse, 200, 'OK', pageInfo);
|
const response = new RegistryMetadataschemasSuccessResponse(queryResponse, 200, 'OK', pageInfo);
|
||||||
const responseEntry = Object.assign(new RequestEntry(), { response: response });
|
const responseEntry = Object.assign(new RequestEntry(), {response: response});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
(registryService as any).requestService.getByHref.and.returnValue(observableOf(responseEntry));
|
(registryService as any).requestService.getByHref.and.returnValue(observableOf(responseEntry));
|
||||||
@@ -212,7 +210,7 @@ describe('RegistryService', () => {
|
|||||||
page: pageInfo
|
page: pageInfo
|
||||||
});
|
});
|
||||||
const response = new RegistryMetadatafieldsSuccessResponse(queryResponse, 200, 'OK', pageInfo);
|
const response = new RegistryMetadatafieldsSuccessResponse(queryResponse, 200, 'OK', pageInfo);
|
||||||
const responseEntry = Object.assign(new RequestEntry(), { response: response });
|
const responseEntry = Object.assign(new RequestEntry(), {response: response});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
(registryService as any).requestService.getByHref.and.returnValue(observableOf(responseEntry));
|
(registryService as any).requestService.getByHref.and.returnValue(observableOf(responseEntry));
|
||||||
@@ -235,35 +233,6 @@ describe('RegistryService', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when requesting bitstreamformats', () => {
|
|
||||||
const queryResponse = Object.assign(new RegistryBitstreamformatsResponse(), {
|
|
||||||
bitstreamformats: mockFieldsList,
|
|
||||||
page: pageInfo
|
|
||||||
});
|
|
||||||
const response = new RegistryBitstreamformatsSuccessResponse(queryResponse, 200, 'OK', pageInfo);
|
|
||||||
const responseEntry = Object.assign(new RequestEntry(), { response: response });
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
(registryService as any).requestService.getByHref.and.returnValue(observableOf(responseEntry));
|
|
||||||
/* tslint:disable:no-empty */
|
|
||||||
registryService.getBitstreamFormats(pagination).subscribe((value) => {
|
|
||||||
});
|
|
||||||
/* tslint:enable:no-empty */
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call getEndpoint on the halService', () => {
|
|
||||||
expect((registryService as any).halService.getEndpoint).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should send out the request on the request service', () => {
|
|
||||||
expect((registryService as any).requestService.configure).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call getByHref on the request service with the correct request url', () => {
|
|
||||||
expect((registryService as any).requestService.getByHref).toHaveBeenCalledWith(endpointWithParams);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when dispatching to the store', () => {
|
describe('when dispatching to the store', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
spyOn(mockStore, 'dispatch');
|
spyOn(mockStore, 'dispatch');
|
||||||
@@ -276,7 +245,7 @@ describe('RegistryService', () => {
|
|||||||
|
|
||||||
it('should dispatch a MetadataRegistryEditSchemaAction with the correct schema', () => {
|
it('should dispatch a MetadataRegistryEditSchemaAction with the correct schema', () => {
|
||||||
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistryEditSchemaAction(mockSchemasList[0]));
|
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistryEditSchemaAction(mockSchemasList[0]));
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when calling cancelEditMetadataSchema', () => {
|
describe('when calling cancelEditMetadataSchema', () => {
|
||||||
@@ -286,7 +255,7 @@ describe('RegistryService', () => {
|
|||||||
|
|
||||||
it('should dispatch a MetadataRegistryCancelSchemaAction', () => {
|
it('should dispatch a MetadataRegistryCancelSchemaAction', () => {
|
||||||
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistryCancelSchemaAction());
|
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistryCancelSchemaAction());
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when calling selectMetadataSchema', () => {
|
describe('when calling selectMetadataSchema', () => {
|
||||||
@@ -296,7 +265,7 @@ describe('RegistryService', () => {
|
|||||||
|
|
||||||
it('should dispatch a MetadataRegistrySelectSchemaAction with the correct schema', () => {
|
it('should dispatch a MetadataRegistrySelectSchemaAction with the correct schema', () => {
|
||||||
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistrySelectSchemaAction(mockSchemasList[0]));
|
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistrySelectSchemaAction(mockSchemasList[0]));
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when calling deselectMetadataSchema', () => {
|
describe('when calling deselectMetadataSchema', () => {
|
||||||
@@ -306,7 +275,7 @@ describe('RegistryService', () => {
|
|||||||
|
|
||||||
it('should dispatch a MetadataRegistryDeselectSchemaAction with the correct schema', () => {
|
it('should dispatch a MetadataRegistryDeselectSchemaAction with the correct schema', () => {
|
||||||
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistryDeselectSchemaAction(mockSchemasList[0]));
|
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistryDeselectSchemaAction(mockSchemasList[0]));
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when calling deselectAllMetadataSchema', () => {
|
describe('when calling deselectAllMetadataSchema', () => {
|
||||||
@@ -316,7 +285,7 @@ describe('RegistryService', () => {
|
|||||||
|
|
||||||
it('should dispatch a MetadataRegistryDeselectAllSchemaAction', () => {
|
it('should dispatch a MetadataRegistryDeselectAllSchemaAction', () => {
|
||||||
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistryDeselectAllSchemaAction());
|
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistryDeselectAllSchemaAction());
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when calling editMetadataField', () => {
|
describe('when calling editMetadataField', () => {
|
||||||
@@ -326,7 +295,7 @@ describe('RegistryService', () => {
|
|||||||
|
|
||||||
it('should dispatch a MetadataRegistryEditFieldAction with the correct Field', () => {
|
it('should dispatch a MetadataRegistryEditFieldAction with the correct Field', () => {
|
||||||
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistryEditFieldAction(mockFieldsList[0]));
|
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistryEditFieldAction(mockFieldsList[0]));
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when calling cancelEditMetadataField', () => {
|
describe('when calling cancelEditMetadataField', () => {
|
||||||
@@ -336,7 +305,7 @@ describe('RegistryService', () => {
|
|||||||
|
|
||||||
it('should dispatch a MetadataRegistryCancelFieldAction', () => {
|
it('should dispatch a MetadataRegistryCancelFieldAction', () => {
|
||||||
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistryCancelFieldAction());
|
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistryCancelFieldAction());
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when calling selectMetadataField', () => {
|
describe('when calling selectMetadataField', () => {
|
||||||
@@ -346,7 +315,7 @@ describe('RegistryService', () => {
|
|||||||
|
|
||||||
it('should dispatch a MetadataRegistrySelectFieldAction with the correct Field', () => {
|
it('should dispatch a MetadataRegistrySelectFieldAction with the correct Field', () => {
|
||||||
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistrySelectFieldAction(mockFieldsList[0]));
|
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistrySelectFieldAction(mockFieldsList[0]));
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when calling deselectMetadataField', () => {
|
describe('when calling deselectMetadataField', () => {
|
||||||
@@ -356,7 +325,7 @@ describe('RegistryService', () => {
|
|||||||
|
|
||||||
it('should dispatch a MetadataRegistryDeselectFieldAction with the correct Field', () => {
|
it('should dispatch a MetadataRegistryDeselectFieldAction with the correct Field', () => {
|
||||||
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistryDeselectFieldAction(mockFieldsList[0]));
|
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistryDeselectFieldAction(mockFieldsList[0]));
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when calling deselectAllMetadataField', () => {
|
describe('when calling deselectAllMetadataField', () => {
|
||||||
@@ -366,7 +335,7 @@ describe('RegistryService', () => {
|
|||||||
|
|
||||||
it('should dispatch a MetadataRegistryDeselectAllFieldAction', () => {
|
it('should dispatch a MetadataRegistryDeselectAllFieldAction', () => {
|
||||||
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistryDeselectAllFieldAction());
|
expect(mockStore.dispatch).toHaveBeenCalledWith(new MetadataRegistryDeselectAllFieldAction());
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -409,7 +378,7 @@ describe('RegistryService', () => {
|
|||||||
result.subscribe((response: RestResponse) => {
|
result.subscribe((response: RestResponse) => {
|
||||||
expect(response.isSuccessful).toBe(true);
|
expect(response.isSuccessful).toBe(true);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when deleteMetadataField is called', () => {
|
describe('when deleteMetadataField is called', () => {
|
||||||
@@ -423,7 +392,7 @@ describe('RegistryService', () => {
|
|||||||
result.subscribe((response: RestResponse) => {
|
result.subscribe((response: RestResponse) => {
|
||||||
expect(response.isSuccessful).toBe(true);
|
expect(response.isSuccessful).toBe(true);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when clearMetadataSchemaRequests is called', () => {
|
describe('when clearMetadataSchemaRequests is called', () => {
|
||||||
|
@@ -5,13 +5,13 @@ import { PaginatedList } from '../data/paginated-list';
|
|||||||
import { PageInfo } from '../shared/page-info.model';
|
import { PageInfo } from '../shared/page-info.model';
|
||||||
import { MetadataSchema } from '../metadata/metadataschema.model';
|
import { MetadataSchema } from '../metadata/metadataschema.model';
|
||||||
import { MetadataField } from '../metadata/metadatafield.model';
|
import { MetadataField } from '../metadata/metadatafield.model';
|
||||||
import { BitstreamFormat } from './mock-bitstream-format.model';
|
|
||||||
import {
|
import {
|
||||||
CreateMetadataFieldRequest,
|
CreateMetadataFieldRequest,
|
||||||
CreateMetadataSchemaRequest,
|
CreateMetadataSchemaRequest,
|
||||||
DeleteRequest,
|
DeleteRequest,
|
||||||
GetRequest,
|
GetRequest,
|
||||||
RestRequest, UpdateMetadataFieldRequest,
|
RestRequest,
|
||||||
|
UpdateMetadataFieldRequest,
|
||||||
UpdateMetadataSchemaRequest
|
UpdateMetadataSchemaRequest
|
||||||
} from '../data/request.models';
|
} from '../data/request.models';
|
||||||
import { GenericConstructor } from '../shared/generic-constructor';
|
import { GenericConstructor } from '../shared/generic-constructor';
|
||||||
@@ -21,24 +21,19 @@ import { RemoteDataBuildService } from '../cache/builders/remote-data-build.serv
|
|||||||
import { RequestService } from '../data/request.service';
|
import { RequestService } from '../data/request.service';
|
||||||
import { RegistryMetadataschemasResponse } from './registry-metadataschemas-response.model';
|
import { RegistryMetadataschemasResponse } from './registry-metadataschemas-response.model';
|
||||||
import {
|
import {
|
||||||
ErrorResponse, MetadatafieldSuccessResponse, MetadataschemaSuccessResponse,
|
MetadatafieldSuccessResponse,
|
||||||
RegistryBitstreamformatsSuccessResponse,
|
MetadataschemaSuccessResponse,
|
||||||
RegistryMetadatafieldsSuccessResponse,
|
RegistryMetadatafieldsSuccessResponse,
|
||||||
RegistryMetadataschemasSuccessResponse, RestResponse
|
RegistryMetadataschemasSuccessResponse,
|
||||||
|
RestResponse
|
||||||
} from '../cache/response.models';
|
} from '../cache/response.models';
|
||||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
import { RegistryMetadatafieldsResponseParsingService } from '../data/registry-metadatafields-response-parsing.service';
|
import { RegistryMetadatafieldsResponseParsingService } from '../data/registry-metadatafields-response-parsing.service';
|
||||||
import { RegistryMetadatafieldsResponse } from './registry-metadatafields-response.model';
|
import { RegistryMetadatafieldsResponse } from './registry-metadatafields-response.model';
|
||||||
import { hasValue, hasNoValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util';
|
import { hasNoValue, hasValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util';
|
||||||
import { URLCombiner } from '../url-combiner/url-combiner';
|
import { URLCombiner } from '../url-combiner/url-combiner';
|
||||||
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
|
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
|
||||||
import { RegistryBitstreamformatsResponseParsingService } from '../data/registry-bitstreamformats-response-parsing.service';
|
import { configureRequest, getResponseFromEntry } from '../shared/operators';
|
||||||
import { RegistryBitstreamformatsResponse } from './registry-bitstreamformats-response.model';
|
|
||||||
import {
|
|
||||||
configureRequest,
|
|
||||||
getResponseFromEntry,
|
|
||||||
getSucceededRemoteData
|
|
||||||
} from '../shared/operators';
|
|
||||||
import { createSelector, select, Store } from '@ngrx/store';
|
import { createSelector, select, Store } from '@ngrx/store';
|
||||||
import { AppState } from '../../app.reducer';
|
import { AppState } from '../../app.reducer';
|
||||||
import { MetadataRegistryState } from '../../+admin/admin-registries/metadata-registry/metadata-registry.reducers';
|
import { MetadataRegistryState } from '../../+admin/admin-registries/metadata-registry/metadata-registry.reducers';
|
||||||
@@ -54,7 +49,7 @@ import {
|
|||||||
MetadataRegistrySelectFieldAction,
|
MetadataRegistrySelectFieldAction,
|
||||||
MetadataRegistrySelectSchemaAction
|
MetadataRegistrySelectSchemaAction
|
||||||
} from '../../+admin/admin-registries/metadata-registry/metadata-registry.actions';
|
} from '../../+admin/admin-registries/metadata-registry/metadata-registry.actions';
|
||||||
import { distinctUntilChanged, flatMap, map, switchMap, take, tap } from 'rxjs/operators';
|
import { distinctUntilChanged, flatMap, map, take, tap } from 'rxjs/operators';
|
||||||
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
||||||
import { NormalizedObjectFactory } from '../cache/models/normalized-object-factory';
|
import { NormalizedObjectFactory } from '../cache/models/normalized-object-factory';
|
||||||
import { ResourceType } from '../shared/resource-type';
|
import { ResourceType } from '../shared/resource-type';
|
||||||
@@ -76,7 +71,8 @@ export class RegistryService {
|
|||||||
|
|
||||||
private metadataSchemasPath = 'metadataschemas';
|
private metadataSchemasPath = 'metadataschemas';
|
||||||
private metadataFieldsPath = 'metadatafields';
|
private metadataFieldsPath = 'metadatafields';
|
||||||
private bitstreamFormatsPath = 'bitstreamformats';
|
|
||||||
|
// private bitstreamFormatsPath = 'bitstreamformats';
|
||||||
|
|
||||||
constructor(protected requestService: RequestService,
|
constructor(protected requestService: RequestService,
|
||||||
private rdb: RemoteDataBuildService,
|
private rdb: RemoteDataBuildService,
|
||||||
@@ -181,7 +177,7 @@ export class RegistryService {
|
|||||||
*/
|
*/
|
||||||
public getAllMetadataFields(pagination?: PaginationComponentOptions): Observable<RemoteData<PaginatedList<MetadataField>>> {
|
public getAllMetadataFields(pagination?: PaginationComponentOptions): Observable<RemoteData<PaginatedList<MetadataField>>> {
|
||||||
if (hasNoValue(pagination)) {
|
if (hasNoValue(pagination)) {
|
||||||
pagination = { currentPage: 1, pageSize: 10000 } as any;
|
pagination = {currentPage: 1, pageSize: 10000} as any;
|
||||||
}
|
}
|
||||||
const requestObs = this.getMetadataFieldsRequestObs(pagination);
|
const requestObs = this.getMetadataFieldsRequestObs(pagination);
|
||||||
|
|
||||||
@@ -215,36 +211,6 @@ export class RegistryService {
|
|||||||
return this.rdb.toRemoteDataObservable(requestEntryObs, payloadObs);
|
return this.rdb.toRemoteDataObservable(requestEntryObs, payloadObs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getBitstreamFormats(pagination: PaginationComponentOptions): Observable<RemoteData<PaginatedList<BitstreamFormat>>> {
|
|
||||||
const requestObs = this.getBitstreamFormatsRequestObs(pagination);
|
|
||||||
|
|
||||||
const requestEntryObs = requestObs.pipe(
|
|
||||||
flatMap((request: RestRequest) => this.requestService.getByHref(request.href))
|
|
||||||
);
|
|
||||||
|
|
||||||
const rbrObs: Observable<RegistryBitstreamformatsResponse> = requestEntryObs.pipe(
|
|
||||||
getResponseFromEntry(),
|
|
||||||
map((response: RegistryBitstreamformatsSuccessResponse) => response.bitstreamformatsResponse)
|
|
||||||
);
|
|
||||||
|
|
||||||
const bitstreamformatsObs: Observable<BitstreamFormat[]> = rbrObs.pipe(
|
|
||||||
map((rbr: RegistryBitstreamformatsResponse) => rbr.bitstreamformats)
|
|
||||||
);
|
|
||||||
|
|
||||||
const pageInfoObs: Observable<PageInfo> = requestEntryObs.pipe(
|
|
||||||
getResponseFromEntry(),
|
|
||||||
map((response: RegistryBitstreamformatsSuccessResponse) => response.pageInfo)
|
|
||||||
);
|
|
||||||
|
|
||||||
const payloadObs = observableCombineLatest(bitstreamformatsObs, pageInfoObs).pipe(
|
|
||||||
map(([bitstreamformats, pageInfo]) => {
|
|
||||||
return new PaginatedList(pageInfo, bitstreamformats);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return this.rdb.toRemoteDataObservable(requestEntryObs, payloadObs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getMetadataSchemasRequestObs(pagination: PaginationComponentOptions): Observable<RestRequest> {
|
public getMetadataSchemasRequestObs(pagination: PaginationComponentOptions): Observable<RestRequest> {
|
||||||
return this.halService.getEndpoint(this.metadataSchemasPath).pipe(
|
return this.halService.getEndpoint(this.metadataSchemasPath).pipe(
|
||||||
map((url: string) => {
|
map((url: string) => {
|
||||||
@@ -307,26 +273,6 @@ export class RegistryService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getBitstreamFormatsRequestObs(pagination: PaginationComponentOptions): Observable<RestRequest> {
|
|
||||||
return this.halService.getEndpoint(this.bitstreamFormatsPath).pipe(
|
|
||||||
map((url: string) => {
|
|
||||||
const args: string[] = [];
|
|
||||||
args.push(`size=${pagination.pageSize}`);
|
|
||||||
args.push(`page=${pagination.currentPage - 1}`);
|
|
||||||
if (isNotEmpty(args)) {
|
|
||||||
url = new URLCombiner(url, `?${args.join('&')}`).toString();
|
|
||||||
}
|
|
||||||
const request = new GetRequest(this.requestService.generateRequestId(), url);
|
|
||||||
return Object.assign(request, {
|
|
||||||
getResponseParser(): GenericConstructor<ResponseParsingService> {
|
|
||||||
return RegistryBitstreamformatsResponseParsingService;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
tap((request: RestRequest) => this.requestService.configure(request)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public editMetadataSchema(schema: MetadataSchema) {
|
public editMetadataSchema(schema: MetadataSchema) {
|
||||||
this.store.dispatch(new MetadataRegistryEditSchemaAction(schema));
|
this.store.dispatch(new MetadataRegistryEditSchemaAction(schema));
|
||||||
}
|
}
|
||||||
@@ -340,15 +286,15 @@ export class RegistryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public selectMetadataSchema(schema: MetadataSchema) {
|
public selectMetadataSchema(schema: MetadataSchema) {
|
||||||
this.store.dispatch(new MetadataRegistrySelectSchemaAction(schema))
|
this.store.dispatch(new MetadataRegistrySelectSchemaAction(schema));
|
||||||
}
|
}
|
||||||
|
|
||||||
public deselectMetadataSchema(schema: MetadataSchema) {
|
public deselectMetadataSchema(schema: MetadataSchema) {
|
||||||
this.store.dispatch(new MetadataRegistryDeselectSchemaAction(schema))
|
this.store.dispatch(new MetadataRegistryDeselectSchemaAction(schema));
|
||||||
}
|
}
|
||||||
|
|
||||||
public deselectAllMetadataSchema() {
|
public deselectAllMetadataSchema() {
|
||||||
this.store.dispatch(new MetadataRegistryDeselectAllSchemaAction())
|
this.store.dispatch(new MetadataRegistryDeselectAllSchemaAction());
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSelectedMetadataSchemas(): Observable<MetadataSchema[]> {
|
public getSelectedMetadataSchemas(): Observable<MetadataSchema[]> {
|
||||||
@@ -368,15 +314,15 @@ export class RegistryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public selectMetadataField(field: MetadataField) {
|
public selectMetadataField(field: MetadataField) {
|
||||||
this.store.dispatch(new MetadataRegistrySelectFieldAction(field))
|
this.store.dispatch(new MetadataRegistrySelectFieldAction(field));
|
||||||
}
|
}
|
||||||
|
|
||||||
public deselectMetadataField(field: MetadataField) {
|
public deselectMetadataField(field: MetadataField) {
|
||||||
this.store.dispatch(new MetadataRegistryDeselectFieldAction(field))
|
this.store.dispatch(new MetadataRegistryDeselectFieldAction(field));
|
||||||
}
|
}
|
||||||
|
|
||||||
public deselectAllMetadataField() {
|
public deselectAllMetadataField() {
|
||||||
this.store.dispatch(new MetadataRegistryDeselectAllFieldAction())
|
this.store.dispatch(new MetadataRegistryDeselectAllFieldAction());
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSelectedMetadataFields(): Observable<MetadataField[]> {
|
public getSelectedMetadataFields(): Observable<MetadataField[]> {
|
||||||
@@ -431,7 +377,7 @@ export class RegistryService {
|
|||||||
this.notificationsService.error('Server Error:', (response as any).errorMessage, new NotificationOptions(-1));
|
this.notificationsService.error('Server Error:', (response as any).errorMessage, new NotificationOptions(-1));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.showNotifications(true, isUpdate, false, { prefix: schema.prefix });
|
this.showNotifications(true, isUpdate, false, {prefix: schema.prefix});
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@@ -451,7 +397,7 @@ export class RegistryService {
|
|||||||
public clearMetadataSchemaRequests(): Observable<string> {
|
public clearMetadataSchemaRequests(): Observable<string> {
|
||||||
return this.halService.getEndpoint(this.metadataSchemasPath).pipe(
|
return this.halService.getEndpoint(this.metadataSchemasPath).pipe(
|
||||||
tap((href: string) => this.requestService.removeByHrefSubstring(href))
|
tap((href: string) => this.requestService.removeByHrefSubstring(href))
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -501,7 +447,7 @@ export class RegistryService {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const fieldString = `${field.schema.prefix}.${field.element}${field.qualifier ? `.${field.qualifier}` : ''}`;
|
const fieldString = `${field.schema.prefix}.${field.element}${field.qualifier ? `.${field.qualifier}` : ''}`;
|
||||||
this.showNotifications(true, isUpdate, true, { field: fieldString });
|
this.showNotifications(true, isUpdate, true, {field: fieldString});
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@@ -521,7 +467,7 @@ export class RegistryService {
|
|||||||
public clearMetadataFieldRequests(): Observable<string> {
|
public clearMetadataFieldRequests(): Observable<string> {
|
||||||
return this.halService.getEndpoint(this.metadataFieldsPath).pipe(
|
return this.halService.getEndpoint(this.metadataFieldsPath).pipe(
|
||||||
tap((href: string) => this.requestService.removeByHrefSubstring(href))
|
tap((href: string) => this.requestService.removeByHrefSubstring(href))
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private delete(path: string, id: number): Observable<RestResponse> {
|
private delete(path: string, id: number): Observable<RestResponse> {
|
||||||
@@ -557,9 +503,9 @@ export class RegistryService {
|
|||||||
);
|
);
|
||||||
messages.subscribe(([head, content]) => {
|
messages.subscribe(([head, content]) => {
|
||||||
if (success) {
|
if (success) {
|
||||||
this.notificationsService.success(head, content)
|
this.notificationsService.success(head, content);
|
||||||
} else {
|
} else {
|
||||||
this.notificationsService.error(head, content)
|
this.notificationsService.error(head, content);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
5
src/app/core/shared/bitstream-format-support-level.ts
Normal file
5
src/app/core/shared/bitstream-format-support-level.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export enum BitstreamFormatSupportLevel {
|
||||||
|
Known = 'KNOWN',
|
||||||
|
Unknown = 'UNKNOWN',
|
||||||
|
Supported = 'SUPPORTED'
|
||||||
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
import { CacheableObject } from '../cache/object-cache.reducer';
|
import { CacheableObject } from '../cache/object-cache.reducer';
|
||||||
import { ResourceType } from './resource-type';
|
import { ResourceType } from './resource-type';
|
||||||
|
import { BitstreamFormatSupportLevel } from './bitstream-format-support-level';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model class for a Bitstream Format
|
* Model class for a Bitstream Format
|
||||||
@@ -25,7 +25,7 @@ export class BitstreamFormat implements CacheableObject {
|
|||||||
/**
|
/**
|
||||||
* The level of support the system offers for this Bitstream Format
|
* The level of support the system offers for this Bitstream Format
|
||||||
*/
|
*/
|
||||||
supportLevel: number;
|
supportLevel: BitstreamFormatSupportLevel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if the Bitstream Format is used to store system information, rather than the content of items in the system
|
* True if the Bitstream Format is used to store system information, rather than the content of items in the system
|
||||||
@@ -35,7 +35,7 @@ export class BitstreamFormat implements CacheableObject {
|
|||||||
/**
|
/**
|
||||||
* String representing this Bitstream Format's file extension
|
* String representing this Bitstream Format's file extension
|
||||||
*/
|
*/
|
||||||
extensions: string;
|
extensions: string[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The link to the rest endpoint where this Bitstream Format can be found
|
* The link to the rest endpoint where this Bitstream Format can be found
|
||||||
@@ -52,4 +52,11 @@ export class BitstreamFormat implements CacheableObject {
|
|||||||
*/
|
*/
|
||||||
uuid: string;
|
uuid: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifier for this Bitstream Format
|
||||||
|
* Note that this ID is unique for bitstream formats,
|
||||||
|
* but might not be unique across different object types
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
<ng-container #componentViewContainer></ng-container>
|
<ng-container #componentViewContainer></ng-container>
|
||||||
|
|
||||||
<small *ngIf="hasHint" class="text-muted" [innerHTML]="model.hint" [ngClass]="getClass('element', 'hint')"></small>
|
<small *ngIf="hasHint" class="text-muted" [innerHTML]="model.hint | translate" [ngClass]="getClass('element', 'hint')"></small>
|
||||||
|
|
||||||
<div *ngIf="showErrorMessages" [ngClass]="[getClass('element', 'errors'), getClass('grid', 'errors')]">
|
<div *ngIf="showErrorMessages" [ngClass]="[getClass('element', 'errors'), getClass('grid', 'errors')]">
|
||||||
<small *ngFor="let message of errorMessages" class="invalid-feedback d-block">{{ message | translate:model.validators }}</small>
|
<small *ngFor="let message of errorMessages" class="invalid-feedback d-block">{{ message | translate:model.validators }}</small>
|
||||||
|
Reference in New Issue
Block a user