Skip to content

Commit 3b884fe

Browse files
author
Mattia Vianelli
committed
Merge remote-tracking branch 'remotes/origin/main' into DURACOM-235
2 parents e3b19e4 + d61d688 commit 3b884fe

32 files changed

Lines changed: 605 additions & 130 deletions
Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +0,0 @@
1-
:host {
2-
::ng-deep {
3-
.switch {
4-
position: absolute;
5-
top: calc(var(--bs-spacer) * 2.5);
6-
}
7-
}
8-
}
9-
:host ::ng-deep ds-dynamic-form-control-container > div > label {
10-
margin-top: 1.75rem;
11-
}
12-

src/app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component.ts

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,35 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnIni
22
import { Bitstream } from '../../core/shared/bitstream.model';
33
import { ActivatedRoute, Router } from '@angular/router';
44
import { filter, map, switchMap, tap } from 'rxjs/operators';
5-
import { combineLatest, combineLatest as observableCombineLatest, Observable, of as observableOf, Subscription } from 'rxjs';
6-
import { DynamicFormControlModel, DynamicFormGroupModel, DynamicFormLayout, DynamicFormService, DynamicInputModel, DynamicSelectModel } from '@ng-dynamic-forms/core';
5+
import {
6+
combineLatest,
7+
combineLatest as observableCombineLatest,
8+
Observable,
9+
of as observableOf,
10+
Subscription
11+
} from 'rxjs';
12+
import {
13+
DynamicFormControlModel,
14+
DynamicFormGroupModel,
15+
DynamicFormLayout,
16+
DynamicFormService,
17+
DynamicInputModel,
18+
DynamicSelectModel
19+
} from '@ng-dynamic-forms/core';
720
import { UntypedFormGroup } from '@angular/forms';
821
import { TranslateService } from '@ngx-translate/core';
9-
import { DynamicCustomSwitchModel } from '../../shared/form/builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.model';
22+
import {
23+
DynamicCustomSwitchModel
24+
} from '../../shared/form/builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.model';
1025
import cloneDeep from 'lodash/cloneDeep';
1126
import { BitstreamDataService } from '../../core/data/bitstream-data.service';
12-
import { getAllSucceededRemoteDataPayload, getFirstCompletedRemoteData, getFirstSucceededRemoteData, getFirstSucceededRemoteDataPayload, getRemoteDataPayload } from '../../core/shared/operators';
27+
import {
28+
getAllSucceededRemoteDataPayload,
29+
getFirstCompletedRemoteData,
30+
getFirstSucceededRemoteData,
31+
getFirstSucceededRemoteDataPayload,
32+
getRemoteDataPayload
33+
} from '../../core/shared/operators';
1334
import { NotificationsService } from '../../shared/notifications/notifications.service';
1435
import { BitstreamFormatDataService } from '../../core/data/bitstream-format-data.service';
1536
import { BitstreamFormat } from '../../core/shared/bitstream-format.model';
@@ -245,7 +266,7 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
245266
/**
246267
* All input models in a simple array for easier iterations
247268
*/
248-
inputModels = [this.fileNameModel, this.primaryBitstreamModel, this.descriptionModel, this.selectedFormatModel,
269+
inputModels = [this.primaryBitstreamModel, this.fileNameModel, this.descriptionModel, this.selectedFormatModel,
249270
this.newFormatModel];
250271

251272
/**
@@ -256,8 +277,8 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
256277
new DynamicFormGroupModel({
257278
id: 'fileNamePrimaryContainer',
258279
group: [
259-
this.fileNameModel,
260-
this.primaryBitstreamModel
280+
this.primaryBitstreamModel,
281+
this.fileNameModel
261282
]
262283
}, {
263284
grid: {
@@ -295,7 +316,10 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
295316
},
296317
primaryBitstream: {
297318
grid: {
298-
host: 'col col-sm-4 d-inline-block switch border-0'
319+
container: 'col-12'
320+
},
321+
element: {
322+
container: 'text-right'
299323
}
300324
},
301325
description: {

src/app/core/data/bitstream-data.service.spec.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ import { NotificationsService } from '../../shared/notifications/notifications.s
2121
import objectContaining = jasmine.objectContaining;
2222
import { RemoteData } from './remote-data';
2323
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
24+
import { BundleDataService } from './bundle-data.service';
25+
import { ItemMock } from 'src/app/shared/mocks/item.mock';
26+
import { createFailedRemoteDataObject, createSuccessfulRemoteDataObject } from 'src/app/shared/remote-data.utils';
27+
import { Bundle } from '../shared/bundle.model';
28+
import { cold } from 'jasmine-marbles';
2429

2530
describe('BitstreamDataService', () => {
2631
let service: BitstreamDataService;
@@ -29,6 +34,7 @@ describe('BitstreamDataService', () => {
2934
let halService: HALEndpointService;
3035
let bitstreamFormatService: BitstreamFormatDataService;
3136
let rdbService: RemoteDataBuildService;
37+
let bundleDataService: BundleDataService;
3238
const bitstreamFormatHref = 'rest-api/bitstreamformats';
3339

3440
const bitstream1 = Object.assign(new Bitstream(), {
@@ -62,6 +68,7 @@ describe('BitstreamDataService', () => {
6268
bitstreamFormatService = jasmine.createSpyObj('bistreamFormatService', {
6369
getBrowseEndpoint: observableOf(bitstreamFormatHref)
6470
});
71+
6572
rdbService = getMockRemoteDataBuildService();
6673

6774
TestBed.configureTestingModule({
@@ -76,6 +83,7 @@ describe('BitstreamDataService', () => {
7683
],
7784
});
7885
service = TestBed.inject(BitstreamDataService);
86+
bundleDataService = TestBed.inject(BundleDataService);
7987
});
8088

8189
describe('composition', () => {
@@ -118,6 +126,32 @@ describe('BitstreamDataService', () => {
118126
expect(service.invalidateByHref).toHaveBeenCalledWith('fake-bitstream1-self');
119127
});
120128

129+
describe('findPrimaryBitstreamByItemAndName', () => {
130+
it('should return primary bitstream', () => {
131+
const exprected$ = cold('(a|)', { a: bitstream1} );
132+
const bundle = Object.assign(new Bundle(), {
133+
primaryBitstream: observableOf(createSuccessfulRemoteDataObject(bitstream1)),
134+
});
135+
spyOn(bundleDataService, 'findByItemAndName').and.returnValue(observableOf(createSuccessfulRemoteDataObject(bundle)));
136+
expect(service.findPrimaryBitstreamByItemAndName(ItemMock, 'ORIGINAL')).toBeObservable(exprected$);
137+
});
138+
139+
it('should return null if primary bitstream has not be succeeded ', () => {
140+
const exprected$ = cold('(a|)', { a: null} );
141+
const bundle = Object.assign(new Bundle(), {
142+
primaryBitstream: observableOf(createFailedRemoteDataObject()),
143+
});
144+
spyOn(bundleDataService, 'findByItemAndName').and.returnValue(observableOf(createSuccessfulRemoteDataObject(bundle)));
145+
expect(service.findPrimaryBitstreamByItemAndName(ItemMock, 'ORIGINAL')).toBeObservable(exprected$);
146+
});
147+
148+
it('should return EMPTY if nothing where found', () => {
149+
const exprected$ = cold('(|)', {} );
150+
spyOn(bundleDataService, 'findByItemAndName').and.returnValue(observableOf(createFailedRemoteDataObject<Bundle>()));
151+
expect(service.findPrimaryBitstreamByItemAndName(ItemMock, 'ORIGINAL')).toBeObservable(exprected$);
152+
});
153+
});
154+
121155
it('should be able to delete multiple bitstreams', () => {
122156
service.removeMultiple([bitstream1, bitstream2]);
123157

src/app/core/data/bitstream-data.service.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { HttpHeaders } from '@angular/common/http';
22
import { Injectable } from '@angular/core';
3-
import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
3+
import { combineLatest as observableCombineLatest, Observable, EMPTY } from 'rxjs';
44
import { find, map, switchMap, take } from 'rxjs/operators';
55
import { hasValue } from '../../shared/empty.util';
6-
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
6+
import { FollowLinkConfig, followLink } from '../../shared/utils/follow-link-config.model';
77
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
88
import { ObjectCacheService } from '../cache/object-cache.service';
99
import { Bitstream } from '../shared/bitstream.model';
@@ -34,6 +34,7 @@ import { NoContent } from '../shared/NoContent.model';
3434
import { IdentifiableDataService } from './base/identifiable-data.service';
3535
import { dataService } from './base/data-service.decorator';
3636
import { Operation, RemoveOperation } from 'fast-json-patch';
37+
import { getFirstCompletedRemoteData } from '../shared/operators';
3738

3839
/**
3940
* A service to retrieve {@link Bitstream}s from the REST API
@@ -201,6 +202,37 @@ export class BitstreamDataService extends IdentifiableDataService<Bitstream> imp
201202
return this.searchData.getSearchByHref(searchMethod, options, ...linksToFollow);
202203
}
203204

205+
206+
/**
207+
*
208+
* Make a request to get primary bitstream
209+
* in all current use cases, and having it simplifies this method
210+
*
211+
* @param item the {@link Item} the {@link Bundle} is a part of
212+
* @param bundleName the name of the {@link Bundle} we want to find
213+
* {@link Bitstream}s for
214+
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
215+
* no valid cached version. Defaults to true
216+
* @param reRequestOnStale Whether or not the request should automatically be re-
217+
* requested after the response becomes stale
218+
* @return {Observable<Bitstream | null>}
219+
* Return an observable that constains primary bitstream information or null
220+
*/
221+
public findPrimaryBitstreamByItemAndName(item: Item, bundleName: string, useCachedVersionIfAvailable = true, reRequestOnStale = true): Observable<Bitstream | null> {
222+
return this.bundleService.findByItemAndName(item, bundleName, useCachedVersionIfAvailable, reRequestOnStale, followLink('primaryBitstream')).pipe(
223+
getFirstCompletedRemoteData(),
224+
switchMap((rd: RemoteData<Bundle>) => {
225+
if (!rd.hasSucceeded) {
226+
return EMPTY;
227+
}
228+
return rd.payload.primaryBitstream.pipe(
229+
getFirstCompletedRemoteData(),
230+
map((rdb: RemoteData<Bitstream>) => rdb.hasSucceeded ? rdb.payload : null)
231+
);
232+
})
233+
);
234+
}
235+
204236
/**
205237
* Make a new FindListRequest with given search method
206238
*

src/app/core/submission/models/workspaceitem-section-upload.model.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ import { WorkspaceitemSectionUploadFileObject } from './workspaceitem-section-up
44
* An interface to represent submission's upload section data.
55
*/
66
export interface WorkspaceitemSectionUploadObject {
7-
7+
/**
8+
* Primary bitstream flag
9+
*/
10+
primary: string | null;
811
/**
912
* A list of [[WorkspaceitemSectionUploadFileObject]]
1013
*/

src/app/item-page/simple/field-components/file-section/file-section.component.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
<ds-metadata-field-wrapper *ngIf="bitstreams?.length > 0" [label]="label | translate">
33
<div class="file-section">
44
<ds-themed-file-download-link *ngFor="let file of bitstreams; let last=last;" [bitstream]="file" [item]="item">
5-
<span>{{ dsoNameService.getName(file) }}</span>
5+
<span>
6+
<span *ngIf="primaryBitsreamId === file.id" class="badge badge-primary">{{ 'item.page.bitstreams.primary' | translate }}</span>
7+
{{ dsoNameService.getName(file) }}
8+
</span>
69
<span> ({{(file?.sizeBytes) | dsFileSize }})</span>
710
<span *ngIf="!last" innerHTML="{{separator}}"></span>
811
</ds-themed-file-download-link>

src/app/item-page/simple/field-components/file-section/file-section.component.spec.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ describe('FileSectionComponent', () => {
2525
let fixture: ComponentFixture<FileSectionComponent>;
2626

2727
const bitstreamDataService = jasmine.createSpyObj('bitstreamDataService', {
28-
findAllByItemAndBundleName: createSuccessfulRemoteDataObject$(createPaginatedList([]))
28+
findAllByItemAndBundleName: createSuccessfulRemoteDataObject$(createPaginatedList([])),
29+
findPrimaryBitstreamByItemAndName: observableOf(null)
2930
});
3031

3132
const mockBitstream: Bitstream = Object.assign(new Bitstream(),
@@ -81,6 +82,20 @@ describe('FileSectionComponent', () => {
8182
fixture.detectChanges();
8283
}));
8384

85+
it('should set the id of primary bitstream', () => {
86+
comp.primaryBitsreamId = undefined;
87+
bitstreamDataService.findPrimaryBitstreamByItemAndName.and.returnValue(observableOf(mockBitstream));
88+
comp.ngOnInit();
89+
expect(comp.primaryBitsreamId).toBe(mockBitstream.id);
90+
});
91+
92+
it('should not set the id of primary bitstream', () => {
93+
comp.primaryBitsreamId = undefined;
94+
bitstreamDataService.findPrimaryBitstreamByItemAndName.and.returnValue(observableOf(null));
95+
comp.ngOnInit();
96+
expect(comp.primaryBitsreamId).toBeUndefined();
97+
});
98+
8499
describe('when the bitstreams are loading', () => {
85100
beforeEach(() => {
86101
comp.bitstreams$.next([mockBitstream]);

src/app/item-page/simple/field-components/file-section/file-section.component.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ export class FileSectionComponent implements OnInit {
3939

4040
pageSize: number;
4141

42+
primaryBitsreamId: string;
43+
4244
constructor(
4345
protected bitstreamDataService: BitstreamDataService,
4446
protected notificationsService: NotificationsService,
@@ -50,9 +52,19 @@ export class FileSectionComponent implements OnInit {
5052
}
5153

5254
ngOnInit(): void {
55+
this.getPrimaryBitstreamId();
5356
this.getNextPage();
5457
}
5558

59+
private getPrimaryBitstreamId() {
60+
this.bitstreamDataService.findPrimaryBitstreamByItemAndName(this.item, 'ORIGINAL', true, true).subscribe((primaryBitstream: Bitstream | null) => {
61+
if (!primaryBitstream) {
62+
return;
63+
}
64+
this.primaryBitsreamId = primaryBitstream?.id;
65+
});
66+
}
67+
5668
/**
5769
* This method will retrieve the next page of Bitstreams from the external BitstreamDataService call.
5870
* It'll retrieve the currentPage from the class variables and it'll add the next page of bitstreams with the

src/app/shared/form/builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<div [formGroup]="group" class="form-check custom-control custom-switch" [class.disabled]="model.disabled">
1+
<div [formGroup]="group" [ngClass]="getClass('element', 'container')" class="form-check custom-control custom-switch" [class.disabled]="model.disabled">
22
<input type="checkbox" class="form-check-input custom-control-input"
33
[checked]="model.checked"
44
[class.is-invalid]="showErrorMessages"
@@ -14,7 +14,7 @@
1414
(change)="onChange($event)"
1515
(focus)="onFocus($event)"/>
1616
<label class="form-check-label custom-control-label" [for]="bindId && model.id">
17-
<span [innerHTML]="model.label"
17+
<span [innerHTML]="model.label | translate"
1818
[ngClass]="[getClass('element', 'label'), getClass('grid', 'label')]"></span>
1919
</label>
2020
</div>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
div.custom-switch {
2+
&.custom-control-right {
3+
margin-left: 0;
4+
margin-right: 0;
5+
6+
&::after {
7+
right: -1.5rem;
8+
left: auto;
9+
}
10+
11+
&::before {
12+
right: -2.35rem;
13+
left: auto;
14+
}
15+
}
16+
}

0 commit comments

Comments
 (0)