Skip to content

Commit 7b3ed33

Browse files
Merge remote-tracking branch 'gitHub/main' into task/main/DURACOM-456
2 parents 7289376 + 781bef5 commit 7b3ed33

319 files changed

Lines changed: 15810 additions & 1667 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

config/config.example.yml

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ form:
164164
validatorMap:
165165
required: required
166166
regex: pattern
167+
# If true it enables the button "Duplicate" inside inline form groups.
168+
# The button will give the possibility to duplicate the whole form section copying the metadata values as well.
169+
showInlineGroupDuplicateButton: false
167170

168171
# Notification settings
169172
notifications:
@@ -202,6 +205,10 @@ submission:
202205
# default configuration
203206
- name: default
204207
style: ''
208+
# Icons that should remain visible even when no authority value is present for the metadata field.
209+
# This is useful for fields where you want to display an icon regardless of whether the value has an authority link.
210+
# Example: ['fas fa-user'] will show the user icon for author fields even without authority data.
211+
iconsVisibleWithNoAuthority: ['fas fa-user']
205212
authority:
206213
confidence:
207214
# NOTE: example of configuration
@@ -380,6 +387,8 @@ communityList:
380387
pageSize: 20
381388

382389
homePage:
390+
# Whether to show the top footer section or not
391+
showTopFooter: false
383392
recentSubmissions:
384393
# The number of item showing in recent submission components
385394
pageSize: 5
@@ -396,6 +405,20 @@ homePage:
396405
item:
397406
edit:
398407
undoTimeout: 10000 # 10 seconds
408+
# Defines the security levels available for metadata fields.
409+
# Each level maps to a numeric value stored on the metadata field in the backend and controls visibility of that field based on the user's role.
410+
# Levels are displayed as toggle buttons in the metadata edit UI.
411+
security:
412+
levels:
413+
- value: 0 # Public — visible to everyone
414+
icon: fa fa-globe
415+
color: green
416+
- value: 1 # Registered users — visible to authenticated users only
417+
icon: fa fa-key
418+
color: orange
419+
- value: 2 # Administrators only — restricted to admin users
420+
icon: fa fa-lock
421+
color: red
399422
# Show the item access status label in items lists
400423
showAccessStatuses: false
401424
bitstream:
@@ -410,7 +433,6 @@ item:
410433
# Metdadata list to be displayed for entities without a specific configuration
411434
fallbackMetdataList:
412435
- dc.description.abstract
413-
- dc.description.note
414436
# Configuration for each entity type
415437
entityDataConfig:
416438
- entityType: Person
@@ -430,6 +452,8 @@ item:
430452
iconPosition: IdentifierSubtypesIconPositionEnum.LEFT
431453
link: https://ror.org
432454

455+
# Enable authority based relations in item page
456+
showAuthorityRelations: false
433457
# Community Page Config
434458
community:
435459
# Default tab to be shown when browsing a Community. Valid values are: comcols, search, or browse_<field>
@@ -706,6 +730,28 @@ layout:
706730
default:
707731
icon: fas fa-project-diagram
708732
style: text-success
733+
# If true the download link in item page will be rendered as an advanced attachment, the view can be then configured with the layout.advancedAttachmentRendering config
734+
showDownloadLinkAsAttachment: false
735+
# Configuration for advanced attachment rendering in item pages. This controls how files are displayed when showDownloadLinkAsAttachment is enabled.
736+
# Defines which metadata/attributes to display for bitstream attachments.
737+
advancedAttachmentRendering:
738+
# Metadata and attributes to display for each attachment
739+
metadata:
740+
- name: dc.title
741+
type: metadata
742+
truncatable: false
743+
- name: dc.type
744+
type: metadata
745+
truncatable: false
746+
- name: dc.description
747+
type: metadata
748+
truncatable: true
749+
- name: size
750+
type: attribute
751+
- name: format
752+
type: attribute
753+
- name: checksum
754+
type: attribute
709755

710756
# Configuration for customization of search results
711757
searchResults:
@@ -736,3 +782,22 @@ searchResults:
736782
followAuthorityMetadataValuesLimit: 5
737783

738784

785+
# Configuration of social links using AddToAny plugin
786+
addToAnyPlugin:
787+
# This is enabled flag
788+
socialNetworksEnabled: false
789+
# If you want to self-host check https://www.addtoany.com/buttons/customize/host_cache
790+
scriptUrl: "https://static.addtoany.com/menu/page.js"
791+
# Check available integrations, visit https://www.addtoany.com/buttons/for/website
792+
# 1. Click "Choose Services", select integrations, then click Done
793+
# 2. Get Button Code
794+
# 3. You will get a HTML e.g. <a class="a2a_button_facebook"></a> where "facebook" is part you want to include in list
795+
buttons:
796+
- facebook
797+
- twitter
798+
- linkedin
799+
- email
800+
- copy_link
801+
showPlusButton: true
802+
showCounters: true
803+
title: DSpace demo
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
@if (editMode | async) {
2+
<ng-container *ngTemplateOutlet="editMetadataTemplate"></ng-container>
3+
}
4+
@else {
5+
<ng-container *ngTemplateOutlet="selectMetadataTemplate"></ng-container>
6+
}
7+
8+
<ng-template #selectMetadataTemplate>
9+
<div class="container">
10+
<h3 class="mb-4">{{'menu.section.cms.edit.metadata.head' | translate}}</h3>
11+
<div class="input-group">
12+
<select class="form-control col-md-4 mr-3 mb-2" aria-label="Select metadata" [(ngModel)]="selectedMetadata">
13+
<option [ngValue]="undefined" disabled selected>{{'admin.edit-cms-metadata.select-metadata' | translate}}</option>
14+
@for (md of metadataList; track $index) {
15+
<option [value]="md">{{md}}</option>
16+
}
17+
</select>
18+
<span class="input-group-btn">
19+
<button id="edit-metadata-btn" class="btn btn-primary" (click)="editSelectedMetadata()" [dsBtnDisabled]="!selectedMetadata">
20+
<i class="fas fa-edit mr-1"></i>
21+
{{'admin.edit-cms-metadata.edit-button' | translate}}
22+
</button>
23+
</span>
24+
</div>
25+
</div>
26+
</ng-template>
27+
28+
29+
<ng-template #editMetadataTemplate>
30+
<div class="container">
31+
<h2 class=" mb-5">{{'admin.edit-cms-metadata.title' | translate}} '{{selectedMetadata}}'</h2>
32+
<ds-alert [type]="'alert-info'" [dismissible]="true" [content]="'admin.edit-cms-metadata.markdown' | translate"></ds-alert>
33+
<div class="row">
34+
<div class="col-md">
35+
@for (lang of (languageMap | keyvalue); track lang.key) {
36+
<div class="form-group">
37+
<label>{{languageLabel(lang.value)}}</label>
38+
<textarea class="col-md-12 m-2" [ngModel]="selectedMetadataValues.get(lang.key)" (ngModelChange)="selectedMetadataValues.set(lang.key, $event)" rows="10"></textarea>
39+
</div>
40+
}
41+
</div>
42+
</div>
43+
<ng-container *ngTemplateOutlet="editMetadataButtonsTemplate"></ng-container>
44+
</div>
45+
</ng-template>
46+
47+
48+
<ng-template #editMetadataButtonsTemplate>
49+
<div class="row">
50+
<div class="col-md">
51+
<button id="save-metadata-btn" class="btn btn-primary float-right m-2" (click)="saveMetadata()">
52+
<span>
53+
<i class="fas fa-save mr-1"></i>
54+
{{ 'admin.edit-cms-metadata.save-button' | translate }}
55+
</span>
56+
</button>
57+
<button id="back-metadata-btn" class="btn btn-outline-secondary float-right m-2" (click)="back()">
58+
<span>
59+
<i class="fas fa-arrow-left mr-1"></i>
60+
{{ 'admin.edit-cms-metadata.back-button' | translate }}
61+
</span>
62+
</button>
63+
</div>
64+
</div>
65+
</ng-template>

src/app/admin/admin-edit-cms-metadata/admin-edit-cms-metadata.component.scss

Whitespace-only changes.
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import { NO_ERRORS_SCHEMA } from '@angular/core';
2+
import {
3+
ComponentFixture,
4+
TestBed,
5+
waitForAsync,
6+
} from '@angular/core/testing';
7+
import { FormsModule } from '@angular/forms';
8+
import { By } from '@angular/platform-browser';
9+
import { provideNoopAnimations } from '@angular/platform-browser/animations';
10+
import { NotificationsService } from '@dspace/core/notification-system/notifications.service';
11+
import { NotificationsServiceStub } from '@dspace/core/testing/notifications-service.stub';
12+
import { TranslateLoaderMock } from '@dspace/core/testing/translate-loader.mock';
13+
import {
14+
TranslateLoader,
15+
TranslateModule,
16+
} from '@ngx-translate/core';
17+
import { of } from 'rxjs';
18+
19+
import { environment } from '../../../environments/environment.test';
20+
import { SiteDataService } from '../../core/data/site-data.service';
21+
import { Site } from '../../core/shared/site.model';
22+
import { AdminEditCmsMetadataComponent } from './admin-edit-cms-metadata.component';
23+
24+
describe('AdminEditCmsMetadataComponent', () => {
25+
26+
let component: AdminEditCmsMetadataComponent;
27+
let fixture: ComponentFixture<AdminEditCmsMetadataComponent>;
28+
const site = Object.assign(new Site(), {
29+
metadata: { },
30+
});
31+
32+
const siteServiceStub = jasmine.createSpyObj('SiteDataService', {
33+
find: jasmine.createSpy('find'),
34+
patch: jasmine.createSpy('patch'),
35+
});
36+
37+
const metadataValueMap = new Map([
38+
['en', ''],
39+
['de', ''],
40+
['cs', ''],
41+
['nl', ''],
42+
['pt', ''],
43+
['fr', ''],
44+
['lv', ''],
45+
['bn', ''],
46+
['el', ''],
47+
]);
48+
beforeEach(waitForAsync(() => {
49+
TestBed.configureTestingModule({
50+
imports: [
51+
FormsModule,
52+
TranslateModule.forRoot({
53+
loader: {
54+
provide: TranslateLoader,
55+
useClass: TranslateLoaderMock,
56+
},
57+
}),
58+
AdminEditCmsMetadataComponent,
59+
],
60+
providers: [
61+
{ provide: NotificationsService, useValue: NotificationsServiceStub },
62+
{ provide: SiteDataService, useValue: siteServiceStub },
63+
provideNoopAnimations(),
64+
],
65+
schemas: [NO_ERRORS_SCHEMA],
66+
}).compileComponents();
67+
}));
68+
69+
beforeEach(() => {
70+
fixture = TestBed.createComponent(AdminEditCmsMetadataComponent);
71+
component = fixture.componentInstance;
72+
siteServiceStub.find.and.returnValue(of(site));
73+
siteServiceStub.patch.and.returnValue(of(site));
74+
});
75+
76+
describe('', () => {
77+
78+
beforeEach(() => {
79+
// component.editMode = false;
80+
fixture.detectChanges();
81+
});
82+
it('should create', () => {
83+
expect(component).toBeTruthy();
84+
});
85+
86+
it('should show metadata cms list correctly', () => {
87+
// Substract 1 because the top footer is not included in the list if it is not enabled (and it's not, by default)
88+
const metadataListLength = environment.cms.metadataList.length - 1;
89+
const selectMetadata = fixture.debugElement.query(By.css('select'));
90+
expect(selectMetadata.children).toHaveSize(metadataListLength + 1);
91+
});
92+
93+
});
94+
95+
describe('when the edit button is clicked', () => {
96+
beforeEach(() => {
97+
spyOn(component, 'editSelectedMetadata');
98+
component.selectedMetadata = 'metadata';
99+
fixture.detectChanges();
100+
});
101+
it('should call selectMetadataToEdit', () => {
102+
const editButton = fixture.debugElement.query(By.css('#edit-metadata-btn'));
103+
editButton.nativeElement.click();
104+
expect(component.editSelectedMetadata).toHaveBeenCalled();
105+
});
106+
});
107+
108+
describe('after the button edit is clicked', () => {
109+
110+
beforeEach(() => {
111+
component.selectedMetadata = environment.cms.metadataList[0];
112+
component.selectedMetadataValues = metadataValueMap;
113+
component.editMode.next(true);
114+
fixture.detectChanges();
115+
});
116+
117+
it('should render textareas of the languages', () => {
118+
const languagesLength = environment.languages.filter((l) => l.active).length;
119+
const textareas = fixture.debugElement.queryAll(By.css('textarea'));
120+
console.log(textareas.length, languagesLength);
121+
expect(textareas).toHaveSize(languagesLength);
122+
});
123+
124+
describe('after the button save is clicked', () => {
125+
126+
it('should call method edit', () => {
127+
spyOn(component, 'saveMetadata');
128+
const saveButton = fixture.debugElement.query(By.css('#save-metadata-btn'));
129+
saveButton.nativeElement.click();
130+
expect(component.saveMetadata).toHaveBeenCalled();
131+
});
132+
133+
it('should call method patch of service', () => {
134+
component.selectedMetadata = environment.cms.metadataList[0];
135+
const saveButton = fixture.debugElement.query(By.css('#save-metadata-btn'));
136+
saveButton.nativeElement.click();
137+
const operations = [];
138+
operations.push({
139+
op: 'replace',
140+
path: '/metadata/' + component.selectedMetadata,
141+
value: {
142+
value: component.selectedMetadataValues.get(environment.languages[0].code),
143+
language: environment.languages[0].code,
144+
},
145+
});
146+
component.selectedMetadataValues.forEach((value, key) => {
147+
if (key !== environment.languages[0].code) {
148+
operations.push({
149+
op: 'add',
150+
path: '/metadata/' + component.selectedMetadata,
151+
value: {
152+
value: value,
153+
language: key,
154+
},
155+
});
156+
}
157+
});
158+
expect(siteServiceStub.patch).toHaveBeenCalledWith(site, operations);
159+
});
160+
161+
});
162+
});
163+
});

0 commit comments

Comments
 (0)