mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-12 12:33:07 +00:00
CC License Submission Step
This commit is contained in:
@@ -145,6 +145,8 @@ import { Version } from './shared/version.model';
|
|||||||
import { VersionHistory } from './shared/version-history.model';
|
import { VersionHistory } from './shared/version-history.model';
|
||||||
import { WorkflowActionDataService } from './data/workflow-action-data.service';
|
import { WorkflowActionDataService } from './data/workflow-action-data.service';
|
||||||
import { WorkflowAction } from './tasks/models/workflow-action-object.model';
|
import { WorkflowAction } from './tasks/models/workflow-action-object.model';
|
||||||
|
import { SubmissionCcLicensesDataService } from './data/submission-cc-licenses-data.service';
|
||||||
|
import { SubmissionCcLicence } from './shared/submission-cc-license.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When not in production, endpoint responses can be mocked for testing purposes
|
* When not in production, endpoint responses can be mocked for testing purposes
|
||||||
@@ -214,6 +216,7 @@ const PROVIDERS = [
|
|||||||
BrowseItemsResponseParsingService,
|
BrowseItemsResponseParsingService,
|
||||||
BrowseService,
|
BrowseService,
|
||||||
ConfigResponseParsingService,
|
ConfigResponseParsingService,
|
||||||
|
SubmissionCcLicensesDataService,
|
||||||
SubmissionDefinitionsConfigService,
|
SubmissionDefinitionsConfigService,
|
||||||
SubmissionFormsConfigService,
|
SubmissionFormsConfigService,
|
||||||
SubmissionRestService,
|
SubmissionRestService,
|
||||||
@@ -296,6 +299,7 @@ export const models =
|
|||||||
License,
|
License,
|
||||||
WorkflowItem,
|
WorkflowItem,
|
||||||
WorkspaceItem,
|
WorkspaceItem,
|
||||||
|
SubmissionCcLicence,
|
||||||
SubmissionDefinitionsModel,
|
SubmissionDefinitionsModel,
|
||||||
SubmissionFormsModel,
|
SubmissionFormsModel,
|
||||||
SubmissionSectionModel,
|
SubmissionSectionModel,
|
||||||
|
34
src/app/core/data/submission-cc-licenses-data.service.ts
Normal file
34
src/app/core/data/submission-cc-licenses-data.service.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { dataService } from '../cache/builders/build-decorators';
|
||||||
|
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||||
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
|
import { CoreState } from '../core.reducers';
|
||||||
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
|
import { DataService } from './data.service';
|
||||||
|
import { RequestService } from './request.service';
|
||||||
|
import { SUBMISSION_CC_LICENSE } from '../shared/submission-cc-licences.resource-type';
|
||||||
|
import { SubmissionCcLicence } from '../shared/submission-cc-license.model';
|
||||||
|
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
@dataService(SUBMISSION_CC_LICENSE)
|
||||||
|
export class SubmissionCcLicensesDataService extends DataService<SubmissionCcLicence> {
|
||||||
|
|
||||||
|
protected linkPath = 'submissioncclicenses';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected comparator: DefaultChangeAnalyzer<SubmissionCcLicence>,
|
||||||
|
protected halService: HALEndpointService,
|
||||||
|
protected http: HttpClient,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected objectCache: ObjectCacheService,
|
||||||
|
protected rdbService: RemoteDataBuildService,
|
||||||
|
protected requestService: RequestService,
|
||||||
|
protected store: Store<CoreState>,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
}
|
@@ -1,4 +1,5 @@
|
|||||||
import { HALLink } from './hal-link.model';
|
import { HALLink } from './hal-link.model';
|
||||||
|
import { deserialize } from 'cerialize';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents HAL resources.
|
* Represents HAL resources.
|
||||||
@@ -6,10 +7,13 @@ import { HALLink } from './hal-link.model';
|
|||||||
* A HAL resource has a _links section with at least a self link.
|
* A HAL resource has a _links section with at least a self link.
|
||||||
*/
|
*/
|
||||||
export class HALResource {
|
export class HALResource {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link HALLink}s for this {@link HALResource}
|
* The {@link HALLink}s for this {@link HALResource}
|
||||||
*/
|
*/
|
||||||
|
@deserialize
|
||||||
_links: {
|
_links: {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link HALLink} that refers to this {@link HALResource}
|
* The {@link HALLink} that refers to this {@link HALResource}
|
||||||
*/
|
*/
|
||||||
|
@@ -0,0 +1,9 @@
|
|||||||
|
import { ResourceType } from './resource-type';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The resource type for License
|
||||||
|
*
|
||||||
|
* Needs to be in a separate file to prevent circular
|
||||||
|
* dependencies in webpack.
|
||||||
|
*/
|
||||||
|
export const SUBMISSION_CC_LICENSE = new ResourceType('submissioncclicense');
|
35
src/app/core/shared/submission-cc-license.model.ts
Normal file
35
src/app/core/shared/submission-cc-license.model.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { autoserialize, inheritSerialization } from 'cerialize';
|
||||||
|
import { typedObject } from '../cache/builders/build-decorators';
|
||||||
|
import { excludeFromEquals } from '../utilities/equals.decorators';
|
||||||
|
import { ResourceType } from './resource-type';
|
||||||
|
import { HALResource } from './hal-resource.model';
|
||||||
|
import { SUBMISSION_CC_LICENSE } from './submission-cc-licences.resource-type';
|
||||||
|
|
||||||
|
@typedObject
|
||||||
|
@inheritSerialization(HALResource)
|
||||||
|
export class SubmissionCcLicence extends HALResource {
|
||||||
|
|
||||||
|
static type = SUBMISSION_CC_LICENSE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object type
|
||||||
|
*/
|
||||||
|
@excludeFromEquals
|
||||||
|
@autoserialize
|
||||||
|
type: ResourceType;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
fields: Array<{
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
description: string;
|
||||||
|
enums: Array<{
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
description: string;
|
||||||
|
}>;
|
||||||
|
}>;
|
||||||
|
}
|
@@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* An interface to represent the submission's creative commons license section data.
|
||||||
|
*/
|
||||||
|
export interface WorkspaceitemSectionCcLicenseObject {
|
||||||
|
ccLicense: {
|
||||||
|
name: string;
|
||||||
|
fields: {
|
||||||
|
[field: string]: string;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@@ -1,6 +1,7 @@
|
|||||||
import { WorkspaceitemSectionFormObject } from './workspaceitem-section-form.model';
|
import { WorkspaceitemSectionFormObject } from './workspaceitem-section-form.model';
|
||||||
import { WorkspaceitemSectionLicenseObject } from './workspaceitem-section-license.model';
|
import { WorkspaceitemSectionLicenseObject } from './workspaceitem-section-license.model';
|
||||||
import { WorkspaceitemSectionUploadObject } from './workspaceitem-section-upload.model';
|
import { WorkspaceitemSectionUploadObject } from './workspaceitem-section-upload.model';
|
||||||
|
import { WorkspaceitemSectionCcLicenseObject } from './workspaceitem-section-cc-license.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface to represent submission's section object.
|
* An interface to represent submission's section object.
|
||||||
@@ -17,4 +18,5 @@ export type WorkspaceitemSectionDataType
|
|||||||
= WorkspaceitemSectionUploadObject
|
= WorkspaceitemSectionUploadObject
|
||||||
| WorkspaceitemSectionFormObject
|
| WorkspaceitemSectionFormObject
|
||||||
| WorkspaceitemSectionLicenseObject
|
| WorkspaceitemSectionLicenseObject
|
||||||
|
| WorkspaceitemSectionCcLicenseObject
|
||||||
| string;
|
| string;
|
||||||
|
31
src/app/shared/ds-select/ds-select.component.html
Normal file
31
src/app/shared/ds-select/ds-select.component.html
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<div>
|
||||||
|
|
||||||
|
<div ngbDropdown class="btn-group" (openChange)="toggled.emit($event)">
|
||||||
|
|
||||||
|
<div class="input-group-prepend" *ngIf="label">
|
||||||
|
<span id="dsSelectMenuLabel" class="input-group-text">
|
||||||
|
{{ label | translate }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button aria-describedby="dsSelectMenuLabel"
|
||||||
|
id="dsSelectMenuButton"
|
||||||
|
class="btn btn-outline-primary selection"
|
||||||
|
(blur)="close.emit($event)"
|
||||||
|
(click)="close.emit($event)"
|
||||||
|
[disabled]="disabled"
|
||||||
|
ngbDropdownToggle>
|
||||||
|
<ng-content select=".selection"></ng-content>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div ngbDropdownMenu
|
||||||
|
class="dropdown-menu"
|
||||||
|
id="dsSelectDropdownMenu"
|
||||||
|
aria-labelledby="dsSelectMenuButton">
|
||||||
|
<div aria-labelledby="dropdownMenuButton">
|
||||||
|
<ng-content select=".menu"></ng-content>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
25
src/app/shared/ds-select/ds-select.component.spec.ts
Normal file
25
src/app/shared/ds-select/ds-select.component.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { DsSelectComponent } from './ds-select.component';
|
||||||
|
|
||||||
|
describe('DsSelectComponent', () => {
|
||||||
|
let component: DsSelectComponent;
|
||||||
|
let fixture: ComponentFixture<DsSelectComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ DsSelectComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(DsSelectComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
36
src/app/shared/ds-select/ds-select.component.ts
Normal file
36
src/app/shared/ds-select/ds-select.component.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component which represent a DSpace dropdown selector.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-select',
|
||||||
|
templateUrl: './ds-select.component.html',
|
||||||
|
styleUrls: ['./ds-select.component.css']
|
||||||
|
})
|
||||||
|
export class DsSelectComponent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An optional label for the dropdown selector.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
label: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the dropdown selector is disabled.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
disabled: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits an event when the dropdown selector is opened or closed.
|
||||||
|
*/
|
||||||
|
@Output()
|
||||||
|
toggled = new EventEmitter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits an event when the dropdown selector or closed.
|
||||||
|
*/
|
||||||
|
@Output()
|
||||||
|
close = new EventEmitter();
|
||||||
|
}
|
@@ -193,6 +193,7 @@ import { ModifyItemOverviewComponent } from '../+item-page/edit-item-page/modify
|
|||||||
import { ClaimedTaskActionsLoaderComponent } from './mydspace-actions/claimed-task/switcher/claimed-task-actions-loader.component';
|
import { ClaimedTaskActionsLoaderComponent } from './mydspace-actions/claimed-task/switcher/claimed-task-actions-loader.component';
|
||||||
import { ClaimedTaskActionsDirective } from './mydspace-actions/claimed-task/switcher/claimed-task-actions.directive';
|
import { ClaimedTaskActionsDirective } from './mydspace-actions/claimed-task/switcher/claimed-task-actions.directive';
|
||||||
import { ClaimedTaskActionsEditMetadataComponent } from './mydspace-actions/claimed-task/edit-metadata/claimed-task-actions-edit-metadata.component';
|
import { ClaimedTaskActionsEditMetadataComponent } from './mydspace-actions/claimed-task/edit-metadata/claimed-task-actions-edit-metadata.component';
|
||||||
|
import { DsSelectComponent } from './ds-select/ds-select.component';
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
||||||
@@ -269,6 +270,7 @@ const COMPONENTS = [
|
|||||||
DsDynamicFormGroupComponent,
|
DsDynamicFormGroupComponent,
|
||||||
DsDynamicFormArrayComponent,
|
DsDynamicFormArrayComponent,
|
||||||
DsDatePickerInlineComponent,
|
DsDatePickerInlineComponent,
|
||||||
|
DsSelectComponent,
|
||||||
ErrorComponent,
|
ErrorComponent,
|
||||||
FormComponent,
|
FormComponent,
|
||||||
LangSwitchComponent,
|
LangSwitchComponent,
|
||||||
|
@@ -0,0 +1,114 @@
|
|||||||
|
<div class="mb-2 ccLicense-select">
|
||||||
|
<ds-select
|
||||||
|
[disabled]="!submissionCcLicenses"
|
||||||
|
[label]="'submission.sections.ccLicense.type'">
|
||||||
|
|
||||||
|
<ng-container class="selection">
|
||||||
|
<span *ngIf="!submissionCcLicenses">
|
||||||
|
<i class='fas fa-circle-notch fa-spin'></i>
|
||||||
|
</span>
|
||||||
|
<span *ngIf="getSelectedCcLicense()">
|
||||||
|
{{ getSelectedCcLicense().name }}
|
||||||
|
</span>
|
||||||
|
<span *ngIf="submissionCcLicenses && !getSelectedCcLicense()">
|
||||||
|
{{ 'submission.sections.ccLicense.select' | translate }}
|
||||||
|
</span>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container class="menu">
|
||||||
|
<button *ngIf="submissionCcLicenses?.length == 0"
|
||||||
|
class="dropdown-item disabled">
|
||||||
|
{{ 'submission.sections.ccLicense.none' | translate }}
|
||||||
|
</button>
|
||||||
|
<button *ngFor="let license of submissionCcLicenses"
|
||||||
|
class="dropdown-item"
|
||||||
|
(click)="select(license)">
|
||||||
|
{{ license.name }}
|
||||||
|
</button>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
</ds-select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-container *ngIf="getSelectedCcLicense()">
|
||||||
|
|
||||||
|
<div *ngFor="let field of getSelectedCcLicense().fields"
|
||||||
|
class="mb-2">
|
||||||
|
|
||||||
|
<div class="d-flex flex-row mb-2">
|
||||||
|
<div class="label {{ field.id }}">
|
||||||
|
{{ field.label }}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="btn btn-outline-info btn-sm ml-2"
|
||||||
|
(click)="openInfoModal(infoModal)">
|
||||||
|
<i class="fas fa-question"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-template #infoModal>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<div class="modal-header">
|
||||||
|
<div>
|
||||||
|
<h4>
|
||||||
|
{{ field.label }}
|
||||||
|
</h4>
|
||||||
|
<div [innerHTML]="field.description"></div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="close"
|
||||||
|
(click)="closeInfoModal()" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<div *ngFor="let value of field.enums"
|
||||||
|
class="mb-2">
|
||||||
|
<h5>
|
||||||
|
{{ value.label }}
|
||||||
|
</h5>
|
||||||
|
<div [innerHTML]="value.description"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ds-select *ngIf="field.enums?.length > 5">
|
||||||
|
<ng-container class="selection" *ngVar="getSelectedOption(getSelectedCcLicense(), field.id) as option">
|
||||||
|
<span *ngIf="option">
|
||||||
|
{{ option }}
|
||||||
|
</span>
|
||||||
|
<span *ngIf="!option">
|
||||||
|
{{ 'submission.sections.ccLicense.option.select' | translate }}
|
||||||
|
</span>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container class="menu">
|
||||||
|
<button *ngFor="let value of field.enums"
|
||||||
|
class="dropdown-item"
|
||||||
|
(click)="selectOption(getSelectedCcLicense(), field.id, value.label)">
|
||||||
|
{{ value.label }}
|
||||||
|
</button>
|
||||||
|
</ng-container>
|
||||||
|
</ds-select>
|
||||||
|
|
||||||
|
<ng-container *ngIf="field.enums?.length <= 5">
|
||||||
|
<div *ngFor="let value of field.enums"
|
||||||
|
class="d-flex flex-row m-2"
|
||||||
|
(click)="selectOption(getSelectedCcLicense(), field.id, value.label)">
|
||||||
|
<input type="radio"
|
||||||
|
title="{{ value.label }}"
|
||||||
|
class="mr-1"
|
||||||
|
[checked]="isSelectedOption(getSelectedCcLicense(), field.id, value.label)">
|
||||||
|
<div class="label">
|
||||||
|
{{ value.label }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</ng-container>
|
@@ -0,0 +1,220 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { SubmissionSectionCcLicensesComponent } from './submission-section-cc-licenses.component';
|
||||||
|
import { SUBMISSION_CC_LICENSE } from '../../core/shared/submission-cc-licences.resource-type';
|
||||||
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { SubmissionCcLicensesDataService } from '../../core/data/submission-cc-licenses-data.service';
|
||||||
|
import { DebugElement } from '@angular/core';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { SharedModule } from '../shared.module';
|
||||||
|
import { SectionsService } from '../../submission/sections/sections.service';
|
||||||
|
import { SectionDataObject } from '../../submission/sections/models/section-data.model';
|
||||||
|
import { SectionsType } from '../../submission/sections/sections-type';
|
||||||
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { PageInfo } from '../../core/shared/page-info.model';
|
||||||
|
import { PaginatedList } from '../../core/data/paginated-list';
|
||||||
|
import { SubmissionCcLicence } from '../../core/shared/submission-cc-license.model';
|
||||||
|
import { cold } from 'jasmine-marbles';
|
||||||
|
|
||||||
|
describe('SubmissionSectionCcLicensesComponent', () => {
|
||||||
|
|
||||||
|
let component: SubmissionSectionCcLicensesComponent;
|
||||||
|
let fixture: ComponentFixture<SubmissionSectionCcLicensesComponent>;
|
||||||
|
let de: DebugElement;
|
||||||
|
|
||||||
|
const sectionObject: SectionDataObject = {
|
||||||
|
config: 'test config',
|
||||||
|
mandatory: true,
|
||||||
|
data: {},
|
||||||
|
errors: [],
|
||||||
|
header: 'test header',
|
||||||
|
id: 'test section id',
|
||||||
|
sectionType: SectionsType.SubmissionForm
|
||||||
|
};
|
||||||
|
|
||||||
|
const submissionCcLicenses: SubmissionCcLicence[] = [
|
||||||
|
{
|
||||||
|
type: SUBMISSION_CC_LICENSE,
|
||||||
|
name: 'test license name 1',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
id: 'test-field-id-1a',
|
||||||
|
label: 'test field label 1a',
|
||||||
|
description: 'test field description 1a',
|
||||||
|
enums: [
|
||||||
|
{
|
||||||
|
id: 'test enum id 1a I',
|
||||||
|
label: 'test enum label 1a I',
|
||||||
|
description: 'test enum description 1a I',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'test enum id 1a II',
|
||||||
|
label: 'test enum label 1a II',
|
||||||
|
description: 'test enum description 1a II',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'test-field-id-1b',
|
||||||
|
label: 'test field label 1b',
|
||||||
|
description: 'test field description 1b',
|
||||||
|
enums: [
|
||||||
|
{
|
||||||
|
id: 'test enum id 1b I',
|
||||||
|
label: 'test enum label 1b I',
|
||||||
|
description: 'test enum description 1b I',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'test enum id 1b II',
|
||||||
|
label: 'test enum label 1b II',
|
||||||
|
description: 'test enum description 1b II',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
_links: {
|
||||||
|
self: {
|
||||||
|
href: 'test link',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: SUBMISSION_CC_LICENSE,
|
||||||
|
name: 'test license name 2',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
id: 'test-field-id-2a',
|
||||||
|
label: 'test field label 2a',
|
||||||
|
description: 'test field description 2a',
|
||||||
|
enums: [
|
||||||
|
{
|
||||||
|
id: 'test enum id 2a I',
|
||||||
|
label: 'test enum label 2a I',
|
||||||
|
description: 'test enum description 2a I'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'test enum id 2a II',
|
||||||
|
label: 'test enum label 2a II',
|
||||||
|
description: 'test enum description 2a II'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'test-field-id-2b',
|
||||||
|
label: 'test field label 2b',
|
||||||
|
description: 'test field description 2b',
|
||||||
|
enums: [
|
||||||
|
{
|
||||||
|
id: 'test enum id 2b I',
|
||||||
|
label: 'test enum label 2b I',
|
||||||
|
description: 'test enum description 2b I'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'test enum id 2b II',
|
||||||
|
label: 'test enum label 2b II',
|
||||||
|
description: 'test enum description 2b II'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
_links: {
|
||||||
|
self: {
|
||||||
|
href: 'test link',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const submissionCcLicensesDataService = {
|
||||||
|
findAll: () => observableOf(new RemoteData(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
undefined,
|
||||||
|
new PaginatedList(new PageInfo(), submissionCcLicenses),
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
|
||||||
|
const sectionService = {
|
||||||
|
getSectionState: () => observableOf(
|
||||||
|
{
|
||||||
|
data: {},
|
||||||
|
}
|
||||||
|
),
|
||||||
|
setSectionStatus: () => undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
SharedModule,
|
||||||
|
TranslateModule.forRoot(),
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
SubmissionSectionCcLicensesComponent,
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{provide: SubmissionCcLicensesDataService, useValue: submissionCcLicensesDataService},
|
||||||
|
{provide: SectionsService, useValue: sectionService},
|
||||||
|
{provide: 'collectionIdProvider', useValue: 'test collection id'},
|
||||||
|
{provide: 'sectionDataProvider', useValue: sectionObject},
|
||||||
|
{provide: 'submissionIdProvider', useValue: 'test submission id'},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(SubmissionSectionCcLicensesComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
de = fixture.debugElement;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a dropdown with the different cc licenses', () => {
|
||||||
|
expect(
|
||||||
|
de.query(By.css('.ccLicense-select ds-select .dropdown-menu button:nth-child(1)')).nativeElement.innerText
|
||||||
|
).toContain('test license name 1');
|
||||||
|
expect(
|
||||||
|
de.query(By.css('.ccLicense-select ds-select .dropdown-menu button:nth-child(2)')).nativeElement.innerText
|
||||||
|
).toContain('test license name 2');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when a license is selected', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
component.select(submissionCcLicenses[1]);
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display the selected cc license', () => {
|
||||||
|
expect(
|
||||||
|
de.query(By.css('.ccLicense-select ds-select button.selection')).nativeElement.innerText
|
||||||
|
).toContain('test license name 2');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display all field labels of the selected cc license only', () => {
|
||||||
|
expect(de.query(By.css('div.test-field-id-1a'))).toBeNull();
|
||||||
|
expect(de.query(By.css('div.test-field-id-1b'))).toBeNull();
|
||||||
|
expect(de.query(By.css('div.test-field-id-2a'))).toBeTruthy();
|
||||||
|
expect(de.query(By.css('div.test-field-id-2b'))).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have section status incomplete', () => {
|
||||||
|
expect(component.getSectionStatus()).toBeObservable(cold('(a|)', { a: false }));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when all options have a value selected', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const ccLicence = submissionCcLicenses[1];
|
||||||
|
component.selectOption(ccLicence, ccLicence.fields[0].id, ccLicence.fields[0].enums[1].label);
|
||||||
|
component.selectOption(ccLicence, ccLicence.fields[1].id, ccLicence.fields[1].enums[0].label);
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have section status complete', () => {
|
||||||
|
expect(component.getSectionStatus()).toBeObservable(cold('(a|)', { a: true }));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,197 @@
|
|||||||
|
import { Component, Inject } from '@angular/core';
|
||||||
|
import { Observable, of as observableOf, Subscription } from 'rxjs';
|
||||||
|
import { SubmissionCcLicence } from '../../core/shared/submission-cc-license.model';
|
||||||
|
import { getRemoteDataPayload, getSucceededRemoteData } from '../../core/shared/operators';
|
||||||
|
import { distinctUntilChanged, filter, map } from 'rxjs/operators';
|
||||||
|
import { SubmissionCcLicensesDataService } from '../../core/data/submission-cc-licenses-data.service';
|
||||||
|
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import { renderSectionFor } from '../../submission/sections/sections-decorator';
|
||||||
|
import { SectionsType } from '../../submission/sections/sections-type';
|
||||||
|
import { SectionModelComponent } from '../../submission/sections/models/section.model';
|
||||||
|
import { SectionDataObject } from '../../submission/sections/models/section-data.model';
|
||||||
|
import { SectionsService } from '../../submission/sections/sections.service';
|
||||||
|
import { WorkspaceitemSectionCcLicenseObject } from '../../core/submission/models/workspaceitem-section-cc-license.model';
|
||||||
|
import { JsonPatchOperationPathCombiner } from '../../core/json-patch/builder/json-patch-operation-path-combiner';
|
||||||
|
import { isNotEmpty } from '../empty.util';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component represents the submission section to select the Creative Commons license.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-submission-section-cc-licenses',
|
||||||
|
templateUrl: './submission-section-cc-licenses.component.html',
|
||||||
|
styleUrls: ['./submission-section-cc-licenses.component.css']
|
||||||
|
})
|
||||||
|
@renderSectionFor(SectionsType.CcLicense)
|
||||||
|
export class SubmissionSectionCcLicensesComponent extends SectionModelComponent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The form id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
public formId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if this section is loading
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
public isLoading = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The [JsonPatchOperationPathCombiner] object
|
||||||
|
* @type {JsonPatchOperationPathCombiner}
|
||||||
|
*/
|
||||||
|
protected pathCombiner: JsonPatchOperationPathCombiner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of Subscriptions this component subscribes to.
|
||||||
|
*/
|
||||||
|
private subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache of the available Creative Commons licenses.
|
||||||
|
*/
|
||||||
|
submissionCcLicenses: SubmissionCcLicence[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to NgbModal
|
||||||
|
*/
|
||||||
|
protected modalRef: NgbModalRef;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected modalService: NgbModal,
|
||||||
|
protected sectionService: SectionsService,
|
||||||
|
protected submissionCcLicensesDataService: SubmissionCcLicensesDataService,
|
||||||
|
@Inject('collectionIdProvider') public injectedCollectionId: string,
|
||||||
|
@Inject('sectionDataProvider') public injectedSectionData: SectionDataObject,
|
||||||
|
@Inject('submissionIdProvider') public injectedSubmissionId: string
|
||||||
|
) {
|
||||||
|
super(
|
||||||
|
injectedCollectionId,
|
||||||
|
injectedSectionData,
|
||||||
|
injectedSubmissionId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data of this section.
|
||||||
|
*/
|
||||||
|
get data(): WorkspaceitemSectionCcLicenseObject {
|
||||||
|
return this.sectionData.data as WorkspaceitemSectionCcLicenseObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select a given Creative Commons license.
|
||||||
|
* @param ccLicense the Creative Commons license to select.
|
||||||
|
*/
|
||||||
|
select(ccLicense: SubmissionCcLicence) {
|
||||||
|
if (!!this.getSelectedCcLicense() && this.getSelectedCcLicense().name === ccLicense.name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.data.ccLicense = {
|
||||||
|
name: ccLicense.name,
|
||||||
|
fields: {},
|
||||||
|
};
|
||||||
|
this.updateSectionStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the selected Creative Commons license.
|
||||||
|
*/
|
||||||
|
getSelectedCcLicense(): SubmissionCcLicence {
|
||||||
|
if (!this.submissionCcLicenses || !this.data.ccLicense) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this.submissionCcLicenses.filter((ccLicense) => ccLicense.name === this.data.ccLicense.name)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select an option for a given license field.
|
||||||
|
* @param ccLicense the related Creative Commons license.
|
||||||
|
* @param field the field for which to select an option.
|
||||||
|
* @param value the value of the selected option,.
|
||||||
|
*/
|
||||||
|
selectOption(ccLicense: SubmissionCcLicence, field: string, value: string) {
|
||||||
|
|
||||||
|
this.data.ccLicense.fields[field] = value;
|
||||||
|
this.updateSectionStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the selected option value for a given license field.
|
||||||
|
* @param ccLicense the related Creative Commons license.
|
||||||
|
* @param field the field for which to get the selected option value.
|
||||||
|
*/
|
||||||
|
getSelectedOption(ccLicense: SubmissionCcLicence, field: string): string {
|
||||||
|
return this.data.ccLicense.fields[field];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether a given option value is selected for a given license field.
|
||||||
|
* @param ccLicense the related Creative Commons license.
|
||||||
|
* @param field the field for which to check whether the option is selected.
|
||||||
|
* @param value the value for which to check whether it is selected.
|
||||||
|
*/
|
||||||
|
isSelectedOption(ccLicense: SubmissionCcLicence, field: string, value: string): boolean {
|
||||||
|
return this.getSelectedOption(ccLicense, field) === value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a given info modal.
|
||||||
|
* @param content the modal content.
|
||||||
|
*/
|
||||||
|
openInfoModal(content) {
|
||||||
|
this.modalRef = this.modalService.open(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the info modal.
|
||||||
|
*/
|
||||||
|
closeInfoModal() {
|
||||||
|
this.modalRef.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get section status
|
||||||
|
*
|
||||||
|
* @return Observable<boolean>
|
||||||
|
* the section status
|
||||||
|
*/
|
||||||
|
getSectionStatus(): Observable<boolean> {
|
||||||
|
return observableOf(
|
||||||
|
!!this.getSelectedCcLicense() && this.getSelectedCcLicense().fields.every(
|
||||||
|
(field) => !!this.getSelectedOption(this.getSelectedCcLicense(), field.id)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsubscribe from all subscriptions
|
||||||
|
*/
|
||||||
|
onSectionDestroy(): void {
|
||||||
|
this.subscriptions.forEach((subscription) => subscription.unsubscribe());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the section.
|
||||||
|
*/
|
||||||
|
onSectionInit(): void {
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.sectionService.getSectionState(this.submissionId, this.sectionData.id).pipe(
|
||||||
|
filter((sectionState) => {
|
||||||
|
return isNotEmpty(sectionState) && (isNotEmpty(sectionState.data) || isNotEmpty(sectionState.errors))
|
||||||
|
}),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
).subscribe((sectionState) => {
|
||||||
|
this.sectionData.data = sectionState.data;
|
||||||
|
}),
|
||||||
|
this.submissionCcLicensesDataService.findAll({elementsPerPage: Number.MAX_SAFE_INTEGER}).pipe(
|
||||||
|
getSucceededRemoteData(),
|
||||||
|
getRemoteDataPayload(),
|
||||||
|
map((list) => list.page),
|
||||||
|
).subscribe(
|
||||||
|
(licenses) => this.submissionCcLicenses = licenses
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,25 +1,19 @@
|
|||||||
<div>
|
<ds-select
|
||||||
<div ngbDropdown #collectionControls="ngbDropdown" class="btn-group input-group" (openChange)="toggled($event)">
|
[label]="'submission.sections.general.collection'"
|
||||||
<div class="input-group-prepend">
|
|
||||||
<span id="collectionControlsMenuLabel" class="input-group-text">
|
|
||||||
{{ 'submission.sections.general.collection' | translate }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<button aria-describedby="collectionControlsMenuLabel"
|
|
||||||
id="collectionControlsMenuButton"
|
|
||||||
class="btn btn-outline-primary"
|
|
||||||
(blur)="onClose()"
|
|
||||||
(click)="onClose()"
|
|
||||||
[disabled]="(disabled$ | async) || (processingChange$ | async)"
|
[disabled]="(disabled$ | async) || (processingChange$ | async)"
|
||||||
ngbDropdownToggle>
|
(toggled)="toggled($event)"
|
||||||
<span *ngIf="(processingChange$ | async)"><i class='fas fa-circle-notch fa-spin'></i></span>
|
(close)="onClose()">
|
||||||
<span *ngIf="!(processingChange$ | async)">{{ selectedCollectionName$ | async }}</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div ngbDropdownMenu
|
<ng-container class="selection">
|
||||||
class="dropdown-menu"
|
<span *ngIf="(processingChange$ | async)">
|
||||||
id="collectionControlsDropdownMenu"
|
<i class='fas fa-circle-notch fa-spin'></i>
|
||||||
aria-labelledby="collectionControlsMenuButton">
|
</span>
|
||||||
|
<span *ngIf="!(processingChange$ | async)">
|
||||||
|
{{ selectedCollectionName$ | async }}
|
||||||
|
</span>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container class="menu">
|
||||||
<div class="form-group w-100 pr-2 pl-2">
|
<div class="form-group w-100 pr-2 pl-2">
|
||||||
<input *ngIf="searchField"
|
<input *ngIf="searchField"
|
||||||
type="search"
|
type="search"
|
||||||
@@ -45,6 +39,6 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ng-container>
|
||||||
</div>
|
|
||||||
</div>
|
</ds-select>
|
||||||
|
@@ -29,6 +29,7 @@ import { SubmissionSectionUploadAccessConditionsComponent } from './sections/upl
|
|||||||
import { SubmissionSubmitComponent } from './submit/submission-submit.component';
|
import { SubmissionSubmitComponent } from './submit/submission-submit.component';
|
||||||
import { storeModuleConfig } from '../app.reducer';
|
import { storeModuleConfig } from '../app.reducer';
|
||||||
import { CoreState } from '../core/core.reducers';
|
import { CoreState } from '../core/core.reducers';
|
||||||
|
import { SubmissionSectionCcLicensesComponent } from '../shared/submission-section-cc-licenses/submission-section-cc-licenses.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -44,8 +45,8 @@ import { CoreState } from '../core/core.reducers';
|
|||||||
SubmissionSectionUploadComponent,
|
SubmissionSectionUploadComponent,
|
||||||
SubmissionSectionformComponent,
|
SubmissionSectionformComponent,
|
||||||
SubmissionSectionLicenseComponent,
|
SubmissionSectionLicenseComponent,
|
||||||
|
SubmissionSectionCcLicensesComponent,
|
||||||
SectionsDirective,
|
SectionsDirective,
|
||||||
SubmissionSectionContainerComponent,
|
|
||||||
SubmissionEditComponent,
|
SubmissionEditComponent,
|
||||||
SubmissionFormSectionAddComponent,
|
SubmissionFormSectionAddComponent,
|
||||||
SubmissionFormCollectionComponent,
|
SubmissionFormCollectionComponent,
|
||||||
@@ -53,6 +54,7 @@ import { CoreState } from '../core/core.reducers';
|
|||||||
SubmissionFormFooterComponent,
|
SubmissionFormFooterComponent,
|
||||||
SubmissionSubmitComponent,
|
SubmissionSubmitComponent,
|
||||||
SubmissionUploadFilesComponent,
|
SubmissionUploadFilesComponent,
|
||||||
|
SubmissionSectionContainerComponent,
|
||||||
SubmissionSectionUploadFileComponent,
|
SubmissionSectionUploadFileComponent,
|
||||||
SubmissionSectionUploadFileEditComponent,
|
SubmissionSectionUploadFileEditComponent,
|
||||||
SubmissionSectionUploadFileViewComponent
|
SubmissionSectionUploadFileViewComponent
|
||||||
@@ -61,7 +63,9 @@ import { CoreState } from '../core/core.reducers';
|
|||||||
SubmissionSectionUploadComponent,
|
SubmissionSectionUploadComponent,
|
||||||
SubmissionSectionformComponent,
|
SubmissionSectionformComponent,
|
||||||
SubmissionSectionLicenseComponent,
|
SubmissionSectionLicenseComponent,
|
||||||
SubmissionSectionContainerComponent],
|
SubmissionSectionContainerComponent,
|
||||||
|
SubmissionSectionCcLicensesComponent,
|
||||||
|
],
|
||||||
exports: [
|
exports: [
|
||||||
SubmissionEditComponent,
|
SubmissionEditComponent,
|
||||||
SubmissionFormComponent,
|
SubmissionFormComponent,
|
||||||
|
@@ -2426,6 +2426,14 @@
|
|||||||
|
|
||||||
"submission.sections.describe.relationship-lookup.name-variant.notification.decline": "Use only for this submission",
|
"submission.sections.describe.relationship-lookup.name-variant.notification.decline": "Use only for this submission",
|
||||||
|
|
||||||
|
"submission.sections.ccLicense.type": "License Type",
|
||||||
|
|
||||||
|
"submission.sections.ccLicense.select": "Select a license…",
|
||||||
|
|
||||||
|
"submission.sections.ccLicense.none": "No licenses available",
|
||||||
|
|
||||||
|
"submission.sections.ccLicense.option.select": "Select an option…",
|
||||||
|
|
||||||
"submission.sections.general.add-more": "Add more",
|
"submission.sections.general.add-more": "Add more",
|
||||||
|
|
||||||
"submission.sections.general.collection": "Collection",
|
"submission.sections.general.collection": "Collection",
|
||||||
@@ -2456,7 +2464,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
"submission.sections.submit.progressbar.cclicense": "Creative commons license",
|
"submission.sections.submit.progressbar.CClicense": "Creative commons license",
|
||||||
|
|
||||||
"submission.sections.submit.progressbar.describe.recycle": "Recycle",
|
"submission.sections.submit.progressbar.describe.recycle": "Recycle",
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user