Skip to content

Commit ca4edf7

Browse files
Merge remote-tracking branch 'gitHub/main' into task/main/DURACOM-426
2 parents 837b47e + f3b7d30 commit ca4edf7

12 files changed

Lines changed: 2261 additions & 2299 deletions

File tree

package-lock.json

Lines changed: 1854 additions & 1743 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,22 +77,22 @@
7777
}
7878
},
7979
"dependencies": {
80-
"@angular/animations": "^20.3.14",
80+
"@angular/animations": "^20.3.16",
8181
"@angular/cdk": "^20.2.14",
82-
"@angular/common": "^20.3.14",
83-
"@angular/compiler": "^20.3.14",
84-
"@angular/core": "^20.3.14",
85-
"@angular/forms": "^20.3.14",
86-
"@angular/localize": "^20.3.14",
87-
"@angular/platform-browser": "^20.3.14",
88-
"@angular/platform-browser-dynamic": "^20.3.14",
89-
"@angular/platform-server": "^20.3.14",
90-
"@angular/router": "^20.3.14",
82+
"@angular/common": "^20.3.16",
83+
"@angular/compiler": "^20.3.16",
84+
"@angular/core": "^20.3.16",
85+
"@angular/forms": "^20.3.16",
86+
"@angular/localize": "^20.3.16",
87+
"@angular/platform-browser": "^20.3.16",
88+
"@angular/platform-browser-dynamic": "^20.3.16",
89+
"@angular/platform-server": "^20.3.16",
90+
"@angular/router": "^20.3.16",
9191
"@angular/ssr": "^20.3.10",
9292
"@kolkov/ngx-gallery": "^2.0.1",
9393
"@ng-bootstrap/ng-bootstrap": "^15.1.2",
94-
"@4science_ng-dynamic-forms/core": "^19.0.1",
95-
"@4science_ng-dynamic-forms/ui-ng-bootstrap": "^19.0.4",
94+
"@4science_ng-dynamic-forms/core": "^19.1.0",
95+
"@4science_ng-dynamic-forms/ui-ng-bootstrap": "^19.1.0",
9696
"@ngrx/effects": "^20.1.0",
9797
"@ngrx/router-store": "^20.1.0",
9898
"@ngrx/store": "^20.1.0",
@@ -161,7 +161,7 @@
161161
"@angular-eslint/schematics": "^20.7.0",
162162
"@angular-eslint/template-parser": "^20.6.0",
163163
"@angular-eslint/utils": "^20.7.0",
164-
"@angular/cli": "^20.3.12",
164+
"@angular/cli": "^20.3.15",
165165
"@angular/compiler-cli": "^20.3.12",
166166
"@cypress/schematic": "^1.5.0",
167167
"@fortawesome/fontawesome-free": "^6.7.2",
@@ -218,7 +218,7 @@
218218
"postcss-loader": "^4.0.3",
219219
"postcss-preset-env": "^7.4.2",
220220
"rimraf": "^6.1.2",
221-
"sass": "~1.94.2",
221+
"sass": "~1.97.3",
222222
"sass-loader": "^12.6.0",
223223
"sass-resources-loader": "^2.2.5",
224224
"ts-node": "^8.10.2",

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { By } from '@angular/platform-browser';
88
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
99
import { APP_CONFIG } from '@dspace/config/app-config.interface';
1010
import { BitstreamDataService } from '@dspace/core/data/bitstream-data.service';
11+
import { LocaleService } from '@dspace/core/locale/locale.service';
1112
import { NotificationsService } from '@dspace/core/notification-system/notifications.service';
1213
import { PaginationService } from '@dspace/core/pagination/pagination.service';
1314
import { Bitstream } from '@dspace/core/shared/bitstream.model';
@@ -37,6 +38,12 @@ import { FullFileSectionComponent } from './full-file-section.component';
3738
describe('FullFileSectionComponent', () => {
3839
let comp: FullFileSectionComponent;
3940
let fixture: ComponentFixture<FullFileSectionComponent>;
41+
let localeService: any;
42+
const languageList = ['en;q=1', 'de;q=0.8'];
43+
const mockLocaleService = jasmine.createSpyObj('LocaleService', {
44+
getCurrentLanguageCode: jasmine.createSpy('getCurrentLanguageCode'),
45+
getLanguageCodeList: of(languageList),
46+
});
4047

4148
const mockBitstream: Bitstream = Object.assign(new Bitstream(),
4249
{
@@ -93,6 +100,7 @@ describe('FullFileSectionComponent', () => {
93100
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
94101
{ provide: SearchConfigurationService, useValue: jasmine.createSpyObj(['getCurrentConfiguration']) },
95102
{ provide: PaginationService, useValue: paginationService },
103+
{ provide: LocaleService, useValue: mockLocaleService },
96104
{ provide: APP_CONFIG, useValue: environment },
97105
],
98106
schemas: [NO_ERRORS_SCHEMA],
@@ -104,6 +112,8 @@ describe('FullFileSectionComponent', () => {
104112
}));
105113

106114
beforeEach(waitForAsync(() => {
115+
localeService = TestBed.inject(LocaleService);
116+
localeService.getCurrentLanguageCode.and.returnValue(of('en'));
107117
fixture = TestBed.createComponent(FullFileSectionComponent);
108118
comp = fixture.componentInstance;
109119
fixture.detectChanges();

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { ActivatedRoute } from '@angular/router';
1010
import { APP_CONFIG } from '@dspace/config/app-config.interface';
1111
import { BitstreamDataService } from '@dspace/core/data/bitstream-data.service';
1212
import { APP_DATA_SERVICES_MAP } from '@dspace/core/data-services-map-type';
13+
import { LocaleService } from '@dspace/core/locale/locale.service';
1314
import { NotificationsService } from '@dspace/core/notification-system/notifications.service';
1415
import { Bitstream } from '@dspace/core/shared/bitstream.model';
1516
import { PageInfo } from '@dspace/core/shared/page-info.model';
@@ -38,6 +39,12 @@ import { FileSectionComponent } from './file-section.component';
3839
describe('FileSectionComponent', () => {
3940
let comp: FileSectionComponent;
4041
let fixture: ComponentFixture<FileSectionComponent>;
42+
let localeService: any;
43+
const languageList = ['en;q=1', 'de;q=0.8'];
44+
const mockLocaleService = jasmine.createSpyObj('LocaleService', {
45+
getCurrentLanguageCode: jasmine.createSpy('getCurrentLanguageCode'),
46+
getLanguageCodeList: of(languageList),
47+
});
4148

4249
const bitstreamDataService = jasmine.createSpyObj('bitstreamDataService', {
4350
findAllByItemAndBundleName: createSuccessfulRemoteDataObject$(createPaginatedList([])),
@@ -88,6 +95,7 @@ describe('FileSectionComponent', () => {
8895
{ provide: APP_CONFIG, useValue: environment },
8996
{ provide: ThemeService, useValue: getMockThemeService() },
9097
{ provide: ActivatedRoute, useValue: new ActivatedRouteStub() },
98+
{ provide: LocaleService, useValue: mockLocaleService },
9199
provideMockStore(),
92100
],
93101
schemas: [NO_ERRORS_SCHEMA],
@@ -103,6 +111,8 @@ describe('FileSectionComponent', () => {
103111
}));
104112

105113
beforeEach(waitForAsync(() => {
114+
localeService = TestBed.inject(LocaleService);
115+
localeService.getCurrentLanguageCode.and.returnValue(of('en'));
106116
fixture = TestBed.createComponent(FileSectionComponent);
107117
comp = fixture.componentInstance;
108118
fixture.detectChanges();

src/app/process-page/detail/process-detail.component.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { DSONameService } from '@dspace/core/breadcrumbs/dso-name.service';
2323
import { BitstreamDataService } from '@dspace/core/data/bitstream-data.service';
2424
import { PaginatedList } from '@dspace/core/data/paginated-list.model';
2525
import { ProcessDataService } from '@dspace/core/data/processes/process-data.service';
26+
import { LocaleService } from '@dspace/core/locale/locale.service';
2627
import { NotificationsService } from '@dspace/core/notification-system/notifications.service';
2728
import { Process } from '@dspace/core/processes/process.model';
2829
import { Bitstream } from '@dspace/core/shared/bitstream.model';
@@ -60,6 +61,12 @@ describe('ProcessDetailComponent', () => {
6061
let router: RouterStub;
6162
let modalService;
6263
let notificationsService: NotificationsServiceStub;
64+
let localeService: any;
65+
const languageList = ['en;q=1', 'de;q=0.8'];
66+
const mockLocaleService = jasmine.createSpyObj('LocaleService', {
67+
getCurrentLanguageCode: jasmine.createSpy('getCurrentLanguageCode'),
68+
getLanguageCodeList: of(languageList),
69+
});
6370

6471
let process: Process;
6572
let fileName: string;
@@ -169,6 +176,7 @@ describe('ProcessDetailComponent', () => {
169176
{ provide: NgbModal, useValue: modalService },
170177
{ provide: NotificationsService, useValue: notificationsService },
171178
{ provide: Router, useValue: router },
179+
{ provide: LocaleService, useValue: mockLocaleService },
172180
],
173181
schemas: [CUSTOM_ELEMENTS_SCHEMA],
174182
})
@@ -186,7 +194,10 @@ describe('ProcessDetailComponent', () => {
186194
beforeEach(() => {
187195
fixture = TestBed.createComponent(ProcessDetailComponent);
188196
component = fixture.componentInstance;
197+
localeService = TestBed.inject(LocaleService);
198+
localeService.getCurrentLanguageCode.and.returnValue(of('en'));
189199
});
200+
190201
afterEach(fakeAsync(() => {
191202
TestBed.resetTestingModule();
192203
fixture.destroy();

src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,15 @@
4949
</button>
5050
}
5151
<button class="dropdown-item collection-item text-truncate"
52+
[class.active]="selectedIndex === 0"
5253
(click)="onSelect(undefined); sdRef.close()" (mousedown)="onSelect(undefined); sdRef.close()"
5354
title="{{ 'dropdown.clear.tooltip' | translate }}" role="option"
5455
type="button">
5556
<i>{{ 'dropdown.clear' | translate }}</i>
5657
</button>
5758
@for (listEntry of optionsList; track listEntry; let i = $index) {
5859
<button class="dropdown-item collection-item text-truncate"
59-
[class.active]="i === selectedIndex"
60+
[class.active]="selectedIndex === (i + 1)"
6061
(keydown.enter)="onSelect(listEntry); sdRef.close()" (mousedown)="onSelect(listEntry); sdRef.close()"
6162
title="{{ inputFormatter(listEntry) }}" role="option" type="button"
6263
[attr.id]="inputFormatter(listEntry) === (currentValue|async) ? ('combobox_' + id + '_selected') : null">

src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom
156156
}
157157
}
158158

159-
loadOptions(fromInit: boolean) {
159+
loadOptions(fromInit: boolean, scrollAfterLoad: boolean = false) {
160160
this.loading = true;
161161
this.getDataFromService().pipe(
162162
getFirstSucceededRemoteDataPayload(),
@@ -174,7 +174,11 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom
174174
list.pageInfo.totalElements,
175175
list.pageInfo.totalPages,
176176
);
177-
this.selectedIndex = 0;
177+
178+
if (!fromInit) {
179+
this.setSelectedIndexToCurrentValue(scrollAfterLoad);
180+
}
181+
178182
this.cdr.detectChanges();
179183
});
180184
}
@@ -192,26 +196,60 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom
192196
if (!this.model.readOnly) {
193197
this.group.markAsUntouched();
194198
this.inputText = null;
195-
this.updatePageInfo(this.model.maxOptions, 1);
196-
this.loadOptions(false);
199+
200+
const pageSize = Math.min(this.pageInfo.totalElements, 200);
201+
this.updatePageInfo(pageSize, 1);
202+
203+
this.loadOptions(false, true);
204+
this.setSelectedIndexToCurrentValue(true);
197205
sdRef.open();
198206
}
199207
}
200208

209+
/**
210+
* Set the selectedIndex to match the current value when dropdown opens
211+
* @param shouldScroll Whether to scroll to the selected item after setting the index
212+
*/
213+
private setSelectedIndexToCurrentValue(shouldScroll: boolean = false): void {
214+
if (this.currentValue) {
215+
this.currentValue.pipe(take(1)).subscribe(currentVal => {
216+
if (currentVal && this.optionsList.length > 0) {
217+
const foundIndex = this.optionsList.findIndex(entry =>
218+
this.inputFormatter(entry) === currentVal,
219+
);
220+
this.selectedIndex = foundIndex >= 0 ? foundIndex + 1 : 0;
221+
} else {
222+
this.selectedIndex = 0;
223+
}
224+
225+
if (shouldScroll && this.selectedIndex > 0) {
226+
// Ensure DOM is updated before scrolling
227+
this.cdr.detectChanges();
228+
// Use setTimeout to ensure the active class is applied and rendered
229+
setTimeout(() => this.scrollToSelected(), 0);
230+
}
231+
});
232+
} else {
233+
this.selectedIndex = 0;
234+
}
235+
}
236+
201237
navigateDropdown(event: KeyboardEvent) {
238+
const totalItems = this.optionsList.length + 1;
239+
202240
if (event.key === 'ArrowDown') {
203-
this.selectedIndex = Math.min(this.selectedIndex + 1, this.optionsList.length - 1);
241+
this.selectedIndex = Math.min(this.selectedIndex + 1, totalItems - 1);
204242
} else if (event.key === 'ArrowUp') {
205243
this.selectedIndex = Math.max(this.selectedIndex - 1, 0);
206244
}
207245
this.scrollToSelected();
208246
}
209247

210248
scrollToSelected() {
211-
const dropdownItems = this.dropdownMenu.nativeElement.querySelectorAll('.dropdown-item');
249+
const dropdownItems = this.dropdownMenu.nativeElement.querySelectorAll('.dropdown-item:not(.disabled)');
212250
const selectedItem = dropdownItems[this.selectedIndex];
213251
if (selectedItem) {
214-
selectedItem.scrollIntoView({ block: 'nearest' });
252+
selectedItem.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
215253
}
216254
}
217255

@@ -227,7 +265,11 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom
227265
event.preventDefault();
228266
event.stopPropagation();
229267
if (sdRef.isOpen()) {
230-
this.onSelect(this.optionsList[this.selectedIndex]);
268+
if (this.selectedIndex === 0) {
269+
this.onSelect(undefined);
270+
} else {
271+
this.onSelect(this.optionsList[this.selectedIndex - 1]);
272+
}
231273
sdRef.close();
232274
} else {
233275
sdRef.open();

src/app/shared/utils/file-size-pipe.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ import {
22
Pipe,
33
PipeTransform,
44
} from '@angular/core';
5+
import { LocaleService } from '@dspace/core/locale/locale.service';
56
import { filesize } from 'filesize';
7+
import { take } from 'rxjs/operators';
68

79
/*
810
* Convert bytes into largest possible unit.
@@ -18,7 +20,20 @@ import { filesize } from 'filesize';
1820
name: 'dsFileSize',
1921
})
2022
export class FileSizePipe implements PipeTransform {
23+
24+
private currentLocale: string;
25+
26+
constructor(private localeService: LocaleService) {
27+
this.localeService.getCurrentLanguageCode().pipe(take(1)).subscribe(locale => {
28+
this.currentLocale = locale;
29+
});
30+
}
31+
2132
transform(bytes: number = 0, precision: number = 2): string {
22-
return filesize(bytes, { standard: 'jedec', round: precision });
33+
return filesize(bytes, {
34+
standard: 'jedec',
35+
round: precision,
36+
locale: this.currentLocale,
37+
});
2338
}
2439
}

src/app/submission/sections/cc-license/submission-section-cc-licenses.component.spec.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,8 @@ describe('SubmissionSectionCcLicensesComponent', () => {
241241
});
242242

243243
it('should have section status incomplete', () => {
244-
expect(component.getSectionStatus()).toBeObservable(cold('(a|)', { a: false }));
244+
component.required$.next(true);
245+
expect(component.getSectionStatus()).toBeObservable(cold('(a)', { a: false }));
245246
});
246247

247248
describe('when all options have a value selected', () => {
@@ -271,7 +272,13 @@ describe('SubmissionSectionCcLicensesComponent', () => {
271272
});
272273

273274
it('should have section status incomplete', () => {
274-
expect(component.getSectionStatus()).toBeObservable(cold('(a|)', { a: false }));
275+
component.required$.next(true);
276+
expect(component.getSectionStatus()).toBeObservable(cold('(a)', { a: false }));
277+
});
278+
279+
it('should have section status complete if not required', () => {
280+
component.required$.next(false);
281+
expect(component.getSectionStatus()).toBeObservable(cold('(a)', { a: true }));
275282
});
276283

277284
describe('when the cc license is accepted', () => {
@@ -282,7 +289,8 @@ describe('SubmissionSectionCcLicensesComponent', () => {
282289
});
283290

284291
it('should have section status complete', () => {
285-
expect(component.getSectionStatus()).toBeObservable(cold('(a|)', { a: true }));
292+
component.required$.next(false);
293+
expect(component.getSectionStatus()).toBeObservable(cold('(a)', { a: true })); // first true is because the section is not required
286294
});
287295
});
288296
});

src/app/submission/sections/cc-license/submission-section-cc-licenses.component.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {
3939
import { TranslateModule } from '@ngx-translate/core';
4040
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
4141
import {
42+
BehaviorSubject,
4243
Observable,
4344
of,
4445
Subscription,
@@ -154,6 +155,11 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent
154155

155156
ccLicenseLink$: Observable<string>;
156157

158+
/**
159+
* Is the section required
160+
*/
161+
public required$ = new BehaviorSubject<boolean>(false);
162+
157163
constructor(
158164
protected modalService: NgbModal,
159165
protected sectionService: SectionsService,
@@ -178,6 +184,7 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent
178184
if (hasNoValue(this.ccLicenseLink$)) {
179185
this.ccLicenseLink$ = this.getCcLicenseLink$();
180186
}
187+
this.required$.next(this.sectionData.mandatory);
181188
}
182189

183190
ngOnChanges(changes: SimpleChanges): void {
@@ -310,7 +317,10 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent
310317
* the section status
311318
*/
312319
getSectionStatus(): Observable<boolean> {
313-
return of(this.accepted);
320+
return this.required$.pipe(
321+
map((required) => !required || this.accepted),
322+
distinctUntilChanged(),
323+
);
314324
}
315325

316326
/**

0 commit comments

Comments
 (0)