Merge branch 'main' into themeable-section-upload-file

This commit is contained in:
Mark H. Wood
2023-06-01 16:36:09 -04:00
244 changed files with 4669 additions and 1687 deletions

View File

@@ -413,8 +413,7 @@ dspace-angular
│ ├── merge-i18n-files.ts *
│ ├── serve.ts *
│ ├── sync-i18n-files.ts *
── test-rest.ts *
│ └── webpack.js *
── test-rest.ts *
├── src * The source of the application
│ ├── app * The source code of the application, subdivided by module/page.
│ ├── assets * Folder for static resources

View File

@@ -1,13 +0,0 @@
const path = require('path');
const child_process = require('child_process');
const heapSize = 4096;
const webpackPath = path.join('node_modules', 'webpack', 'bin', 'webpack.js');
const params = [
'--max_old_space_size=' + heapSize,
webpackPath,
...process.argv.slice(2)
];
child_process.spawn('node', params, { stdio:'inherit' });

View File

@@ -68,18 +68,18 @@
<tr *ngFor="let epersonDto of (ePeopleDto$ | async)?.page"
[ngClass]="{'table-primary' : isActive(epersonDto.eperson) | async}">
<td>{{epersonDto.eperson.id}}</td>
<td>{{epersonDto.eperson.name}}</td>
<td>{{ dsoNameService.getName(epersonDto.eperson) }}</td>
<td>{{epersonDto.eperson.email}}</td>
<td>
<div class="btn-group edit-field">
<button (click)="toggleEditEPerson(epersonDto.eperson)"
class="btn btn-outline-primary btn-sm access-control-editEPersonButton"
title="{{labelPrefix + 'table.edit.buttons.edit' | translate: {name: epersonDto.eperson.name} }}">
title="{{labelPrefix + 'table.edit.buttons.edit' | translate: { name: dsoNameService.getName(epersonDto.eperson) } }}">
<i class="fas fa-edit fa-fw"></i>
</button>
<button [disabled]="!epersonDto.ableToDelete" (click)="deleteEPerson(epersonDto.eperson)"
class="delete-button btn btn-outline-danger btn-sm access-control-deleteEPersonButton"
title="{{labelPrefix + 'table.edit.buttons.remove' | translate: {name: epersonDto.eperson.name} }}">
title="{{labelPrefix + 'table.edit.buttons.remove' | translate: { name: dsoNameService.getName(epersonDto.eperson) } }}">
<i class="fas fa-trash-alt fa-fw"></i>
</button>
</div>

View File

@@ -21,6 +21,7 @@ import { RequestService } from '../../core/data/request.service';
import { PageInfo } from '../../core/shared/page-info.model';
import { NoContent } from '../../core/shared/NoContent.model';
import { PaginationService } from '../../core/pagination/pagination.service';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
@Component({
selector: 'ds-epeople-registry',
@@ -93,7 +94,9 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
private router: Router,
private modalService: NgbModal,
private paginationService: PaginationService,
public requestService: RequestService) {
public requestService: RequestService,
public dsoNameService: DSONameService,
) {
this.currentSearchQuery = '';
this.currentSearchScope = 'metadata';
this.searchForm = this.formBuilder.group(({
@@ -121,7 +124,7 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
this.subs.push(this.ePeople$.pipe(
switchMap((epeople: PaginatedList<EPerson>) => {
if (epeople.pageInfo.totalElements > 0) {
return combineLatest(...epeople.page.map((eperson) => {
return combineLatest([...epeople.page.map((eperson: EPerson) => {
return this.authorizationService.isAuthorized(FeatureID.CanDelete, hasValue(eperson) ? eperson.self : undefined).pipe(
map((authorized) => {
const epersonDtoModel: EpersonDtoModel = new EpersonDtoModel();
@@ -130,7 +133,7 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
return epersonDtoModel;
})
);
})).pipe(map((dtos: EpersonDtoModel[]) => {
})]).pipe(map((dtos: EpersonDtoModel[]) => {
return buildPaginatedList(epeople.pageInfo, dtos);
}));
} else {
@@ -237,7 +240,7 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
if (hasValue(ePerson.id)) {
this.epersonService.deleteEPerson(ePerson).pipe(getFirstCompletedRemoteData()).subscribe((restResponse: RemoteData<NoContent>) => {
if (restResponse.hasSucceeded) {
this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.deleted.success', {name: ePerson.name}));
this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.deleted.success', {name: this.dsoNameService.getName(ePerson)}));
} else {
this.notificationsService.error('Error occured when trying to delete EPerson with id: ' + ePerson.id + ' with code: ' + restResponse.statusCode + ' and message: ' + restResponse.errorMessage);
}

View File

@@ -65,9 +65,13 @@
<tbody>
<tr *ngFor="let group of (groups | async)?.payload?.page">
<td class="align-middle">{{group.id}}</td>
<td class="align-middle"><a (click)="groupsDataService.startEditingNewGroup(group)"
[routerLink]="[groupsDataService.getGroupEditPageRouterLink(group)]">{{group.name}}</a></td>
<td class="align-middle">{{(group.object | async)?.payload?.name}}</td>
<td class="align-middle">
<a (click)="groupsDataService.startEditingNewGroup(group)"
[routerLink]="[groupsDataService.getGroupEditPageRouterLink(group)]">
{{ dsoNameService.getName(group) }}
</a>
</td>
<td class="align-middle">{{ dsoNameService.getName(undefined) }}</td>
</tr>
</tbody>
</table>

View File

@@ -37,6 +37,7 @@ import { ValidateEmailNotTaken } from './validators/email-taken.validator';
import { Registration } from '../../../core/shared/registration.model';
import { EpersonRegistrationService } from '../../../core/data/eperson-registration.service';
import { TYPE_REQUEST_FORGOT } from '../../../register-email-form/register-email-form.component';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
@Component({
selector: 'ds-eperson-form',
@@ -192,6 +193,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
private paginationService: PaginationService,
public requestService: RequestService,
private epersonRegistrationService: EpersonRegistrationService,
public dsoNameService: DSONameService,
) {
this.subs.push(this.epersonService.getActiveEPerson().subscribe((eperson: EPerson) => {
this.epersonInitial = eperson;
@@ -212,14 +214,14 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
*/
initialisePage() {
observableCombineLatest(
observableCombineLatest([
this.translateService.get(`${this.messagePrefix}.firstName`),
this.translateService.get(`${this.messagePrefix}.lastName`),
this.translateService.get(`${this.messagePrefix}.email`),
this.translateService.get(`${this.messagePrefix}.canLogIn`),
this.translateService.get(`${this.messagePrefix}.requireCertificate`),
this.translateService.get(`${this.messagePrefix}.emailHint`),
).subscribe(([firstName, lastName, email, canLogIn, requireCertificate, emailHint]) => {
]).subscribe(([firstName, lastName, email, canLogIn, requireCertificate, emailHint]) => {
this.firstName = new DynamicInputModel({
id: 'firstName',
label: firstName,
@@ -386,10 +388,10 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
getFirstCompletedRemoteData()
).subscribe((rd: RemoteData<EPerson>) => {
if (rd.hasSucceeded) {
this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.created.success', { name: ePersonToCreate.name }));
this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.created.success', { name: this.dsoNameService.getName(ePersonToCreate) }));
this.submitForm.emit(ePersonToCreate);
} else {
this.notificationsService.error(this.translateService.get(this.labelPrefix + 'notification.created.failure', { name: ePersonToCreate.name }));
this.notificationsService.error(this.translateService.get(this.labelPrefix + 'notification.created.failure', { name: this.dsoNameService.getName(ePersonToCreate) }));
this.cancelForm.emit();
}
});
@@ -425,10 +427,10 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
const response = this.epersonService.updateEPerson(editedEperson);
response.pipe(getFirstCompletedRemoteData()).subscribe((rd: RemoteData<EPerson>) => {
if (rd.hasSucceeded) {
this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.edited.success', { name: editedEperson.name }));
this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.edited.success', { name: this.dsoNameService.getName(editedEperson) }));
this.submitForm.emit(editedEperson);
} else {
this.notificationsService.error(this.translateService.get(this.labelPrefix + 'notification.edited.failure', { name: editedEperson.name }));
this.notificationsService.error(this.translateService.get(this.labelPrefix + 'notification.edited.failure', { name: this.dsoNameService.getName(editedEperson) }));
this.cancelForm.emit();
}
});
@@ -476,7 +478,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
if (hasValue(eperson.id)) {
this.epersonService.deleteEPerson(eperson).pipe(getFirstCompletedRemoteData()).subscribe((restResponse: RemoteData<NoContent>) => {
if (restResponse.hasSucceeded) {
this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.deleted.success', { name: eperson.name }));
this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.deleted.success', { name: this.dsoNameService.getName(eperson) }));
this.submitForm.emit();
} else {
this.notificationsService.error('Error occured when trying to delete EPerson with id: ' + eperson.id + ' with code: ' + restResponse.statusCode + ' and message: ' + restResponse.errorMessage);
@@ -554,7 +556,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
.subscribe((list: PaginatedList<EPerson>) => {
if (list.totalElements > 0) {
this.notificationsService.error(this.translateService.get(this.labelPrefix + 'notification.' + notificationSection + '.failure.emailInUse', {
name: ePerson.name,
name: this.dsoNameService.getName(ePerson),
email: ePerson.email
}));
}

View File

@@ -26,7 +26,7 @@
<ds-alert *ngIf="groupBeingEdited?.permanent" [type]="AlertTypeEnum.Warning"
[content]="messagePrefix + '.alert.permanent'"></ds-alert>
<ds-alert *ngIf="!(canEdit$ | async) && (groupDataService.getActiveGroup() | async)" [type]="AlertTypeEnum.Warning"
[content]="(messagePrefix + '.alert.workflowGroup' | translate:{ name: (getLinkedDSO(groupBeingEdited) | async)?.payload?.name, comcol: (getLinkedDSO(groupBeingEdited) | async)?.payload?.type, comcolEditRolesRoute: (getLinkedEditRolesRoute(groupBeingEdited) | async) })">
[content]="(messagePrefix + '.alert.workflowGroup' | translate:{ name: dsoNameService.getName((getLinkedDSO(groupBeingEdited) | async)?.payload), comcol: (getLinkedDSO(groupBeingEdited) | async)?.payload?.type, comcolEditRolesRoute: (getLinkedEditRolesRoute(groupBeingEdited) | async) })">
</ds-alert>
<ds-form [formId]="formId"

View File

@@ -36,6 +36,8 @@ import { NotificationsServiceStub } from '../../../shared/testing/notifications-
import { Operation } from 'fast-json-patch';
import { ValidateGroupExists } from './validators/group-exists.validator';
import { NoContent } from '../../../core/shared/NoContent.model';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../shared/mocks/dso-name.service.mock';
describe('GroupFormComponent', () => {
let component: GroupFormComponent;
@@ -188,7 +190,7 @@ describe('GroupFormComponent', () => {
translateService = getMockTranslateService();
router = new RouterMock();
notificationService = new NotificationsServiceStub();
TestBed.configureTestingModule({
return TestBed.configureTestingModule({
imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule,
TranslateModule.forRoot({
loader: {
@@ -198,7 +200,8 @@ describe('GroupFormComponent', () => {
}),
],
declarations: [GroupFormComponent],
providers: [GroupFormComponent,
providers: [
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: EPersonDataService, useValue: ePersonDataServiceStub },
{ provide: GroupDataService, useValue: groupsDataServiceStub },
{ provide: DSpaceObjectDataService, useValue: dsoDataServiceStub },
@@ -240,8 +243,8 @@ describe('GroupFormComponent', () => {
fixture.detectChanges();
});
it('should emit a new group using the correct values', waitForAsync(() => {
fixture.whenStable().then(() => {
it('should emit a new group using the correct values', (async () => {
await fixture.whenStable().then(() => {
expect(component.submitForm.emit).toHaveBeenCalledWith(expected);
});
}));
@@ -303,8 +306,8 @@ describe('GroupFormComponent', () => {
expect(groupsDataServiceStub.patch).toHaveBeenCalledWith(expected, operations);
});
it('should emit the existing group using the correct new values', waitForAsync(() => {
fixture.whenStable().then(() => {
it('should emit the existing group using the correct new values', (async () => {
await fixture.whenStable().then(() => {
expect(component.submitForm.emit).toHaveBeenCalledWith(expected2);
});
}));

View File

@@ -46,6 +46,7 @@ import { followLink } from '../../../shared/utils/follow-link-config.model';
import { NoContent } from '../../../core/shared/NoContent.model';
import { Operation } from 'fast-json-patch';
import { ValidateGroupExists } from './validators/group-exists.validator';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
import { environment } from '../../../../environments/environment';
@Component({
@@ -134,7 +135,8 @@ export class GroupFormComponent implements OnInit, OnDestroy {
groupNameValueChangeSubscribe: Subscription;
constructor(public groupDataService: GroupDataService,
constructor(
public groupDataService: GroupDataService,
private ePersonDataService: EPersonDataService,
private dSpaceObjectDataService: DSpaceObjectDataService,
private formBuilderService: FormBuilderService,
@@ -145,7 +147,9 @@ export class GroupFormComponent implements OnInit, OnDestroy {
private authorizationService: AuthorizationDataService,
private modalService: NgbModal,
public requestService: RequestService,
protected changeDetectorRef: ChangeDetectorRef) {
protected changeDetectorRef: ChangeDetectorRef,
public dsoNameService: DSONameService,
) {
}
ngOnInit() {
@@ -331,7 +335,7 @@ export class GroupFormComponent implements OnInit, OnDestroy {
.subscribe((list: PaginatedList<Group>) => {
if (list.totalElements > 0) {
this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.' + notificationSection + '.failure.groupNameInUse', {
name: group.name
name: this.dsoNameService.getName(group),
}));
}
}));
@@ -364,10 +368,10 @@ export class GroupFormComponent implements OnInit, OnDestroy {
getFirstCompletedRemoteData()
).subscribe((rd: RemoteData<Group>) => {
if (rd.hasSucceeded) {
this.notificationsService.success(this.translateService.get(this.messagePrefix + '.notification.edited.success', { name: rd.payload.name }));
this.notificationsService.success(this.translateService.get(this.messagePrefix + '.notification.edited.success', { name: this.dsoNameService.getName(rd.payload) }));
this.submitForm.emit(rd.payload);
} else {
this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.edited.failure', { name: group.name }));
this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.edited.failure', { name: this.dsoNameService.getName(group) }));
this.cancelForm.emit();
}
});
@@ -427,11 +431,11 @@ export class GroupFormComponent implements OnInit, OnDestroy {
this.groupDataService.delete(group.id).pipe(getFirstCompletedRemoteData())
.subscribe((rd: RemoteData<NoContent>) => {
if (rd.hasSucceeded) {
this.notificationsService.success(this.translateService.get(this.messagePrefix + '.notification.deleted.success', { name: group.name }));
this.notificationsService.success(this.translateService.get(this.messagePrefix + '.notification.deleted.success', { name: this.dsoNameService.getName(group) }));
this.onCancel();
} else {
this.notificationsService.error(
this.translateService.get(this.messagePrefix + '.notification.deleted.failure.title', { name: group.name }),
this.translateService.get(this.messagePrefix + '.notification.deleted.failure.title', { name: this.dsoNameService.getName(group) }),
this.translateService.get(this.messagePrefix + '.notification.deleted.failure.content', { cause: rd.errorMessage }));
}
});

View File

@@ -57,8 +57,12 @@
<tbody>
<tr *ngFor="let ePerson of (ePeopleSearchDtos | async)?.page">
<td class="align-middle">{{ePerson.eperson.id}}</td>
<td class="align-middle"><a (click)="ePersonDataService.startEditingNewEPerson(ePerson.eperson)"
[routerLink]="[ePersonDataService.getEPeoplePageRouterLink()]">{{ePerson.eperson.name}}</a></td>
<td class="align-middle">
<a (click)="ePersonDataService.startEditingNewEPerson(ePerson.eperson)"
[routerLink]="[ePersonDataService.getEPeoplePageRouterLink()]">
{{ dsoNameService.getName(ePerson.eperson) }}
</a>
</td>
<td class="align-middle">
{{messagePrefix + '.table.email' | translate}}: {{ ePerson.eperson.email ? ePerson.eperson.email : '-' }}<br/>
{{messagePrefix + '.table.netid' | translate}}: {{ ePerson.eperson.netid ? ePerson.eperson.netid : '-' }}
@@ -69,7 +73,7 @@
(click)="deleteMemberFromGroup(ePerson)"
[disabled]="actionConfig.remove.disabled"
[ngClass]="['btn btn-sm', actionConfig.remove.css]"
title="{{messagePrefix + '.table.edit.buttons.remove' | translate: {name: ePerson.eperson.name} }}">
title="{{messagePrefix + '.table.edit.buttons.remove' | translate: { name: dsoNameService.getName(ePerson.eperson) } }}">
<i [ngClass]="actionConfig.remove.icon"></i>
</button>
@@ -77,7 +81,7 @@
(click)="addMemberToGroup(ePerson)"
[disabled]="actionConfig.add.disabled"
[ngClass]="['btn btn-sm', actionConfig.add.css]"
title="{{messagePrefix + '.table.edit.buttons.add' | translate: {name: ePerson.eperson.name} }}">
title="{{messagePrefix + '.table.edit.buttons.add' | translate: { name: dsoNameService.getName(ePerson.eperson) } }}">
<i [ngClass]="actionConfig.add.icon"></i>
</button>
</div>
@@ -117,8 +121,12 @@
<tbody>
<tr *ngFor="let ePerson of (ePeopleMembersOfGroupDtos | async)?.page">
<td class="align-middle">{{ePerson.eperson.id}}</td>
<td class="align-middle"><a (click)="ePersonDataService.startEditingNewEPerson(ePerson.eperson)"
[routerLink]="[ePersonDataService.getEPeoplePageRouterLink()]">{{ePerson.eperson.name}}</a></td>
<td class="align-middle">
<a (click)="ePersonDataService.startEditingNewEPerson(ePerson.eperson)"
[routerLink]="[ePersonDataService.getEPeoplePageRouterLink()]">
{{ dsoNameService.getName(ePerson.eperson) }}
</a>
</td>
<td class="align-middle">
{{messagePrefix + '.table.email' | translate}}: {{ ePerson.eperson.email ? ePerson.eperson.email : '-' }}<br/>
{{messagePrefix + '.table.netid' | translate}}: {{ ePerson.eperson.netid ? ePerson.eperson.netid : '-' }}
@@ -129,14 +137,14 @@
(click)="deleteMemberFromGroup(ePerson)"
[disabled]="actionConfig.remove.disabled"
[ngClass]="['btn btn-sm', actionConfig.remove.css]"
title="{{messagePrefix + '.table.edit.buttons.remove' | translate: {name: ePerson.eperson.name} }}">
title="{{messagePrefix + '.table.edit.buttons.remove' | translate: { name: dsoNameService.getName(ePerson.eperson) } }}">
<i [ngClass]="actionConfig.remove.icon"></i>
</button>
<button *ngIf="!ePerson.memberOfGroup"
(click)="addMemberToGroup(ePerson)"
[disabled]="actionConfig.add.disabled"
[ngClass]="['btn btn-sm', actionConfig.add.css]"
title="{{messagePrefix + '.table.edit.buttons.add' | translate: {name: ePerson.eperson.name} }}">
title="{{messagePrefix + '.table.edit.buttons.add' | translate: { name: dsoNameService.getName(ePerson.eperson) } }}">
<i [ngClass]="actionConfig.add.icon"></i>
</button>
</div>

View File

@@ -28,6 +28,8 @@ import { NotificationsServiceStub } from '../../../../shared/testing/notificatio
import { RouterMock } from '../../../../shared/mocks/router.mock';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../../../shared/testing/pagination-service.stub';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
describe('MembersListComponent', () => {
let component: MembersListComponent;
@@ -118,7 +120,7 @@ describe('MembersListComponent', () => {
translateService = getMockTranslateService();
paginationService = new PaginationServiceStub();
TestBed.configureTestingModule({
return TestBed.configureTestingModule({
imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule,
TranslateModule.forRoot({
loader: {
@@ -135,6 +137,7 @@ describe('MembersListComponent', () => {
{ provide: FormBuilderService, useValue: builderService },
{ provide: Router, useValue: new RouterMock() },
{ provide: PaginationService, useValue: paginationService },
{ provide: DSONameService, useValue: new DSONameServiceMock() },
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();

View File

@@ -27,6 +27,7 @@ import { NotificationsService } from '../../../../shared/notifications/notificat
import { PaginationComponentOptions } from '../../../../shared/pagination/pagination-component-options.model';
import { EpersonDtoModel } from '../../../../core/eperson/models/eperson-dto.model';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
/**
* Keys to keep track of specific subscriptions
@@ -143,7 +144,8 @@ export class MembersListComponent implements OnInit, OnDestroy {
protected notificationsService: NotificationsService,
protected formBuilder: UntypedFormBuilder,
protected paginationService: PaginationService,
private router: Router
protected router: Router,
public dsoNameService: DSONameService,
) {
this.currentSearchQuery = '';
this.currentSearchScope = 'metadata';
@@ -253,7 +255,7 @@ export class MembersListComponent implements OnInit, OnDestroy {
this.groupDataService.getActiveGroup().pipe(take(1)).subscribe((activeGroup: Group) => {
if (activeGroup != null) {
const response = this.groupDataService.deleteMemberFromGroup(activeGroup, ePerson.eperson);
this.showNotifications('deleteMember', response, ePerson.eperson.name, activeGroup);
this.showNotifications('deleteMember', response, this.dsoNameService.getName(ePerson.eperson), activeGroup);
} else {
this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.failure.noActiveGroup'));
}
@@ -269,7 +271,7 @@ export class MembersListComponent implements OnInit, OnDestroy {
this.groupDataService.getActiveGroup().pipe(take(1)).subscribe((activeGroup: Group) => {
if (activeGroup != null) {
const response = this.groupDataService.addMemberToGroup(activeGroup, ePerson.eperson);
this.showNotifications('addMember', response, ePerson.eperson.name, activeGroup);
this.showNotifications('addMember', response, this.dsoNameService.getName(ePerson.eperson), activeGroup);
} else {
this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.failure.noActiveGroup'));
}

View File

@@ -53,15 +53,19 @@
<tbody>
<tr *ngFor="let group of (searchResults$ | async)?.payload?.page">
<td class="align-middle">{{group.id}}</td>
<td class="align-middle"><a (click)="groupDataService.startEditingNewGroup(group)"
[routerLink]="[groupDataService.getGroupEditPageRouterLink(group)]">{{group.name}}</a></td>
<td class="align-middle">{{(group.object | async)?.payload?.name}}</td>
<td class="align-middle">
<a (click)="groupDataService.startEditingNewGroup(group)"
[routerLink]="[groupDataService.getGroupEditPageRouterLink(group)]">
{{ dsoNameService.getName(group) }}
</a>
</td>
<td class="align-middle">{{ dsoNameService.getName((group.object | async)?.payload) }}</td>
<td class="align-middle">
<div class="btn-group edit-field">
<button *ngIf="(isSubgroupOfGroup(group) | async) && !(isActiveGroup(group) | async)"
(click)="deleteSubgroupFromGroup(group)"
class="btn btn-outline-danger btn-sm deleteButton"
title="{{messagePrefix + '.table.edit.buttons.remove' | translate: {name: group.name} }}">
title="{{messagePrefix + '.table.edit.buttons.remove' | translate: { name: dsoNameService.getName(group) } }}">
<i class="fas fa-trash-alt fa-fw"></i>
</button>
@@ -70,7 +74,7 @@
<button *ngIf="!(isSubgroupOfGroup(group) | async) && !(isActiveGroup(group) | async)"
(click)="addSubgroupToGroup(group)"
class="btn btn-outline-primary btn-sm addButton"
title="{{messagePrefix + '.table.edit.buttons.add' | translate: {name: group.name} }}">
title="{{messagePrefix + '.table.edit.buttons.add' | translate: { name: dsoNameService.getName(group) } }}">
<i class="fas fa-plus fa-fw"></i>
</button>
</div>
@@ -108,14 +112,18 @@
<tbody>
<tr *ngFor="let group of (subGroups$ | async)?.payload?.page">
<td class="align-middle">{{group.id}}</td>
<td class="align-middle"><a (click)="groupDataService.startEditingNewGroup(group)"
[routerLink]="[groupDataService.getGroupEditPageRouterLink(group)]">{{group.name}}</a></td>
<td class="align-middle">{{(group.object | async)?.payload?.name}}</td>
<td class="align-middle">
<a (click)="groupDataService.startEditingNewGroup(group)"
[routerLink]="[groupDataService.getGroupEditPageRouterLink(group)]">
{{ dsoNameService.getName(group) }}
</a>
</td>
<td class="align-middle">{{ dsoNameService.getName((group.object | async)?.payload)}}</td>
<td class="align-middle">
<div class="btn-group edit-field">
<button (click)="deleteSubgroupFromGroup(group)"
class="btn btn-outline-danger btn-sm deleteButton"
title="{{messagePrefix + '.table.edit.buttons.remove' | translate: {name: group.name} }}">
title="{{messagePrefix + '.table.edit.buttons.remove' | translate: { name: dsoNameService.getName(group) } }}">
<i class="fas fa-trash-alt fa-fw"></i>
</button>
</div>

View File

@@ -29,6 +29,8 @@ import { NotificationsServiceStub } from '../../../../shared/testing/notificatio
import { map } from 'rxjs/operators';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../../../shared/testing/pagination-service.stub';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
describe('SubgroupsListComponent', () => {
let component: SubgroupsListComponent;
@@ -108,6 +110,7 @@ describe('SubgroupsListComponent', () => {
],
declarations: [SubgroupsListComponent],
providers: [SubgroupsListComponent,
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: GroupDataService, useValue: groupsDataServiceStub },
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
{ provide: FormBuilderService, useValue: builderService },

View File

@@ -18,6 +18,7 @@ import { PaginationComponentOptions } from '../../../../shared/pagination/pagina
import { NoContent } from '../../../../core/shared/NoContent.model';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { followLink } from '../../../../shared/utils/follow-link-config.model';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
/**
* Keys to keep track of specific subscriptions
@@ -88,7 +89,9 @@ export class SubgroupsListComponent implements OnInit, OnDestroy {
private notificationsService: NotificationsService,
private formBuilder: UntypedFormBuilder,
private paginationService: PaginationService,
private router: Router) {
private router: Router,
public dsoNameService: DSONameService,
) {
this.currentSearchQuery = '';
}
@@ -177,7 +180,7 @@ export class SubgroupsListComponent implements OnInit, OnDestroy {
this.groupDataService.getActiveGroup().pipe(take(1)).subscribe((activeGroup: Group) => {
if (activeGroup != null) {
const response = this.groupDataService.deleteSubGroupFromGroup(activeGroup, subgroup);
this.showNotifications('deleteSubgroup', response, subgroup.name, activeGroup);
this.showNotifications('deleteSubgroup', response, this.dsoNameService.getName(subgroup), activeGroup);
} else {
this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.failure.noActiveGroup'));
}
@@ -193,7 +196,7 @@ export class SubgroupsListComponent implements OnInit, OnDestroy {
if (activeGroup != null) {
if (activeGroup.uuid !== subgroup.uuid) {
const response = this.groupDataService.addSubGroupToGroup(activeGroup, subgroup);
this.showNotifications('addSubgroup', response, subgroup.name, activeGroup);
this.showNotifications('addSubgroup', response, this.dsoNameService.getName(subgroup), activeGroup);
} else {
this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.failure.subgroupToAddIsActiveGroup'));
}

View File

@@ -56,8 +56,8 @@
<tbody>
<tr *ngFor="let groupDto of (groupsDto$ | async)?.page">
<td>{{groupDto.group.id}}</td>
<td>{{groupDto.group.name}}</td>
<td>{{(groupDto.group.object | async)?.payload?.name}}</td>
<td>{{ dsoNameService.getName(groupDto.group) }}</td>
<td>{{ dsoNameService.getName((groupDto.group.object | async)?.payload) }}</td>
<td>{{groupDto.epersons?.totalElements + groupDto.subgroups?.totalElements}}</td>
<td>
<div class="btn-group edit-field">
@@ -65,7 +65,7 @@
<button *ngSwitchCase="true"
[routerLink]="groupService.getGroupEditPageRouterLink(groupDto.group)"
class="btn btn-outline-primary btn-sm btn-edit"
title="{{messagePrefix + 'table.edit.buttons.edit' | translate: {name: groupDto.group.name} }}"
title="{{messagePrefix + 'table.edit.buttons.edit' | translate: {name: dsoNameService.getName(groupDto.group) } }}"
>
<i class="fas fa-edit fa-fw"></i>
</button>
@@ -80,7 +80,7 @@
</ng-container>
<button *ngIf="!groupDto.group?.permanent && groupDto.ableToDelete"
(click)="deleteGroup(groupDto)" class="btn btn-outline-danger btn-sm btn-delete"
title="{{messagePrefix + 'table.edit.buttons.remove' | translate: {name: groupDto.group.name} }}">
title="{{messagePrefix + 'table.edit.buttons.remove' | translate: {name: dsoNameService.getName(groupDto.group) } }}">
<i class="fas fa-trash-alt fa-fw"></i>
</button>
</div>

View File

@@ -32,8 +32,10 @@ import { PaginationService } from '../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../shared/testing/pagination-service.stub';
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
import { NoContent } from '../../core/shared/NoContent.model';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock, UNDEFINED_NAME } from '../../shared/mocks/dso-name.service.mock';
describe('GroupRegistryComponent', () => {
describe('GroupsRegistryComponent', () => {
let component: GroupsRegistryComponent;
let fixture: ComponentFixture<GroupsRegistryComponent>;
let ePersonDataServiceStub: any;
@@ -160,7 +162,7 @@ describe('GroupRegistryComponent', () => {
authorizationService = jasmine.createSpyObj('authorizationService', ['isAuthorized']);
setIsAuthorized(true, true);
paginationService = new PaginationServiceStub();
TestBed.configureTestingModule({
return TestBed.configureTestingModule({
imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule,
TranslateModule.forRoot({
loader: {
@@ -171,6 +173,7 @@ describe('GroupRegistryComponent', () => {
],
declarations: [GroupsRegistryComponent],
providers: [GroupsRegistryComponent,
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: EPersonDataService, useValue: ePersonDataServiceStub },
{ provide: GroupDataService, useValue: groupsDataServiceStub },
{ provide: DSpaceObjectDataService, useValue: dsoDataServiceStub },
@@ -208,7 +211,7 @@ describe('GroupRegistryComponent', () => {
it('should display community/collection name if present', () => {
const collectionNamesFound = fixture.debugElement.queryAll(By.css('#groups tr td:nth-child(3)'));
expect(collectionNamesFound.length).toEqual(2);
expect(collectionNamesFound[0].nativeElement.textContent).toEqual('');
expect(collectionNamesFound[0].nativeElement.textContent).toEqual(UNDEFINED_NAME);
expect(collectionNamesFound[1].nativeElement.textContent).toEqual('testgroupid2objectName');
});

View File

@@ -37,6 +37,7 @@ import { PaginationComponentOptions } from '../../shared/pagination/pagination-c
import { NoContent } from '../../core/shared/NoContent.model';
import { PaginationService } from '../../core/pagination/pagination.service';
import { followLink } from '../../shared/utils/follow-link-config.model';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
@Component({
selector: 'ds-groups-registry',
@@ -104,7 +105,9 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy {
private router: Router,
private authorizationService: AuthorizationDataService,
private paginationService: PaginationService,
public requestService: RequestService) {
public requestService: RequestService,
public dsoNameService: DSONameService,
) {
this.currentSearchQuery = '';
this.searchForm = this.formBuilder.group(({
query: this.currentSearchQuery,
@@ -201,10 +204,10 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy {
.subscribe((rd: RemoteData<NoContent>) => {
if (rd.hasSucceeded) {
this.deletedGroupsIds = [...this.deletedGroupsIds, group.group.id];
this.notificationsService.success(this.translateService.get(this.messagePrefix + 'notification.deleted.success', { name: group.group.name }));
this.notificationsService.success(this.translateService.get(this.messagePrefix + 'notification.deleted.success', { name: this.dsoNameService.getName(group.group) }));
} else {
this.notificationsService.error(
this.translateService.get(this.messagePrefix + 'notification.deleted.failure.title', { name: group.group.name }),
this.translateService.get(this.messagePrefix + 'notification.deleted.failure.title', { name: this.dsoNameService.getName(group.group) }),
this.translateService.get(this.messagePrefix + 'notification.deleted.failure.content', { cause: rd.errorMessage }));
}
});

View File

@@ -13,6 +13,7 @@ import { BitstreamDataService } from '../../../../../core/data/bitstream-data.se
import { GenericConstructor } from '../../../../../core/shared/generic-constructor';
import { ListableObjectDirective } from '../../../../../shared/object-collection/shared/listable-object/listable-object.directive';
import { ThemeService } from '../../../../../shared/theme-support/theme.service';
import { DSONameService } from '../../../../../core/breadcrumbs/dso-name.service';
@listableObjectComponent(ItemSearchResult, ViewMode.GridElement, Context.AdminSearch)
@Component({
@@ -28,12 +29,14 @@ export class ItemAdminSearchResultGridElementComponent extends SearchResultGridE
@ViewChild('badges', { static: true }) badges: ElementRef;
@ViewChild('buttons', { static: true }) buttons: ElementRef;
constructor(protected truncatableService: TruncatableService,
constructor(
public dsoNameService: DSONameService,
protected truncatableService: TruncatableService,
protected bitstreamDataService: BitstreamDataService,
private themeService: ThemeService,
private componentFactoryResolver: ComponentFactoryResolver
private componentFactoryResolver: ComponentFactoryResolver,
) {
super(truncatableService, bitstreamDataService);
super(dsoNameService, truncatableService, bitstreamDataService);
}
/**

View File

@@ -82,7 +82,7 @@ export class SupervisionOrderGroupSelectorComponent {
getFirstCompletedRemoteData(),
).subscribe((rd: RemoteData<SupervisionOrder>) => {
if (rd.state === 'Success') {
this.notificationsService.success(this.translateService.get('supervision-group-selector.notification.create.success.title', { name: this.selectedGroup.name }));
this.notificationsService.success(this.translateService.get('supervision-group-selector.notification.create.success.title', { name: this.dsoNameService.getName(this.selectedGroup) }));
this.create.emit(rd.payload);
this.close();
} else {

View File

@@ -7,7 +7,7 @@
<a class="badge badge-primary mr-1 mb-1 text-capitalize mw-100 text-truncate" *ngFor="let supervisionOrder of supervisionOrders" data-test="soBadge"
[ngbTooltip]="'workflow-item.search.result.list.element.supervised.remove-tooltip' | translate"
(click)="$event.preventDefault(); $event.stopImmediatePropagation(); deleteSupervisionOrder(supervisionOrder)" aria-label="Close">
{{supervisionOrder.group.name}}
{{ dsoNameService.getName(supervisionOrder.group) }}
<span aria-hidden="true"> ×</span>
</a>
</div>

View File

@@ -8,6 +8,7 @@ import { Group } from '../../../../../../core/eperson/models/group.model';
import { getFirstCompletedRemoteData } from '../../../../../../core/shared/operators';
import { isNotEmpty } from '../../../../../../shared/empty.util';
import { RemoteData } from '../../../../../../core/data/remote-data';
import { DSONameService } from '../../../../../../core/breadcrumbs/dso-name.service';
export interface SupervisionOrderListEntry {
supervisionOrder: SupervisionOrder;
@@ -33,6 +34,11 @@ export class SupervisionOrderStatusComponent implements OnChanges {
@Output() delete: EventEmitter<SupervisionOrderListEntry> = new EventEmitter<SupervisionOrderListEntry>();
constructor(
public dsoNameService: DSONameService,
) {
}
ngOnChanges(changes: SimpleChanges): void {
if (changes && changes.supervisionOrderList) {
this.getSupervisionOrderEntries(changes.supervisionOrderList.currentValue)

View File

@@ -23,6 +23,7 @@ import {
import { take } from 'rxjs/operators';
import { WorkflowItemSearchResult } from '../../../../../shared/object-collection/shared/workflow-item-search-result.model';
import { ThemeService } from '../../../../../shared/theme-support/theme.service';
import { DSONameService } from '../../../../../core/breadcrumbs/dso-name.service';
@listableObjectComponent(WorkflowItemSearchResult, ViewMode.GridElement, Context.AdminWorkflowSearch)
@Component({
@@ -55,13 +56,14 @@ export class WorkflowItemSearchResultAdminWorkflowGridElementComponent extends S
public item$: Observable<Item>;
constructor(
public dsoNameService: DSONameService,
private componentFactoryResolver: ComponentFactoryResolver,
private linkService: LinkService,
protected truncatableService: TruncatableService,
private themeService: ThemeService,
protected bitstreamDataService: BitstreamDataService
) {
super(truncatableService, bitstreamDataService);
super(dsoNameService, truncatableService, bitstreamDataService);
}
/**

View File

@@ -1,4 +1,4 @@
import { Component, ComponentFactoryResolver, ElementRef, ViewChild } from '@angular/core';
import { Component, ComponentFactoryResolver, ElementRef, ViewChild, OnInit } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { map, mergeMap, take, tap } from 'rxjs/operators';
@@ -36,6 +36,7 @@ import { DSpaceObject } from '../../../../../core/shared/dspace-object.model';
import { SupervisionOrder } from '../../../../../core/supervision-order/models/supervision-order.model';
import { PaginatedList } from '../../../../../core/data/paginated-list.model';
import { SupervisionOrderDataService } from '../../../../../core/supervision-order/supervision-order-data.service';
import { DSONameService } from '../../../../../core/breadcrumbs/dso-name.service';
@listableObjectComponent(WorkspaceItemSearchResult, ViewMode.GridElement, Context.AdminWorkflowSearch)
@Component({
@@ -46,7 +47,7 @@ import { SupervisionOrderDataService } from '../../../../../core/supervision-ord
/**
* The component for displaying a grid element for an workflow item on the admin workflow search page
*/
export class WorkspaceItemSearchResultAdminWorkflowGridElementComponent extends SearchResultGridElementComponent<WorkspaceItemSearchResult, WorkspaceItem> {
export class WorkspaceItemSearchResultAdminWorkflowGridElementComponent extends SearchResultGridElementComponent<WorkspaceItemSearchResult, WorkspaceItem> implements OnInit {
/**
* The item linked to the workspace item
@@ -79,6 +80,7 @@ export class WorkspaceItemSearchResultAdminWorkflowGridElementComponent extends
@ViewChild('buttons', { static: true }) buttons: ElementRef;
constructor(
public dsoNameService: DSONameService,
private componentFactoryResolver: ComponentFactoryResolver,
private linkService: LinkService,
protected truncatableService: TruncatableService,
@@ -86,7 +88,7 @@ export class WorkspaceItemSearchResultAdminWorkflowGridElementComponent extends
protected bitstreamDataService: BitstreamDataService,
protected supervisionOrderDataService: SupervisionOrderDataService,
) {
super(truncatableService, bitstreamDataService);
super(dsoNameService, truncatableService, bitstreamDataService);
}
/**

View File

@@ -39,7 +39,7 @@ export class WorkflowItemSearchResultAdminWorkflowListElementComponent extends S
constructor(private linkService: LinkService,
protected truncatableService: TruncatableService,
protected dsoNameService: DSONameService,
public dsoNameService: DSONameService,
@Inject(APP_CONFIG) protected appConfig: AppConfig
) {
super(truncatableService, dsoNameService, appConfig);

View File

@@ -59,7 +59,7 @@ export class WorkspaceItemSearchResultAdminWorkflowListElementComponent extends
public supervisionOrder$: BehaviorSubject<SupervisionOrder[]> = new BehaviorSubject<SupervisionOrder[]>([]);
constructor(private linkService: LinkService,
protected dsoNameService: DSONameService,
public dsoNameService: DSONameService,
protected supervisionOrderDataService: SupervisionOrderDataService,
protected truncatableService: TruncatableService,
@Inject(APP_CONFIG) protected appConfig: AppConfig

View File

@@ -1,5 +1,5 @@
<div class="container">
<h3>{{'bitstream.download.page' | translate:{bitstream: (bitstream$ | async)?.name} }}</h3>
<h3>{{'bitstream.download.page' | translate:{ bitstream: dsoNameService.getName((bitstream$ | async)) } }}</h3>
<div class="pt-3">
<button (click)="back()" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left"></i> {{'bitstream.download.page.back' | translate}}

View File

@@ -14,6 +14,7 @@ import { getForbiddenRoute } from '../../app-routing-paths';
import { RemoteData } from '../../core/data/remote-data';
import { redirectOn4xx } from '../../core/shared/authorized.operators';
import { Location } from '@angular/common';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
@Component({
selector: 'ds-bitstream-download-page',
@@ -36,6 +37,7 @@ export class BitstreamDownloadPageComponent implements OnInit {
private fileService: FileService,
private hardRedirectService: HardRedirectService,
private location: Location,
public dsoNameService: DSONameService,
) {
}

View File

@@ -1,6 +1,5 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { EditBitstreamPageComponent } from './edit-bitstream-page/edit-bitstream-page.component';
import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
import { BitstreamPageResolver } from './bitstream-page.resolver';
import { BitstreamDownloadPageComponent } from './bitstream-download-page/bitstream-download-page.component';
@@ -13,6 +12,7 @@ import { LegacyBitstreamUrlResolver } from './legacy-bitstream-url.resolver';
import { BitstreamBreadcrumbResolver } from '../core/breadcrumbs/bitstream-breadcrumb.resolver';
import { BitstreamBreadcrumbsService } from '../core/breadcrumbs/bitstream-breadcrumbs.service';
import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
import { ThemedEditBitstreamPageComponent } from './edit-bitstream-page/themed-edit-bitstream-page.component';
const EDIT_BITSTREAM_PATH = ':id/edit';
const EDIT_BITSTREAM_AUTHORIZATIONS_PATH = ':id/authorizations';
@@ -49,7 +49,7 @@ const EDIT_BITSTREAM_AUTHORIZATIONS_PATH = ':id/authorizations';
},
{
path: EDIT_BITSTREAM_PATH,
component: EditBitstreamPageComponent,
component: ThemedEditBitstreamPageComponent,
resolve: {
bitstream: BitstreamPageResolver,
breadcrumb: BitstreamBreadcrumbResolver,

View File

@@ -7,6 +7,7 @@ import { BitstreamAuthorizationsComponent } from './bitstream-authorizations/bit
import { FormModule } from '../shared/form/form.module';
import { ResourcePoliciesModule } from '../shared/resource-policies/resource-policies.module';
import { BitstreamDownloadPageComponent } from './bitstream-download-page/bitstream-download-page.component';
import { ThemedEditBitstreamPageComponent } from './edit-bitstream-page/themed-edit-bitstream-page.component';
/**
* This module handles all components that are necessary for Bitstream related pages
@@ -22,6 +23,7 @@ import { BitstreamDownloadPageComponent } from './bitstream-download-page/bitstr
declarations: [
BitstreamAuthorizationsComponent,
EditBitstreamPageComponent,
ThemedEditBitstreamPageComponent,
BitstreamDownloadPageComponent,
]
})

View File

@@ -8,7 +8,7 @@
<div class="container">
<div class="row">
<div class="col-12">
<h3>{{bitstreamRD?.payload?.name}} <span class="text-muted">({{bitstreamRD?.payload?.sizeBytes | dsFileSize}})</span></h3>
<h3>{{dsoNameService.getName(bitstreamRD?.payload)}} <span class="text-muted">({{bitstreamRD?.payload?.sizeBytes | dsFileSize}})</span></h3>
</div>
</div>
</div>

View File

@@ -395,7 +395,7 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
private formService: DynamicFormService,
private translate: TranslateService,
private bitstreamService: BitstreamDataService,
private dsoNameService: DSONameService,
public dsoNameService: DSONameService,
private notificationsService: NotificationsService,
private bitstreamFormatService: BitstreamFormatDataService) {
}

View File

@@ -0,0 +1,22 @@
import { Component } from '@angular/core';
import { EditBitstreamPageComponent } from './edit-bitstream-page.component';
import { ThemedComponent } from '../../shared/theme-support/themed.component';
@Component({
selector: 'ds-themed-edit-bitstream-page',
styleUrls: [],
templateUrl: '../../shared/theme-support/themed.component.html',
})
export class ThemedEditBitstreamPageComponent extends ThemedComponent<EditBitstreamPageComponent> {
protected getComponentName(): string {
return 'EditBitstreamPageComponent';
}
protected importThemedComponent(themeName: string): Promise<any> {
return import(`../../../themes/${themeName}/app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component`);
}
protected importUnthemedComponent(): Promise<any> {
return import('./edit-bitstream-page.component');
}
}

View File

@@ -18,6 +18,7 @@ import { isValidDate } from '../../shared/date.util';
import { APP_CONFIG, AppConfig } from '../../../config/app-config.interface';
import { RemoteData } from '../../core/data/remote-data';
import { Item } from '../../core/shared/item.model';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
@Component({
selector: 'ds-browse-by-date-page',
@@ -42,8 +43,10 @@ export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent {
protected router: Router,
protected paginationService: PaginationService,
protected cdRef: ChangeDetectorRef,
@Inject(APP_CONFIG) public appConfig: AppConfig) {
super(route, browseService, dsoService, paginationService, router, appConfig);
@Inject(APP_CONFIG) public appConfig: AppConfig,
public dsoNameService: DSONameService,
) {
super(route, browseService, dsoService, paginationService, router, appConfig, dsoNameService);
}
ngOnInit(): void {

View File

@@ -4,6 +4,8 @@ import { of as observableOf } from 'rxjs';
import { createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils';
import { BrowseDefinition } from '../core/shared/browse-definition.model';
import { BrowseByDataType } from './browse-by-switcher/browse-by-decorator';
import { DSONameServiceMock } from '../shared/mocks/dso-name.service.mock';
import { DSONameService } from '../core/breadcrumbs/dso-name.service';
describe('BrowseByGuard', () => {
describe('canActivate', () => {
@@ -33,7 +35,7 @@ describe('BrowseByGuard', () => {
findById: () => createSuccessfulRemoteDataObject$(browseDefinition)
};
guard = new BrowseByGuard(dsoService, translateService, browseDefinitionService);
guard = new BrowseByGuard(dsoService, translateService, browseDefinitionService, new DSONameServiceMock() as DSONameService);
});
it('should return true, and sets up the data correctly, with a scope and value', () => {

View File

@@ -3,11 +3,13 @@ import { Injectable } from '@angular/core';
import { DSpaceObjectDataService } from '../core/data/dspace-object-data.service';
import { hasNoValue, hasValue } from '../shared/empty.util';
import { map, switchMap } from 'rxjs/operators';
import { getFirstSucceededRemoteData, getFirstSucceededRemoteDataPayload } from '../core/shared/operators';
import { getFirstSucceededRemoteDataPayload } from '../core/shared/operators';
import { TranslateService } from '@ngx-translate/core';
import { Observable, of as observableOf } from 'rxjs';
import { BrowseDefinitionDataService } from '../core/browse/browse-definition-data.service';
import { BrowseDefinition } from '../core/shared/browse-definition.model';
import { DSONameService } from '../core/breadcrumbs/dso-name.service';
import { DSpaceObject } from '../core/shared/dspace-object.model';
@Injectable()
/**
@@ -17,7 +19,9 @@ export class BrowseByGuard implements CanActivate {
constructor(protected dsoService: DSpaceObjectDataService,
protected translate: TranslateService,
protected browseDefinitionService: BrowseDefinitionDataService) {
protected browseDefinitionService: BrowseDefinitionDataService,
protected dsoNameService: DSONameService,
) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
@@ -31,14 +35,14 @@ export class BrowseByGuard implements CanActivate {
}
const scope = route.queryParams.scope;
const value = route.queryParams.value;
const metadataTranslated = this.translate.instant('browse.metadata.' + id);
const metadataTranslated = this.translate.instant(`browse.metadata.${id}`);
return browseDefinition$.pipe(
switchMap((browseDefinition) => {
switchMap((browseDefinition: BrowseDefinition) => {
if (hasValue(scope)) {
const dsoAndMetadata$ = this.dsoService.findById(scope).pipe(getFirstSucceededRemoteData());
return dsoAndMetadata$.pipe(
map((dsoRD) => {
const name = dsoRD.payload.name;
const dso$: Observable<DSpaceObject> = this.dsoService.findById(scope).pipe(getFirstSucceededRemoteDataPayload());
return dso$.pipe(
map((dso: DSpaceObject) => {
const name = this.dsoNameService.getName(dso);
route.data = this.createData(title, id, browseDefinition, name, metadataTranslated, value, route);
return true;
})

View File

@@ -5,7 +5,7 @@
<header class="comcol-header mr-auto">
<!-- Parent Name -->
<ds-comcol-page-header [name]="parentContext.name">
<ds-comcol-page-header [name]="dsoNameService.getName(parentContext)">
</ds-comcol-page-header>
<!-- Collection logo -->
<ds-comcol-page-logo *ngIf="logo$"
@@ -35,12 +35,12 @@
<ds-browse-by *ngIf="startsWithOptions" class="col-xs-12 w-100"
title="{{'browse.title' | translate:
{
collection: (parent$ | async)?.payload?.name || '',
collection: dsoNameService.getName((parent$ | async)?.payload),
field: 'browse.metadata.' + browseId | translate,
startsWith: (startsWith)? ('browse.startsWith' | translate: { startsWith: '&quot;' + startsWith + '&quot;' }) : '',
value: (value)? '&quot;' + value + '&quot;': ''
} }}"
parentname="{{(parent$ | async)?.payload?.name || ''}}"
parentname="{{dsoNameService.getName((parent$ | async)?.payload)}}"
[objects$]="(items$ !== undefined)? items$ : browseEntries$"
[paginationConfig]="(currentPagination$ |async)"
[sortConfig]="(currentSort$ |async)"

View File

@@ -21,6 +21,7 @@ import { Bitstream } from '../../core/shared/bitstream.model';
import { Collection } from '../../core/shared/collection.model';
import { Community } from '../../core/shared/community.model';
import { APP_CONFIG, AppConfig } from '../../../config/app-config.interface';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
export const BBM_PAGINATION_ID = 'bbm';
@@ -126,7 +127,9 @@ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy {
protected dsoService: DSpaceObjectDataService,
protected paginationService: PaginationService,
protected router: Router,
@Inject(APP_CONFIG) public appConfig: AppConfig) {
@Inject(APP_CONFIG) public appConfig: AppConfig,
public dsoNameService: DSONameService,
) {
this.fetchThumbnails = this.appConfig.browseBy.showThumbnails;
this.paginationConfig = Object.assign(new PaginationComponentOptions(), {

View File

@@ -13,6 +13,7 @@ import { PaginationService } from '../../core/pagination/pagination.service';
import { map } from 'rxjs/operators';
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
import { AppConfig, APP_CONFIG } from '../../../config/app-config.interface';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
@Component({
selector: 'ds-browse-by-title-page',
@@ -29,8 +30,10 @@ export class BrowseByTitlePageComponent extends BrowseByMetadataPageComponent {
protected dsoService: DSpaceObjectDataService,
protected paginationService: PaginationService,
protected router: Router,
@Inject(APP_CONFIG) public appConfig: AppConfig) {
super(route, browseService, dsoService, paginationService, router, appConfig);
@Inject(APP_CONFIG) public appConfig: AppConfig,
public dsoNameService: DSONameService,
) {
super(route, browseService, dsoService, paginationService, router, appConfig, dsoNameService);
}
ngOnInit(): void {

View File

@@ -157,7 +157,7 @@ export class CollectionItemMapperComponent implements OnInit {
scope: undefined,
dsoTypes: [DSpaceObjectType.ITEM],
sort: this.defaultSortOptions
}), 10000).pipe(
}), 10000, undefined, undefined, followLink('owningCollection')).pipe(
toDSpaceObjectListRD(),
startWith(undefined)
);

View File

@@ -8,7 +8,7 @@
<header class="comcol-header mr-auto">
<!-- Collection Name -->
<ds-comcol-page-header
[name]="collection.name">
[name]="dsoNameService.getName(collection)">
</ds-comcol-page-header>
<!-- Collection logo -->
<ds-comcol-page-logo *ngIf="logoRD$"

View File

@@ -29,6 +29,7 @@ import { FeatureID } from '../core/data/feature-authorization/feature-id';
import { getCollectionPageRoute } from './collection-page-routing-paths';
import { redirectOn4xx } from '../core/shared/authorized.operators';
import { BROWSE_LINKS_TO_FOLLOW } from '../core/browse/browse.service';
import { DSONameService } from '../core/breadcrumbs/dso-name.service';
import { APP_CONFIG, AppConfig } from '../../../src/config/app-config.interface';
@Component({
@@ -70,6 +71,7 @@ export class CollectionPageComponent implements OnInit {
private authService: AuthService,
private paginationService: PaginationService,
private authorizationDataService: AuthorizationDataService,
public dsoNameService: DSONameService,
@Inject(APP_CONFIG) public appConfig: AppConfig,
) {
this.paginationConfig = Object.assign(new PaginationComponentOptions(), {

View File

@@ -1,7 +1,7 @@
<div class="container">
<div class="row">
<div class="col-12 pb-4">
<h2 id="sub-header" class="border-bottom pb-2">{{'collection.create.sub-head' | translate:{ parent: (parentRD$| async)?.payload.name } }}</h2>
<h2 id="sub-header" class="border-bottom pb-2">{{'collection.create.sub-head' | translate:{ parent: dsoNameService.getName((parentRD$| async)?.payload) } }}</h2>
</div>
</div>
<ds-collection-form (submitForm)="onSubmit($event)"

View File

@@ -13,16 +13,19 @@ import { CreateCollectionPageComponent } from './create-collection-page.componen
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
import { RequestService } from '../../core/data/request.service';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../shared/mocks/dso-name.service.mock';
describe('CreateCollectionPageComponent', () => {
let comp: CreateCollectionPageComponent;
let fixture: ComponentFixture<CreateCollectionPageComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
return TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
declarations: [CreateCollectionPageComponent],
providers: [
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: CollectionDataService, useValue: {} },
{
provide: CommunityDataService,

View File

@@ -8,6 +8,7 @@ import { CollectionDataService } from '../../core/data/collection-data.service';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
import { RequestService } from '../../core/data/request.service';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
/**
* Component that represents the page where a user can create a new Collection
@@ -22,6 +23,7 @@ export class CreateCollectionPageComponent extends CreateComColPageComponent<Col
protected type = Collection.type;
public constructor(
public dsoNameService: DSONameService,
protected communityDataService: CommunityDataService,
protected collectionDataService: CollectionDataService,
protected routeService: RouteService,
@@ -30,6 +32,6 @@ export class CreateCollectionPageComponent extends CreateComColPageComponent<Col
protected translate: TranslateService,
protected requestService: RequestService
) {
super(collectionDataService, communityDataService, routeService, router, notificationsService, translate, requestService);
super(collectionDataService, dsoNameService, communityDataService, routeService, router, notificationsService, translate, requestService);
}
}

View File

@@ -3,7 +3,7 @@
<ng-container *ngVar="(dsoRD$ | async)?.payload as dso">
<div class="col-12 pb-4">
<h2 id="header" class="border-bottom pb-2">{{ 'collection.delete.head' | translate}}</h2>
<p class="pb-2">{{ 'collection.delete.text' | translate:{ dso: dso.name } }}</p>
<p class="pb-2">{{ 'collection.delete.text' | translate:{ dso: dsoNameService.getName(dso) } }}</p>
<div class="form-group row">
<div class="col text-right space-children-mr">
<button class="btn btn-outline-secondary" (click)="onCancel(dso)" [disabled]="(processing$ | async)">

View File

@@ -10,6 +10,8 @@ import { NotificationsService } from '../../shared/notifications/notifications.s
import { DeleteCollectionPageComponent } from './delete-collection-page.component';
import { CollectionDataService } from '../../core/data/collection-data.service';
import { RequestService } from '../../core/data/request.service';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../shared/mocks/dso-name.service.mock';
describe('DeleteCollectionPageComponent', () => {
let comp: DeleteCollectionPageComponent;
@@ -20,6 +22,7 @@ describe('DeleteCollectionPageComponent', () => {
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
declarations: [DeleteCollectionPageComponent],
providers: [
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: CollectionDataService, useValue: {} },
{ provide: ActivatedRoute, useValue: { data: observableOf({ dso: { payload: {} } }) } },
{ provide: NotificationsService, useValue: {} },

View File

@@ -5,6 +5,7 @@ import { NotificationsService } from '../../shared/notifications/notifications.s
import { CollectionDataService } from '../../core/data/collection-data.service';
import { Collection } from '../../core/shared/collection.model';
import { TranslateService } from '@ngx-translate/core';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
/**
* Component that represents the page where a user can delete an existing Collection
@@ -19,11 +20,12 @@ export class DeleteCollectionPageComponent extends DeleteComColPageComponent<Col
public constructor(
protected dsoDataService: CollectionDataService,
public dsoNameService: DSONameService,
protected router: Router,
protected route: ActivatedRoute,
protected notifications: NotificationsService,
protected translate: TranslateService,
) {
super(dsoDataService, router, route, notifications, translate);
super(dsoDataService, dsoNameService, router, route, notifications, translate);
}
}

View File

@@ -15,6 +15,8 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { ComcolModule } from '../../../shared/comcol/comcol.module';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../shared/mocks/dso-name.service.mock';
describe('CollectionRolesComponent', () => {
@@ -79,6 +81,7 @@ describe('CollectionRolesComponent', () => {
],
providers: [
{ provide: ActivatedRoute, useValue: route },
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: RequestService, useValue: requestService },
{ provide: GroupDataService, useValue: groupDataService },
{ provide: NotificationsService, useClass: NotificationsServiceStub }

View File

@@ -2,7 +2,7 @@
<div class="row">
<div class="col-12" *ngVar="(itemRD$ | async) as itemRD">
<ng-container *ngIf="itemRD?.hasSucceeded">
<h2 class="border-bottom">{{ 'collection.edit.template.head' | translate:{ collection: collection?.name } }}</h2>
<h2 class="border-bottom">{{ 'collection.edit.template.head' | translate:{ collection: dsoNameService.getName(collection) } }}</h2>
<ds-themed-dso-edit-metadata [updateDataService]="itemTemplateService" [dso]="itemRD?.payload"></ds-themed-dso-edit-metadata>
<button [routerLink]="getCollectionEditUrl(collection)" class="btn btn-outline-secondary">{{ 'collection.edit.template.cancel' | translate }}</button>
</ng-container>

View File

@@ -9,6 +9,7 @@ import { getCollectionEditRoute } from '../collection-page-routing-paths';
import { Item } from '../../core/shared/item.model';
import { getFirstSucceededRemoteDataPayload } from '../../core/shared/operators';
import { AlertType } from '../../shared/alert/aletr-type';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
@Component({
selector: 'ds-edit-item-template-page',
@@ -35,8 +36,11 @@ export class EditItemTemplatePageComponent implements OnInit {
*/
AlertTypeEnum = AlertType;
constructor(protected route: ActivatedRoute,
public itemTemplateService: ItemTemplateDataService) {
constructor(
protected route: ActivatedRoute,
public itemTemplateService: ItemTemplateDataService,
public dsoNameService: DSONameService,
) {
}
ngOnInit(): void {

View File

@@ -2,18 +2,22 @@ import { first } from 'rxjs/operators';
import { ItemTemplatePageResolver } from './item-template-page.resolver';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../shared/mocks/dso-name.service.mock';
describe('ItemTemplatePageResolver', () => {
describe('resolve', () => {
let resolver: ItemTemplatePageResolver;
let itemTemplateService: any;
let dsoNameService: DSONameServiceMock;
const uuid = '1234-65487-12354-1235';
beforeEach(() => {
itemTemplateService = {
findByCollectionID: (id: string) => createSuccessfulRemoteDataObject$({ id })
};
resolver = new ItemTemplatePageResolver(itemTemplateService);
dsoNameService = new DSONameServiceMock();
resolver = new ItemTemplatePageResolver(dsoNameService as DSONameService, itemTemplateService);
});
it('should resolve an item template with the correct id', (done) => {

View File

@@ -6,13 +6,17 @@ import { ItemTemplateDataService } from '../../core/data/item-template-data.serv
import { Observable } from 'rxjs';
import { followLink } from '../../shared/utils/follow-link-config.model';
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
/**
* This class represents a resolver that requests a specific collection's item template before the route is activated
*/
@Injectable()
export class ItemTemplatePageResolver implements Resolve<RemoteData<Item>> {
constructor(private itemTemplateService: ItemTemplateDataService) {
constructor(
public dsoNameService: DSONameService,
private itemTemplateService: ItemTemplateDataService,
) {
}
/**

View File

@@ -25,8 +25,8 @@
class="example-tree-node expandable-node">
<div class="btn-group">
<button type="button" class="btn btn-default" cdkTreeNodeToggle
[title]="'toggle ' + node.name"
[attr.aria-label]="'toggle ' + node.name"
[title]="'toggle ' + dsoNameService.getName(node.payload)"
[attr.aria-label]="'toggle ' + dsoNameService.getName(node.payload)"
(click)="toggleExpanded(node)"
[ngClass]="(hasChild(null, node)| async) ? 'visible' : 'invisible'"
[attr.data-test]="(hasChild(null, node)| async) ? 'expand-button' : ''">
@@ -35,7 +35,7 @@
</button>
<h5 class="align-middle pt-2">
<a [routerLink]="node.route" class="lead">
{{node.name}}
{{ dsoNameService.getName(node.payload) }}
</a>
</h5>
</div>
@@ -66,12 +66,11 @@
class="example-tree-node childless-node">
<div class="btn-group">
<button type="button" class="btn btn-default" cdkTreeNodeToggle>
<span class="fa fa-chevron-right invisible"
aria-hidden="true"></span>
<span class="fa fa-chevron-right invisible" aria-hidden="true"></span>
</button>
<h6 class="align-middle pt-2">
<a [routerLink]="node.route" class="lead">
{{node.name}}
{{ dsoNameService.getName(node.payload) }}
</a>
</h6>
</div>

View File

@@ -7,6 +7,7 @@ import { FlatTreeControl } from '@angular/cdk/tree';
import { isEmpty } from '../../shared/empty.util';
import { FlatNode } from '../flat-node.model';
import { FindListOptions } from '../../core/data/find-list-options.model';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
/**
* A tree-structured list of nodes representing the communities, their subCommunities and collections.
@@ -32,7 +33,10 @@ export class CommunityListComponent implements OnInit, OnDestroy {
paginationConfig: FindListOptions;
constructor(private communityListService: CommunityListService) {
constructor(
protected communityListService: CommunityListService,
public dsoNameService: DSONameService,
) {
this.paginationConfig = new FindListOptions();
this.paginationConfig.elementsPerPage = 2;
this.paginationConfig.currentPage = 1;

View File

@@ -5,7 +5,7 @@
<div class="d-flex flex-row border-bottom mb-4 pb-4">
<header class="comcol-header mr-auto">
<!-- Community name -->
<ds-comcol-page-header [name]="communityPayload.name"></ds-comcol-page-header>
<ds-comcol-page-header [name]="dsoNameService.getName(communityPayload)"></ds-comcol-page-header>
<!-- Community logo -->
<ds-comcol-page-logo *ngIf="logoRD$" [logo]="(logoRD$ | async)?.payload" [alternateText]="'Community Logo'">
</ds-comcol-page-logo>

View File

@@ -19,6 +19,7 @@ import { AuthorizationDataService } from '../core/data/feature-authorization/aut
import { FeatureID } from '../core/data/feature-authorization/feature-id';
import { getCommunityPageRoute } from './community-page-routing-paths';
import { redirectOn4xx } from '../core/shared/authorized.operators';
import { DSONameService } from '../core/breadcrumbs/dso-name.service';
@Component({
selector: 'ds-community-page',
@@ -57,7 +58,8 @@ export class CommunityPageComponent implements OnInit {
private route: ActivatedRoute,
private router: Router,
private authService: AuthService,
private authorizationDataService: AuthorizationDataService
private authorizationDataService: AuthorizationDataService,
public dsoNameService: DSONameService,
) {
}

View File

@@ -3,7 +3,7 @@
<div class="col-12 pb-4">
<ng-container *ngVar="(parentRD$ | async)?.payload as parent">
<h2 *ngIf="!parent" id="header" class="border-bottom pb-2">{{ 'community.create.head' | translate }}</h2>
<h2 *ngIf="parent" id="sub-header" class="border-bottom pb-2">{{ 'community.create.sub-head' | translate:{ parent: parent.name } }}</h2>
<h2 *ngIf="parent" id="sub-header" class="border-bottom pb-2">{{ 'community.create.sub-head' | translate:{ parent: dsoNameService.getName(parent) } }}</h2>
</ng-container>
</div>
</div>

View File

@@ -7,6 +7,7 @@ import { CreateComColPageComponent } from '../../shared/comcol/comcol-forms/crea
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
import { RequestService } from '../../core/data/request.service';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
/**
* Component that represents the page where a user can create a new Community
@@ -22,12 +23,13 @@ export class CreateCommunityPageComponent extends CreateComColPageComponent<Comm
public constructor(
protected communityDataService: CommunityDataService,
public dsoNameService: DSONameService,
protected routeService: RouteService,
protected router: Router,
protected notificationsService: NotificationsService,
protected translate: TranslateService,
protected requestService: RequestService
) {
super(communityDataService, communityDataService, routeService, router, notificationsService, translate, requestService);
super(communityDataService, dsoNameService, communityDataService, routeService, router, notificationsService, translate, requestService);
}
}

View File

@@ -3,7 +3,7 @@
<ng-container *ngVar="(dsoRD$ | async)?.payload as dso">
<div class="col-12 pb-4">
<h2 id="header" class="border-bottom pb-2">{{ 'community.delete.head' | translate}}</h2>
<p class="pb-2">{{ 'community.delete.text' | translate:{ dso: dso.name } }}</p>
<p class="pb-2">{{ 'community.delete.text' | translate:{ dso: dsoNameService.getName(dso) } }}</p>
<div class="form-group row">
<div class="col text-right space-children-mr">
<button class="btn btn-outline-secondary" (click)="onCancel(dso)" [disabled]="(processing$ | async)">

View File

@@ -10,6 +10,8 @@ import { NotificationsService } from '../../shared/notifications/notifications.s
import { SharedModule } from '../../shared/shared.module';
import { DeleteCommunityPageComponent } from './delete-community-page.component';
import { RequestService } from '../../core/data/request.service';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../shared/mocks/dso-name.service.mock';
describe('DeleteCommunityPageComponent', () => {
let comp: DeleteCommunityPageComponent;
@@ -20,6 +22,7 @@ describe('DeleteCommunityPageComponent', () => {
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
declarations: [DeleteCommunityPageComponent],
providers: [
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: CommunityDataService, useValue: {} },
{ provide: ActivatedRoute, useValue: { data: observableOf({ dso: { payload: {} } }) } },
{ provide: NotificationsService, useValue: {} },

View File

@@ -5,6 +5,7 @@ import { ActivatedRoute, Router } from '@angular/router';
import { DeleteComColPageComponent } from '../../shared/comcol/comcol-forms/delete-comcol-page/delete-comcol-page.component';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
/**
* Component that represents the page where a user can delete an existing Community
@@ -19,12 +20,13 @@ export class DeleteCommunityPageComponent extends DeleteComColPageComponent<Comm
public constructor(
protected dsoDataService: CommunityDataService,
public dsoNameService: DSONameService,
protected router: Router,
protected route: ActivatedRoute,
protected notifications: NotificationsService,
protected translate: TranslateService,
) {
super(dsoDataService, router, route, notifications, translate);
super(dsoDataService, dsoNameService, router, route, notifications, translate);
}
}

View File

@@ -15,6 +15,8 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { ComcolModule } from '../../../shared/comcol/comcol.module';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../shared/mocks/dso-name.service.mock';
describe('CommunityRolesComponent', () => {
@@ -63,6 +65,7 @@ describe('CommunityRolesComponent', () => {
CommunityRolesComponent,
],
providers: [
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: ActivatedRoute, useValue: route },
{ provide: RequestService, useValue: requestService },
{ provide: GroupDataService, useValue: groupDataService },

View File

@@ -27,11 +27,22 @@ export class DSONameService {
* With only two exceptions those solutions seem overkill for now.
*/
private readonly factories = {
EPerson: (dso: DSpaceObject): string => {
const firstName = dso.firstMetadataValue('eperson.firstname');
const lastName = dso.firstMetadataValue('eperson.lastname');
if (isEmpty(firstName) && isEmpty(lastName)) {
return this.translateService.instant('dso.name.unnamed');
} else if (isEmpty(firstName) || isEmpty(lastName)) {
return firstName || lastName;
} else {
return `${firstName} ${lastName}`;
}
},
Person: (dso: DSpaceObject): string => {
const familyName = dso.firstMetadataValue('person.familyName');
const givenName = dso.firstMetadataValue('person.givenName');
if (isEmpty(familyName) && isEmpty(givenName)) {
return dso.firstMetadataValue('dc.title') || dso.name;
return dso.firstMetadataValue('dc.title') || this.translateService.instant('dso.name.unnamed');
} else if (isEmpty(familyName) || isEmpty(givenName)) {
return familyName || givenName;
} else {
@@ -52,7 +63,8 @@ export class DSONameService {
*
* @param dso The {@link DSpaceObject} you want a name for
*/
getName(dso: DSpaceObject): string {
getName(dso: DSpaceObject | undefined): string {
if (dso) {
const types = dso.getRenderTypes();
const match = types
.filter((type) => typeof type === 'string')
@@ -66,6 +78,9 @@ export class DSONameService {
name = this.factories.Default(dso);
}
return name;
} else {
return '';
}
}
/**

View File

@@ -9,6 +9,8 @@ import { HALLink } from '../../shared/hal-link.model';
import { EPERSON } from './eperson.resource-type';
import { Group } from './group.model';
import { GROUP } from './group.resource-type';
import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model';
import { GenericConstructor } from '../../shared/generic-constructor';
@typedObject
@inheritSerialization(DSpaceObject)
@@ -82,4 +84,8 @@ export class EPerson extends DSpaceObject {
@link(GROUP, true)
public groups?: Observable<RemoteData<PaginatedList<Group>>>;
getRenderTypes(): (string | GenericConstructor<ListableObject>)[] {
return [this.constructor.name, ...super.getRenderTypes()];
}
}

View File

@@ -333,8 +333,9 @@ export class SearchService implements OnDestroy {
* Send search event to rest api using angularitics
* @param config Paginated search options used
* @param searchQueryResponse The response objects of the performed search
* @param clickedObject Optional UUID of an object a search was performed and clicked for
*/
trackSearch(config: PaginatedSearchOptions, searchQueryResponse: SearchObjects<DSpaceObject>) {
trackSearch(config: PaginatedSearchOptions, searchQueryResponse: SearchObjects<DSpaceObject>, clickedObject?: string) {
const filters: { filter: string, operator: string, value: string, label: string; }[] = [];
const appliedFilters = searchQueryResponse.appliedFilters || [];
for (let i = 0, filtersLength = appliedFilters.length; i < filtersLength; i++) {
@@ -356,6 +357,7 @@ export class SearchService implements OnDestroy {
order: config.sort.direction
},
filters: filters,
clickedObject,
},
});
}

View File

@@ -10,6 +10,8 @@ import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
const mockItem = Object.assign(new Item(), {
bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])),
@@ -48,6 +50,7 @@ describe('JournalIssueGridElementComponent', () => {
imports: [NoopAnimationsModule],
declarations: [JournalIssueGridElementComponent, TruncatePipe],
providers: [
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: TruncatableService, useValue: truncatableServiceStub },
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -10,6 +10,8 @@ import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
const mockItem = Object.assign(new Item(), {
bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])),
@@ -48,6 +50,7 @@ describe('JournalVolumeGridElementComponent', () => {
imports: [NoopAnimationsModule],
declarations: [JournalVolumeGridElementComponent, TruncatePipe],
providers: [
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: TruncatableService, useValue: truncatableServiceStub },
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -10,6 +10,8 @@ import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
const mockItem = Object.assign(new Item(), {
bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])),
@@ -54,6 +56,7 @@ describe('JournalGridElementComponent', () => {
imports: [NoopAnimationsModule],
declarations: [JournalGridElementComponent, TruncatePipe],
providers: [
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: TruncatableService, useValue: truncatableServiceStub },
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -6,6 +6,8 @@ import { of as observableOf } from 'rxjs';
import { Item } from '../../../../core/shared/item.model';
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
const mockItem: Item = Object.assign(new Item(), {
bundles: observableOf({}),
@@ -43,6 +45,7 @@ describe('JournalIssueListElementComponent', () => {
TestBed.configureTestingModule({
declarations: [JournalIssueListElementComponent, TruncatePipe],
providers: [
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: TruncatableService, useValue: truncatableServiceStub },
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -6,6 +6,8 @@ import { of as observableOf } from 'rxjs';
import { Item } from '../../../../core/shared/item.model';
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
const mockItem: Item = Object.assign(new Item(), {
bundles: observableOf({}),
@@ -43,6 +45,7 @@ describe('JournalVolumeListElementComponent', () => {
TestBed.configureTestingModule({
declarations: [JournalVolumeListElementComponent, TruncatePipe],
providers: [
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: TruncatableService, useValue: truncatableServiceStub },
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -6,6 +6,8 @@ import { of as observableOf } from 'rxjs';
import { Item } from '../../../../core/shared/item.model';
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
const mockItem: Item = Object.assign(new Item(), {
bundles: observableOf({}),
@@ -34,9 +36,10 @@ describe('JournalListElementComponent', () => {
};
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
return TestBed.configureTestingModule({
declarations: [JournalListElementComponent, TruncatePipe],
providers: [
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: TruncatableService, useValue: truncatableServiceStub },
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -10,6 +10,8 @@ import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
const mockItem = Object.assign(new Item(), {
bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])),
@@ -54,6 +56,7 @@ describe('OrgUnitGridElementComponent', () => {
imports: [NoopAnimationsModule],
declarations: [OrgUnitGridElementComponent, TruncatePipe],
providers: [
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: TruncatableService, useValue: truncatableServiceStub },
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -10,6 +10,8 @@ import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
const mockItem = Object.assign(new Item(), {
bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])),
@@ -48,6 +50,7 @@ describe('PersonGridElementComponent', () => {
imports: [NoopAnimationsModule],
declarations: [PersonGridElementComponent, TruncatePipe],
providers: [
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: TruncatableService, useValue: truncatableServiceStub },
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -10,6 +10,8 @@ import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
const mockItem = Object.assign(new Item(), {
bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])),
@@ -42,6 +44,7 @@ describe('ProjectGridElementComponent', () => {
imports: [NoopAnimationsModule],
declarations: [ProjectGridElementComponent, TruncatePipe],
providers: [
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: TruncatableService, useValue: truncatableServiceStub },
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -6,6 +6,8 @@ import { of as observableOf } from 'rxjs';
import { Item } from '../../../../core/shared/item.model';
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
const mockItem: Item = Object.assign(new Item(), {
bundles: observableOf({}),
@@ -37,6 +39,7 @@ describe('OrgUnitListElementComponent', () => {
TestBed.configureTestingModule({
declarations: [OrgUnitListElementComponent, TruncatePipe],
providers: [
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: TruncatableService, useValue: truncatableServiceStub },
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -6,6 +6,8 @@ import { of as observableOf } from 'rxjs';
import { Item } from '../../../../core/shared/item.model';
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
const mockItem: Item = Object.assign(new Item(), {
bundles: observableOf({}),
@@ -37,6 +39,7 @@ describe('PersonListElementComponent', () => {
TestBed.configureTestingModule({
declarations: [PersonListElementComponent, TruncatePipe],
providers: [
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: TruncatableService, useValue: truncatableServiceStub },
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -6,6 +6,8 @@ import { Item } from '../../../../core/shared/item.model';
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { ProjectListElementComponent } from './project-list-element.component';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
const mockItem: Item = Object.assign(new Item(), {
bundles: observableOf({}),
@@ -37,6 +39,7 @@ describe('ProjectListElementComponent', () => {
TestBed.configureTestingModule({
declarations: [ProjectListElementComponent, TruncatePipe],
providers: [
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: TruncatableService, useValue: truncatableServiceStub },
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -23,7 +23,7 @@ export class PersonSearchResultListElementComponent extends ItemSearchResultList
public constructor(
protected truncatableService: TruncatableService,
protected dsoNameService: DSONameService,
public dsoNameService: DSONameService,
@Inject(APP_CONFIG) protected appConfig: AppConfig
) {
super(truncatableService, dsoNameService, appConfig);

View File

@@ -25,7 +25,7 @@ export class PersonSidebarSearchListElementComponent extends SidebarSearchListEl
constructor(protected truncatableService: TruncatableService,
protected linkService: LinkService,
protected translateService: TranslateService,
protected dsoNameService: DSONameService
public dsoNameService: DSONameService,
) {
super(truncatableService, linkService, dsoNameService);
}

View File

@@ -49,7 +49,7 @@ export class OrgUnitSearchResultListSubmissionElementComponent extends SearchRes
private itemDataService: ItemDataService,
private bitstreamDataService: BitstreamDataService,
private selectableListService: SelectableListService,
protected dsoNameService: DSONameService,
public dsoNameService: DSONameService,
@Inject(APP_CONFIG) protected appConfig: AppConfig
) {
super(truncatableService, dsoNameService, appConfig);

View File

@@ -47,7 +47,7 @@ export class PersonSearchResultListSubmissionElementComponent extends SearchResu
private itemDataService: ItemDataService,
private bitstreamDataService: BitstreamDataService,
private selectableListService: SelectableListService,
protected dsoNameService: DSONameService,
public dsoNameService: DSONameService,
@Inject(APP_CONFIG) protected appConfig: AppConfig
) {
super(truncatableService, dsoNameService, appConfig);

View File

@@ -1 +1 @@
<ds-submission-import-external></ds-submission-import-external>
<ds-themed-submission-import-external></ds-themed-submission-import-external>

View File

@@ -1,12 +1,12 @@
<div class="container">
<ng-container *ngIf="bundles">
<div class="row">
<div class="col-12 mb-4">
<div class="col-12 mb-2">
<h2>{{'item.bitstreams.upload.title' | translate}}</h2>
<ng-container *ngVar="(itemRD$ | async)?.payload as item">
<div *ngIf="item">
<span class="font-weight-bold">{{'item.bitstreams.upload.item' | translate}}</span>
<span>{{item.name}}</span>
<span>{{ dsoNameService.getName(item) }}</span>
</div>
</ng-container>
</div>
@@ -24,7 +24,7 @@
(click)="f.open()"
ngDefaultControl>
</ds-dso-input-suggestions>
<button *ngIf="!selectedBundleId && selectedBundleName?.length > 0" class="btn btn-success" (click)="createBundle()">
<button *ngIf="!selectedBundleId && selectedBundleName?.length > 0" class="btn btn-success mr-2" (click)="createBundle()">
<i class="fa fa-plus"></i> {{ 'item.bitstreams.upload.bundle.new' | translate }}
</button>
<ds-uploader class="w-100" *ngIf="selectedBundleId"

View File

@@ -19,6 +19,7 @@ import { RequestService } from '../../../core/data/request.service';
import { getBitstreamModuleRoute } from '../../../app-routing-paths';
import { getEntityEditRoute } from '../../item-page-routing-paths';
import { environment } from '../../../../environments/environment';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
@Component({
selector: 'ds-upload-bitstream',
@@ -94,7 +95,9 @@ export class UploadBitstreamComponent implements OnInit, OnDestroy {
protected authService: AuthService,
protected notificationsService: NotificationsService,
protected translate: TranslateService,
protected requestService: RequestService) {
protected requestService: RequestService,
public dsoNameService: DSONameService,
) {
}
/**

View File

@@ -39,6 +39,8 @@ import { IdentifierDataComponent } from '../../shared/object-list/identifier-dat
import { ItemRegisterDoiComponent } from './item-register-doi/item-register-doi.component';
import { DsoSharedModule } from '../../dso-shared/dso-shared.module';
import { ItemCurateComponent } from './item-curate/item-curate.component';
import { ThemedItemStatusComponent } from './item-status/themed-item-status.component';
/**
* Module that contains all components related to the Edit Item page administrator functionality
@@ -67,6 +69,7 @@ import { ItemCurateComponent } from './item-curate/item-curate.component';
ItemPublicComponent,
ItemDeleteComponent,
ItemStatusComponent,
ThemedItemStatusComponent,
ItemRelationshipsComponent,
ItemBitstreamsComponent,
ItemVersionHistoryComponent,
@@ -89,6 +92,9 @@ import { ItemCurateComponent } from './item-curate/item-curate.component';
IdentifierDataService,
ObjectValuesPipe
],
exports: [
ItemOperationComponent,
]
})
export class EditItemPageModule {

View File

@@ -6,7 +6,6 @@ import { ItemReinstateComponent } from './item-reinstate/item-reinstate.componen
import { ItemPrivateComponent } from './item-private/item-private.component';
import { ItemPublicComponent } from './item-public/item-public.component';
import { ItemDeleteComponent } from './item-delete/item-delete.component';
import { ItemStatusComponent } from './item-status/item-status.component';
import { ItemBitstreamsComponent } from './item-bitstreams/item-bitstreams.component';
import { ItemCollectionMapperComponent } from './item-collection-mapper/item-collection-mapper.component';
import { ItemMoveComponent } from './item-move/item-move.component';
@@ -42,6 +41,7 @@ import { ItemPageCollectionMapperGuard } from './item-page-collection-mapper.gua
import { ThemedDsoEditMetadataComponent } from '../../dso-shared/dso-edit-metadata/themed-dso-edit-metadata.component';
import { ItemPageRegisterDoiGuard } from './item-page-register-doi.guard';
import { ItemCurateComponent } from './item-curate/item-curate.component';
import { ThemedItemStatusComponent } from './item-status/themed-item-status.component';
/**
* Routing module that handles the routing for the Edit Item page administrator functionality
@@ -67,7 +67,7 @@ import { ItemCurateComponent } from './item-curate/item-curate.component';
},
{
path: 'status',
component: ItemStatusComponent,
component: ThemedItemStatusComponent,
data: { title: 'item.edit.tabs.status.title', showBreadcrumbs: true },
canActivate: [ItemPageStatusGuard]
},

View File

@@ -11,7 +11,7 @@
<div class="card-header">
<button type="button" class="btn btn-outline-primary" (click)="collapseArea(bundle.id)"
[attr.aria-expanded]="false" [attr.aria-controls]="bundle.id">
{{ 'collection.edit.item.authorizations.show-bitstreams-button' | translate }} {{bundle.name}}
{{ 'collection.edit.item.authorizations.show-bitstreams-button' | translate }} {{ nameService.getName(bundle) }}
</button>
</div>
<div class="card-body" [id]="bundle.id" [ngbCollapse]="bundleBitstreamsMap.get(bundle.id).isCollapsed">

View File

@@ -101,7 +101,7 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy {
constructor(
private linkService: LinkService,
private route: ActivatedRoute,
private nameService: DSONameService
public nameService: DSONameService
) {
}

View File

@@ -3,7 +3,7 @@
<div class="{{bundleNameColumn.buildClasses()}} font-weight-bold row-element d-flex">
<ds-item-edit-bitstream-drag-handle></ds-item-edit-bitstream-drag-handle>
<div class="float-left d-flex align-items-center">
{{'item.edit.bitstreams.bundle.name' | translate:{ name: bundle.name } }}
{{'item.edit.bitstreams.bundle.name' | translate:{ name: dsoNameService.getName(bundle) } }}
</div>
</div>
<div class="{{columnSizes.columns[3].buildClasses()}} text-center row-element">

View File

@@ -4,6 +4,7 @@ import { Item } from '../../../../core/shared/item.model';
import { ResponsiveColumnSizes } from '../../../../shared/responsive-table-sizes/responsive-column-sizes';
import { ResponsiveTableSizes } from '../../../../shared/responsive-table-sizes/responsive-table-sizes';
import { getItemPageRoute } from '../../../item-page-routing-paths';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
@Component({
selector: 'ds-item-edit-bitstream-bundle',
@@ -55,7 +56,10 @@ export class ItemEditBitstreamBundleComponent implements OnInit {
*/
itemPageRoute: string;
constructor(private viewContainerRef: ViewContainerRef) {
constructor(
protected viewContainerRef: ViewContainerRef,
public dsoNameService: DSONameService,
) {
}
ngOnInit(): void {

View File

@@ -1,4 +1,4 @@
<div class="container">
<div class="container mt-2">
<div class="row">
<div class="col-12">
<h2>{{'item.edit.item-mapper.head' | translate}}</h2>

View File

@@ -20,9 +20,10 @@
<div class="row">
<div class="col-12">
<p>
<label for="inheritPoliciesCheckbox">
<input type="checkbox" name="tc" [(ngModel)]="inheritPolicies" id="inheritPoliciesCheckbox">
<label for="inheritPoliciesCheckbox">{{'item.edit.move.inheritpolicies.checkbox' |
translate}}</label>
{{'item.edit.move.inheritpolicies.checkbox' |translate}}
</label>
</p>
<p>
{{'item.edit.move.inheritpolicies.description' | translate}}

View File

@@ -16,6 +16,7 @@ import { SearchService } from '../../../core/shared/search/search.service';
import { getItemEditRoute, getItemPageRoute } from '../../item-page-routing-paths';
import { followLink } from '../../../shared/utils/follow-link-config.model';
import { RequestService } from '../../../core/data/request.service';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
@Component({
selector: 'ds-item-move',
@@ -57,6 +58,7 @@ export class ItemMoveComponent implements OnInit {
private searchService: SearchService,
private translateService: TranslateService,
private requestService: RequestService,
protected dsoNameService: DSONameService,
) {}
ngOnInit(): void {
@@ -88,7 +90,7 @@ export class ItemMoveComponent implements OnInit {
*/
selectDso(data: any): void {
this.selectedCollection = data;
this.selectedCollectionName = data.name;
this.selectedCollectionName = this.dsoNameService.getName(data);
this.canSubmit = true;
}

View File

@@ -9,9 +9,9 @@ import { RemoteData } from '../../../core/data/remote-data';
import { getItemEditRoute, getItemPageRoute } from '../../item-page-routing-paths';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
import { hasValue } from '../../../shared/empty.util';
import { hasValue, isNotEmpty } from '../../../shared/empty.util';
import {
getAllSucceededRemoteDataPayload, getFirstSucceededRemoteData, getRemoteDataPayload,
getAllSucceededRemoteDataPayload, getFirstCompletedRemoteData, getFirstSucceededRemoteData, getRemoteDataPayload,
} from '../../../core/shared/operators';
import { IdentifierDataService } from '../../../core/data/identifier-data.service';
import { Identifier } from '../../../shared/object-list/identifier-data/identifier.model';
@@ -105,12 +105,13 @@ export class ItemStatusComponent implements OnInit {
// Observable for configuration determining whether the Register DOI feature is enabled
let registerConfigEnabled$: Observable<boolean> = this.configurationService.findByPropertyName('identifiers.item-status.register-doi').pipe(
getFirstSucceededRemoteData(),
getRemoteDataPayload(),
map((enabled: ConfigurationProperty) => {
if (enabled !== undefined && enabled.values) {
return true;
getFirstCompletedRemoteData(),
map((rd: RemoteData<ConfigurationProperty>) => {
// If the config property is exposed via rest and has a value set, return it
if (rd.hasSucceeded && hasValue(rd.payload) && isNotEmpty(rd.payload.values)) {
return rd.payload.values[0] === 'true';
}
// Otherwise, return false
return false;
})
);

View File

@@ -0,0 +1,23 @@
import { Component } from '@angular/core';
import { ThemedComponent } from '../../../shared/theme-support/themed.component';
import { ItemStatusComponent } from './item-status.component';
@Component({
selector: 'ds-themed-item-status',
styleUrls: [],
templateUrl: '../../../shared/theme-support/themed.component.html',
})
export class ThemedItemStatusComponent extends ThemedComponent<ItemStatusComponent> {
protected getComponentName(): string {
return 'ItemStatusComponent';
}
protected importThemedComponent(themeName: string): Promise<any> {
return import(`../../../../themes/${themeName}/app/item-page/edit-item-page/item-status/item-status.component`);
}
protected importUnthemedComponent(): Promise<any> {
return import('./item-status.component');
}
}

View File

@@ -1,7 +1,7 @@
<ds-metadata-field-wrapper [label]="label | translate">
<div class="collections">
<a *ngFor="let collection of (this.collections$ | async); let last=last;" [routerLink]="['/collections', collection.id]">
<span>{{collection?.name}}</span><span *ngIf="!last" [innerHTML]="separator"></span>
<span>{{ dsoNameService.getName(collection) }}</span><span *ngIf="!last" [innerHTML]="separator"></span>
</a>
</div>

View File

@@ -12,6 +12,8 @@ import { CollectionsComponent } from './collections.component';
import { buildPaginatedList, PaginatedList } from '../../../core/data/paginated-list.model';
import { PageInfo } from '../../../core/shared/page-info.model';
import { FindListOptions } from '../../../core/data/find-list-options.model';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../shared/mocks/dso-name.service.mock';
const createMockCollection = (id: string) => Object.assign(new Collection(), {
id: id,
@@ -46,6 +48,7 @@ describe('CollectionsComponent', () => {
imports: [TranslateModule.forRoot()],
declarations: [ CollectionsComponent ],
providers: [
{ provide: DSONameService, useValue: new DSONameServiceMock() },
{ provide: RemoteDataBuildService, useValue: getMockRemoteDataBuildService()},
{ provide: CollectionDataService, useValue: collectionDataService },
],

View File

@@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, Input, OnInit, ChangeDetectorRef } from '@angular/core';
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
import {map, scan, startWith, switchMap, tap, withLatestFrom} from 'rxjs/operators';
import { CollectionDataService } from '../../../core/data/collection-data.service';
@@ -14,6 +14,7 @@ import {
getPaginatedListPayload,
} from '../../../core/shared/operators';
import { FindListOptions } from '../../../core/data/find-list-options.model';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
/**
* This component renders the parent collections section of the item
@@ -65,8 +66,11 @@ export class CollectionsComponent implements OnInit {
*/
collections$: Observable<Collection[]>;
constructor(private cds: CollectionDataService) {
constructor(
private cds: CollectionDataService,
public dsoNameService: DSONameService,
protected cdr: ChangeDetectorRef,
) {
}
ngOnInit(): void {
@@ -114,6 +118,7 @@ export class CollectionsComponent implements OnInit {
return [owningCollection, ...mappedCollections].filter(collection => hasValue(collection));
}),
);
this.cdr.detectChanges();
}
handleLoadMore() {

View File

@@ -18,7 +18,7 @@
<div class="col-7">
<dl class="row">
<dt class="col-md-4">{{"item.page.filesection.name" | translate}}</dt>
<dd class="col-md-8">{{file.name}}</dd>
<dd class="col-md-8">{{ dsoNameService.getName(file) }}</dd>
<dt class="col-md-4">{{"item.page.filesection.size" | translate}}</dt>
<dd class="col-md-8">{{(file.sizeBytes) | dsFileSize }}</dd>
@@ -27,9 +27,10 @@
<dt class="col-md-4">{{"item.page.filesection.format" | translate}}</dt>
<dd class="col-md-8">{{(file.format | async)?.payload?.description}}</dd>
<ng-container *ngIf="file.hasMetadata('dc.description')">
<dt class="col-md-4">{{"item.page.filesection.description" | translate}}</dt>
<dd class="col-md-8">{{file.firstMetadataValue("dc.description")}}</dd>
</ng-container>
</dl>
</div>
<div class="col-2">
@@ -60,7 +61,7 @@
<div class="col-7">
<dl class="row">
<dt class="col-md-4">{{"item.page.filesection.name" | translate}}</dt>
<dd class="col-md-8">{{file.name}}</dd>
<dd class="col-md-8">{{ dsoNameService.getName(file) }}</dd>
<dt class="col-md-4">{{"item.page.filesection.size" | translate}}</dt>
<dd class="col-md-8">{{(file.sizeBytes) | dsFileSize }}</dd>

Some files were not shown because too many files have changed in this diff Show More