Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
bf14771
[DURACOM-413] port custom url functionality
FrancescoMolinaro Nov 12, 2025
66bd310
Merge remote-tracking branch 'gitHub/main' into task/main/DURACOM-413
FrancescoMolinaro Nov 13, 2025
b42bf55
[DURACOM-413] additional tests
FrancescoMolinaro Nov 13, 2025
e88a40d
[DURACOM-413] update labels, fix sync script, adapt section handling
FrancescoMolinaro Nov 18, 2025
c93cb50
[DURACOM-413] update error handling/validation + resync translations
FrancescoMolinaro Nov 19, 2025
75937c4
Merge remote-tracking branch 'gitHub/main' into task/main/DURACOM-413
FrancescoMolinaro Dec 5, 2025
d1c1ecf
[DURACOM-413] fix lint
FrancescoMolinaro Dec 5, 2025
8bdfd01
[DURACOM-426] init integration of authority framework
FrancescoMolinaro Dec 10, 2025
a9dc8ec
Merge branch 'task/main/DURACOM-413' into task/main/DURACOM-426
FrancescoMolinaro Dec 12, 2025
8c073ff
[DURACOM-426] port metadata link components for authorithy
FrancescoMolinaro Dec 15, 2025
d262480
[DURACOM-426] fix some tests
FrancescoMolinaro Dec 15, 2025
9c5e6bb
[DURACOM-426] fix some unit tests
FrancescoMolinaro Dec 16, 2025
a514b6e
[DURACOM-426] fix tests and lint
FrancescoMolinaro Dec 16, 2025
a9ee4e5
[DURACOM-426] add authority link for md representation
FrancescoMolinaro Dec 16, 2025
306029c
Merge remote-tracking branch 'gitHub/main' into task/main/DURACOM-426
FrancescoMolinaro Dec 18, 2025
36c77fe
[DURACOM-426] clean up, add example, minor restyle, fix templates
FrancescoMolinaro Dec 18, 2025
e9f3df5
[DURACOM-426] improve tests
FrancescoMolinaro Dec 18, 2025
5b6fa80
[DURACOM-426] refactor
FrancescoMolinaro Dec 19, 2025
b29dc1e
[DURACOM-426] improve title configurability in popover, add link view…
FrancescoMolinaro Jan 15, 2026
3f35069
[DURACOM-426] add labels, fix facets labels,fix onebox other info tem…
FrancescoMolinaro Jan 16, 2026
1258bc2
[DURACOM-426] filter data labels
FrancescoMolinaro Jan 19, 2026
36e34a2
[DURACOM-426] revert changes to lables, except for english
FrancescoMolinaro Jan 19, 2026
d2c0749
[DURACOM-426] add config example, remove unnecessary config
FrancescoMolinaro Jan 19, 2026
1aef155
[DURACOM-426] clean config, add labels
FrancescoMolinaro Jan 19, 2026
995ff87
[DURACOM-426] add authority enrichment
FrancescoMolinaro Jan 21, 2026
efc488a
[DURACOM-426] fix tests
FrancescoMolinaro Jan 21, 2026
252c249
[DURACOM-426] fix test and model update
FrancescoMolinaro Jan 22, 2026
e316b11
[DURACOM-426] add vocabulary template in item field, adapt tests
FrancescoMolinaro Jan 22, 2026
317c1ee
Merge remote-tracking branch 'gitHub/main' into task/main/DURACOM-426
FrancescoMolinaro Jan 23, 2026
be381eb
[DURACOM-426] fix lint
FrancescoMolinaro Jan 23, 2026
a19ef43
[DURACOM-426] refactor
FrancescoMolinaro Jan 29, 2026
25a5bc0
[DURACOM-444] add group component
FrancescoMolinaro Jan 28, 2026
b8bdf47
[DURACOM-444] add modal for relation groups
FrancescoMolinaro Jan 30, 2026
4f6242a
[DURACOM-444] add inline parser
FrancescoMolinaro Jan 30, 2026
c32a477
[DURACOM-444] adapt inline-group parser, style, improve error handlin…
FrancescoMolinaro Jan 30, 2026
cab395e
[DURACOM-444] disable test console capturing
FrancescoMolinaro Jan 30, 2026
ec6efd7
[DURACOM-444] fix authority setup
FrancescoMolinaro Feb 2, 2026
bee3fd9
[DURACOM-444] fix authority in group, fix row style
FrancescoMolinaro Feb 2, 2026
7657918
[DURACOM-445] add new property for authority relations
FrancescoMolinaro Feb 5, 2026
837b47e
Merge remote-tracking branch 'gitHub/main' into task/main/DURACOM-426
FrancescoMolinaro Feb 6, 2026
7501939
Merge remote-tracking branch 'gitHub/main' into task/main/DURACOM-444
FrancescoMolinaro Feb 9, 2026
a51e5c2
[DURACOM-444] adapt tests for group component
FrancescoMolinaro Feb 9, 2026
ca4edf7
Merge remote-tracking branch 'gitHub/main' into task/main/DURACOM-426
FrancescoMolinaro Feb 12, 2026
a15ad30
[DURACOM-426] remove unused method and duplicated config example
FrancescoMolinaro Feb 12, 2026
5ac23e6
[DURACOM-445] add authority based search relations component
FrancescoMolinaro Feb 12, 2026
5160bf9
[DURACOM-426] revert changes to sync script
FrancescoMolinaro Feb 12, 2026
23ecd1e
[DURACOM-445] add nav tabs to authority-related-entities-search, fix …
FrancescoMolinaro Feb 13, 2026
1e9fbee
[DURACOM-453] add edit item menu and data service
FrancescoMolinaro Feb 13, 2026
a3c14c5
[DURACOM-453] finalize improvement for submission and edit mode
FrancescoMolinaro Feb 16, 2026
e0bb5f9
Merge branch 'task/main/DURACOM-444' into task/main/DURACOM-453
FrancescoMolinaro Feb 16, 2026
664e44f
Merge branch 'task/main/DURACOM-426' into task/main/DURACOM-453
FrancescoMolinaro Feb 16, 2026
2edc805
Merge remote-tracking branch 'gitHub/main' into task/main/DURACOM-453
FrancescoMolinaro Feb 16, 2026
850a973
[DURACOM-453] add metadata security and finilize edit mode
FrancescoMolinaro Feb 17, 2026
87cfa6e
[DURACOM-453] fix observable issue, add full projection
FrancescoMolinaro Feb 19, 2026
ab0885e
[DURACOM-453] add shared submission config and labels
FrancescoMolinaro Feb 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 91 additions & 1 deletion config/config.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,12 @@ submission:
style: text-muted
icon: fa-circle-xmark

# Icons to be displayed next to an authority controlled value, to give indication of the source.
sourceIcons:
# Example of configuration for authority logo based on sources.
# The configured icon will be displayed next to the authority value in submission and on item page or search results.
- source: orcid
- path: assets/images/orcid.logo.icon.svg
# Fallback language in which the UI will be rendered if the user's browser language is not an active language
fallbackLanguage: en

Expand Down Expand Up @@ -393,7 +399,8 @@ item:
pageSize: 5
# Show the bitstream access status label on the item page
showAccessStatuses: false

# Enable authority based relations in item page
showAuthorithyRelations: false
# Community Page Config
community:
# Default tab to be shown when browsing a Community. Valid values are: comcols, search, or browse_<field>
Expand Down Expand Up @@ -641,3 +648,86 @@ geospatialMapViewer:
accessibility:
# The duration in days after which the accessibility settings cookie expires
cookieExpirationDuration: 7

# Configuration for custom layout
layout:
# Configuration of icons and styles to be used for each authority controlled link
authorityRef:
- entityType: DEFAULT
entityStyle:
default:
icon: fa fa-user
style: text-info
- entityType: PERSON
entityStyle:
person:
icon: fa fa-user
style: text-success
default:
icon: fa fa-user
style: text-info
- entityType: ORGUNIT
entityStyle:
default:
icon: fa fa-university
style: text-success
- entityType: PROJECT
entityStyle:
default:
icon: fas fa-project-diagram
style: text-success

# When the search results are retrieved, for each item type the metadata with a valid authority value are inspected.
# Referenced items will be fetched with a find all by id strategy to avoid individual rest requests
# to efficiently display the search results.
followAuthorityMetadata:
- type: Publication
metadata: dc.contributor.author
- type: Product
metadata: dc.contributor.author

# The maximum number of item to process when following authority metadata values.
followAuthorityMaxItemLimit: 100

# The maximum number of metadata values to process for each metadata key
# when following authority metadata values.
followAuthorityMetadataValuesLimit: 5

# Configuration for customization of search results
searchResults:
# Metadata fields to be displayed in the search results under the standard ones
additionalMetadataFields:
- dc.contributor.author
- dc.date.issued
- dc.type
# Metadata fields to be displayed in the search results for the author section
authorMetadata:
- dc.contributor.author
- dc.creator
- dc.contributor.*

# Configuration of metadata to be displayed in the item metadata link view popover
metadataLinkViewPopoverData:
# Metdadata list to be displayed for entities without a specific configuration
fallbackMetdataList:
- dc.description.abstract
- dc.description.note
# Configuration for each entity type
entityDataConfig:
- entityType: Person
# Descriptive metadata (popover body)
metadataList:
- person.affiliation.name
- person.email
# Title metadata (popover header)
titleMetadataList:
- person.givenName
- person.familyName
# Configuration for identifier subtypes, based on metadata like dc.identifier.ror where ror is the subtype.
# This is used to map the layout of the identifier in the popover and the icon displayed next to the metadata value.
identifierSubtypes:
- name: ror
icon: assets/images/ror.logo.icon.svg
iconPosition: IdentifierSubtypesIconPositionEnum.LEFT
link: https://ror.org

6 changes: 6 additions & 0 deletions src/app/app-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { ACCESS_CONTROL_MODULE_PATH } from './access-control/access-control-rout
import { NOTIFICATIONS_MODULE_PATH } from './admin/admin-routing-paths';
import {
ADMIN_MODULE_PATH,
EDIT_ITEM_PATH,
FORGOT_PASSWORD_PATH,
HEALTH_PAGE_PATH,
PROFILE_MODULE_PATH,
Expand Down Expand Up @@ -279,6 +280,11 @@ export const APP_ROUTES: Route[] = [
.then((m) => m.ROUTES),
canActivate: [authenticatedGuard],
},
{
path: EDIT_ITEM_PATH,
loadChildren: () => import('./edit-item/edit-item-routes').then((m) => m.ROUTES),
canActivate: [endUserAgreementCurrentUserGuard],
},
{
path: 'external-login/:token',
loadChildren: () => import('./external-login-page/external-login-routes').then((m) => m.ROUTES),
Expand Down
4 changes: 4 additions & 0 deletions src/app/app.menus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { CurationMenuProvider } from './shared/menu/providers/curation.menu';
import { DSpaceObjectEditMenuProvider } from './shared/menu/providers/dso-edit.menu';
import { DsoOptionMenuProvider } from './shared/menu/providers/dso-option.menu';
import { EditMenuProvider } from './shared/menu/providers/edit.menu';
import { EditItemDetailsMenuProvider } from './shared/menu/providers/edit-item-details.menu';
import { ExportMenuProvider } from './shared/menu/providers/export.menu';
import { HealthMenuProvider } from './shared/menu/providers/health.menu';
import { ImportMenuProvider } from './shared/menu/providers/import.menu';
Expand Down Expand Up @@ -104,6 +105,9 @@ export const MENUS = buildMenuStructure({
ClaimMenuProvider.onRoute(
MenuRoute.ITEM_PAGE,
),
EditItemDetailsMenuProvider.onRoute(
MenuRoute.ITEM_PAGE,
),
]),
],
});
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export class BrowseByTaxonomyComponent implements OnInit, OnChanges, OnDestroy {
this.selectedItems = [];
this.facetType = browseDefinition.facetType;
this.vocabularyName = browseDefinition.vocabulary;
this.vocabularyOptions = { name: this.vocabularyName, closed: true };
this.vocabularyOptions = { name: this.vocabularyName, metadata: null, scope: null, closed: true };
this.description = this.translate.instant(`browse.metadata.${this.vocabularyName}.tree.description`);
}));
this.subs.push(this.scope$.subscribe(() => {
Expand Down
108 changes: 88 additions & 20 deletions src/app/collection-page/collection-form/collection-form.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import {
} from '@angular/core';
import { AuthService } from '@dspace/core/auth/auth.service';
import { ObjectCacheService } from '@dspace/core/cache/object-cache.service';
import { ConfigObject } from '@dspace/core/config/models/config.model';
import { SubmissionDefinitionModel } from '@dspace/core/config/models/config-submission-definition.model';
import { SubmissionDefinitionsConfigDataService } from '@dspace/core/config/submission-definitions-config-data.service';
import { CollectionDataService } from '@dspace/core/data/collection-data.service';
import { EntityTypeDataService } from '@dspace/core/data/entity-type-data.service';
import { RequestService } from '@dspace/core/data/request.service';
Expand All @@ -25,6 +28,7 @@ import {
} from '@dspace/shared/utils/empty.util';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import {
DynamicCheckboxModel,
DynamicFormControlModel,
DynamicFormOptionConfig,
DynamicFormService,
Expand All @@ -34,16 +38,24 @@ import {
TranslateModule,
TranslateService,
} from '@ngx-translate/core';
import { Observable } from 'rxjs';
import {
catchError,
combineLatest,
Observable,
of,
} from 'rxjs';

import { ComColFormComponent } from '../../shared/comcol/comcol-forms/comcol-form/comcol-form.component';
import { ComcolPageLogoComponent } from '../../shared/comcol/comcol-page-logo/comcol-page-logo.component';
import { FormComponent } from '../../shared/form/form.component';
import { UploaderComponent } from '../../shared/upload/uploader/uploader.component';
import { VarDirective } from '../../shared/utils/var.directive';
import {
collectionFormCorrectionSubmissionDefinitionSelectionConfig,
collectionFormEntityTypeSelectionConfig,
collectionFormModels,
collectionFormSharedWorkspaceCheckboxConfig,
collectionFormSubmissionDefinitionSelectionConfig,
} from './collection-form.models';

/**
Expand Down Expand Up @@ -79,6 +91,20 @@ export class CollectionFormComponent extends ComColFormComponent<Collection> imp
*/
entityTypeSelection: DynamicSelectModel<string> = new DynamicSelectModel(collectionFormEntityTypeSelectionConfig);

/**
* The dynamic form field used for submission definition selection
* @type {DynamicSelectModel<string>}
*/
submissionDefinitionSelection: DynamicSelectModel<string> = new DynamicSelectModel(collectionFormSubmissionDefinitionSelectionConfig);

/**
* The dynamic form field used for correction submission definition selection
* @type {DynamicSelectModel<string>}
*/
correctionSubmissionDefinitionSelection: DynamicSelectModel<string> = new DynamicSelectModel(collectionFormCorrectionSubmissionDefinitionSelectionConfig);

sharedWorkspaceChekbox: DynamicCheckboxModel = new DynamicCheckboxModel(collectionFormSharedWorkspaceCheckboxConfig);

/**
* The dynamic form fields used for creating/editing a collection
* @type {DynamicFormControlModel[]}
Expand All @@ -94,6 +120,7 @@ export class CollectionFormComponent extends ComColFormComponent<Collection> imp
protected objectCache: ObjectCacheService,
protected entityTypeService: EntityTypeDataService,
protected chd: ChangeDetectorRef,
protected submissionDefinitionService: SubmissionDefinitionsConfigDataService,
protected modalService: NgbModal) {
super(formService, translate, notificationsService, authService, requestService, objectCache, modalService);
}
Expand All @@ -117,35 +144,76 @@ export class CollectionFormComponent extends ComColFormComponent<Collection> imp

initializeForm() {
let currentRelationshipValue: MetadataValue[];
let currentDefinitionValue: MetadataValue[];
let currentCorrectionDefinitionValue: MetadataValue[];
let currentSharedWorkspaceValue: MetadataValue[];
if (this.dso && this.dso.metadata) {
currentRelationshipValue = this.dso.metadata['dspace.entity.type'];
currentDefinitionValue = this.dso.metadata['cris.submission.definition'];
currentCorrectionDefinitionValue = this.dso.metadata['cris.submission.definition-correction'];
currentSharedWorkspaceValue = this.dso.metadata['cris.workspace.shared'];
}

const entities$: Observable<ItemType[]> = this.entityTypeService.findAll({ elementsPerPage: 100, currentPage: 1 }).pipe(
getFirstSucceededRemoteListPayload(),
);

// retrieve all entity types to populate the dropdowns selection
entities$.subscribe((entityTypes: ItemType[]) => {

entityTypes = entityTypes.filter((type: ItemType) => type.label !== NONE_ENTITY_TYPE);
entityTypes.forEach((type: ItemType, index: number) => {
this.entityTypeSelection.add({
disabled: false,
label: type.label,
value: type.label,
} as DynamicFormOptionConfig<string>);
if (currentRelationshipValue && currentRelationshipValue.length > 0 && currentRelationshipValue[0].value === type.label) {
this.entityTypeSelection.select(index);
this.entityTypeSelection.disabled = true;
}
});
const definitions$: Observable<ConfigObject[]> = this.submissionDefinitionService
.findAll({ elementsPerPage: 100, currentPage: 1 }).pipe(
getFirstSucceededRemoteListPayload(),
catchError(() => of([])),
);

// retrieve all entity types and submission definitions to populate the dropdowns selection
combineLatest([entities$, definitions$])
.subscribe(([entityTypes, definitions]: [ItemType[], SubmissionDefinitionModel[]]) => {

const sortedEntityTypes = entityTypes
.filter((type: ItemType) => type.label !== NONE_ENTITY_TYPE)
.sort((a, b) => a.label.localeCompare(b.label));

sortedEntityTypes.forEach((type: ItemType, index: number) => {
this.entityTypeSelection.add({
disabled: false,
label: type.label,
value: type.label,
} as DynamicFormOptionConfig<string>);
if (currentRelationshipValue && currentRelationshipValue.length > 0 && currentRelationshipValue[0].value === type.label) {
this.entityTypeSelection.select(index);
this.entityTypeSelection.disabled = true;
}
});

this.formModel = entityTypes.length === 0 ? collectionFormModels : [...collectionFormModels, this.entityTypeSelection];
definitions.forEach((definition: SubmissionDefinitionModel, index: number) => {
this.submissionDefinitionSelection.add({
disabled: false,
label: definition.name,
value: definition.name,
} as DynamicFormOptionConfig<string>);
this.correctionSubmissionDefinitionSelection.add({
disabled: false,
label: definition.name,
value: definition.name,
} as DynamicFormOptionConfig<string>);
if (currentDefinitionValue && currentDefinitionValue.length > 0 && currentDefinitionValue[0].value === definition.name) {
this.submissionDefinitionSelection.select(index);
}
if (currentCorrectionDefinitionValue && currentCorrectionDefinitionValue.length > 0 && currentCorrectionDefinitionValue[0].value === definition.name) {
this.correctionSubmissionDefinitionSelection.select(index);
}
});

super.ngOnInit();
this.chd.detectChanges();
});
this.formModel = entityTypes.length === 0 ?
[...collectionFormModels, this.submissionDefinitionSelection, this.correctionSubmissionDefinitionSelection, this.sharedWorkspaceChekbox] :
[...collectionFormModels, this.entityTypeSelection, this.submissionDefinitionSelection, this.correctionSubmissionDefinitionSelection, this.sharedWorkspaceChekbox];

super.ngOnInit();

if (currentSharedWorkspaceValue && currentSharedWorkspaceValue.length > 0) {
this.sharedWorkspaceChekbox.value = currentSharedWorkspaceValue[0].value === 'true';
}
this.chd.detectChanges();
});

}
}
33 changes: 33 additions & 0 deletions src/app/collection-page/collection-form/collection-form.models.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
DynamicCheckboxModelConfig,
DynamicFormControlModel,
DynamicInputModel,
DynamicSelectModelConfig,
Expand All @@ -10,6 +11,38 @@ import { environment } from '../../../environments/environment';
export const collectionFormEntityTypeSelectionConfig: DynamicSelectModelConfig<string> = {
id: 'entityType',
name: 'dspace.entity.type',
required: true,
disabled: false,
validators: {
required: null,
},
errorMessages: {
required: 'collection.form.errors.entityType.required',
},
};

export const collectionFormSubmissionDefinitionSelectionConfig: DynamicSelectModelConfig<string> = {
id: 'submissionDefinition',
name: 'cris.submission.definition',
required: true,
disabled: false,
validators: {
required: null,
},
errorMessages: {
required: 'collection.form.errors.submissionDefinition.required',
},
};
export const collectionFormCorrectionSubmissionDefinitionSelectionConfig: DynamicSelectModelConfig<string> = {
id: 'correctionSubmissionDefinition',
name: 'cris.submission.definition-correction',
required: false,
disabled: false,
};

export const collectionFormSharedWorkspaceCheckboxConfig: DynamicCheckboxModelConfig = {
id: 'sharedWorkspace',
name: 'cris.workspace.shared',
disabled: false,
};

Expand Down
Loading
Loading