Skip to content

Commit 2cbafe3

Browse files
committed
Merged dspace-cris-2024_02_x into task/dspace-cris-2024_02_x/DSC-2724
2 parents 7b4c5eb + 8ebaef6 commit 2cbafe3

File tree

13 files changed

+281
-154
lines changed

13 files changed

+281
-154
lines changed

bitbucket-pipelines.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ definitions:
6262
- step: &angular-build
6363
name: angular-build
6464
image:
65-
name: cypress/browsers:node-18.20.3-chrome-125.0.6422.141-1-ff-126.0.1-edge-125.0.2535.85-1
65+
name: cypress/browsers:node-20.18.0-chrome-130.0.6723.69-1-ff-131.0.3-edge-130.0.2849.52-1
6666
run-as-user: 1000
6767
size: 4x
6868
caches:
@@ -78,7 +78,7 @@ definitions:
7878
- step: &unittest-code-checks
7979
name: test-code-checks
8080
image:
81-
name: cypress/browsers:node-18.20.3-chrome-125.0.6422.141-1-ff-126.0.1-edge-125.0.2535.85-1
81+
name: cypress/browsers:node-20.18.0-chrome-130.0.6723.69-1-ff-131.0.3-edge-130.0.2849.52-1
8282
run-as-user: 1000
8383
size: 4x
8484
caches:
@@ -96,7 +96,7 @@ definitions:
9696
- step: &run-e2e-tests
9797
name: Run E2E test
9898
image:
99-
name: cypress/browsers:node-18.20.3-chrome-125.0.6422.141-1-ff-126.0.1-edge-125.0.2535.85-1
99+
name: cypress/browsers:node-20.18.0-chrome-130.0.6723.69-1-ff-131.0.3-edge-130.0.2849.52-1
100100
run-as-user: 0
101101
size: 4x
102102
services:
@@ -105,6 +105,7 @@ definitions:
105105
- node-2024-02-x
106106
- cypress-2024-02-x
107107
script:
108+
- wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | tee /etc/apt/trusted.gpg.d/google.asc >/dev/null
108109
- apt-get update && apt-get install -y curl
109110
- export HASH_COMMIT=${BITBUCKET_COMMIT:0:8}
110111
- echo "Running tests for commit $HASH_COMMIT"
@@ -145,7 +146,7 @@ definitions:
145146
- npx cypress install
146147
- yarn serve:ssr &
147148
- echo "Waiting for server to start..."
148-
- sleep 10
149+
- sleep 60
149150
- echo "Running Cypress tests..."
150151
- yarn cypress:run --env chromeFlags="$CHROME_FLAGS"
151152
- echo "Test execution completed"

cypress/e2e/my-dspace.cy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ describe('My DSpace page', () => {
119119
// Open the New Import dropdown
120120
cy.get('button[data-test="import-dropdown"]').click();
121121
// Click on the "Item" type in that dropdown
122-
cy.get('#importControlsDropdownMenu button[title="Equipment"]').click();
122+
cy.get('#importControlsDropdownMenu button[title="Funding"]').click();
123123

124124
// New URL should include /import-external, as we've moved to the import page
125125
cy.url().should('include', '/import-external');

cypress/support/e2e.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ import 'cypress-axe';
2121

2222
import { DSPACE_XSRF_COOKIE } from 'src/app/core/xsrf/xsrf.constants';
2323

24+
// We might receive uncaught exceptions from external libraries (e.g. it happened before with a broken
25+
// version of the addToAny plugin). These should not cause our tests to fail, so we catch them here.
26+
Cypress.on('uncaught:exception', (err, runnable) => {
27+
// returning false here prevents Cypress from failing the test
28+
return false;
29+
});
30+
2431
// Runs once before all tests
2532
before(() => {
2633
// Cypress doesn't have access to the running application in Node.js.
Lines changed: 56 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,69 @@
11
<div class="container">
2-
<div class="d-flex">
3-
<h2 class="flex-grow-1">{{'audit.object.overview.title' | translate}}</h2>
4-
</div>
2+
<div class="d-flex">
3+
<h2 class="flex-grow-1">{{ 'audit.object.overview.title' | translate }}</h2>
4+
</div>
55

6-
<ng-container *ngIf="object">
7-
<h4 class="mt-4 mb-4">{{ object.name }} (<em>{{object.type}}</em>)</h4>
6+
<ng-container *ngIf="object">
7+
<h4 class="mt-4 mb-4">{{ object.name }} (<em>{{ object.type }}</em>)</h4>
88

9-
<ng-container *ngIf="(auditsRD$ | async)?.payload as audits">
9+
<ng-container *ngIf="(auditsRD$ | async)?.payload as audits">
1010

11-
<div *ngIf="audits.totalElements === 0">
12-
No audits found.
13-
</div>
14-
15-
<ds-pagination *ngIf="audits.totalElements > 0"
16-
[paginationOptions]="pageConfig"
17-
[collectionSize]="audits.totalElements"
18-
[hideGear]="true"
19-
[hidePagerWhenSinglePage]="true">
11+
<div *ngIf="audits.totalElements === 0">
12+
No audits found.
13+
</div>
2014

21-
<div class="table-responsive">
22-
<table class="table table-striped table-hover">
23-
<thead>
24-
<tr>
25-
<!-- <th>{{ 'audit.overview.table.id' | translate }}</th> -->
26-
<th>{{ 'audit.overview.table.entityType' | translate }}</th>
27-
<th>{{ 'audit.overview.table.eperson' | translate }}</th>
28-
<th>{{ 'audit.overview.table.timestamp' | translate }}</th>
29-
<th>Other Object</th>
30-
</tr>
31-
</thead>
32-
<tbody>
33-
<tr *ngFor="let audit of audits.page">
34-
<!-- <td><a [routerLink]="['/auditlogs/', audit.id]">{{audit.id}}</a></td> -->
35-
<td>{{ audit.eventType }}</td>
36-
<td *ngVar="(getEpersonName(audit) | async) as ePersonName">{{ePersonName}}</td>
37-
<td>{{ audit.timeStamp | date:dateFormat}}</td>
38-
<td>
39-
<span *ngIf="object.id === audit.objectUUID">
40-
<!-- object.id === audit.objectUUID -->
41-
<ng-container *ngIf="(getOtherObject(audit, object.id) | async) as subject">
42-
<ng-container *ngIf="subject">
43-
{{ subject.name }} <em>({{ subject.type }})</em>
44-
</ng-container>
45-
</ng-container>
46-
</span>
15+
<ds-pagination *ngIf="audits.totalElements > 0"
16+
[paginationOptions]="pageConfig"
17+
[collectionSize]="audits.totalElements"
18+
[hideGear]="true"
19+
[hidePagerWhenSinglePage]="true">
4720

48-
<span *ngIf="object.id === audit.subjectUUID">
49-
<!-- object.id === audit.subjectUUID -->
50-
</span>
51-
</td>
52-
</tr>
53-
</tbody>
54-
</table>
55-
</div>
56-
</ds-pagination>
21+
<div class="table-responsive">
22+
<table class="table table-striped table-hover">
23+
<thead>
24+
<tr>
25+
<!-- <th>{{ 'audit.overview.table.id' | translate }}</th> -->
26+
<th>{{ 'audit.overview.table.entityType' | translate }}</th>
27+
<th>{{ 'audit.overview.table.eperson' | translate }}</th>
28+
<th>{{ 'audit.overview.table.timestamp' | translate }}</th>
29+
<th>Other Object</th>
30+
</tr>
31+
</thead>
32+
<tbody>
33+
<tr *ngFor="let audit of audits?.page; trackBy: trackById">
34+
<!-- <td><a [routerLink]="['/auditlogs/', audit.id]">{{audit.id}}</a></td> -->
35+
<td>{{ audit.eventType }}</td>
36+
<td>
37+
<span *ngIf="(audit.epersonName | async) as epersonName; else noEperson">{{epersonName}}</span>
38+
<ng-template #noEperson><em>{{ 'audit.overview.table.eperson.anonymous' | translate }}</em></ng-template>
39+
</td>
40+
<td>{{ audit.timeStamp | date:dateFormat }}</td>
41+
<td>
42+
<span *ngIf="object.id === audit.objectUUID">
43+
<!-- object.id === audit.objectUUID -->
44+
<ng-container *ngIf="(audit.subject | async) as subject">
45+
{{ subject.name }} <em>({{ subject.type }})</em>
46+
</ng-container>
47+
</span>
48+
<span *ngIf="object.id === audit.subjectUUID">
49+
<!-- object.id === audit.subjectUUID -->
50+
</span>
51+
</td>
52+
</tr>
53+
</tbody>
54+
</table>
55+
</div>
56+
</ds-pagination>
5757

58-
<a class="btn btn-light mt-3" [routerLink]="['/items', object.id]"><i class="fas fa-arrow-left"></i> Back to Item</a>
58+
<a class="btn btn-light mt-3" [routerLink]="['/items', object.id]"><i class="fas fa-arrow-left"></i> Back to Item</a>
5959

60-
<!-- <a class="btn btn-light mt-3" [routerLink]="'/auditlogs'">{{'audit.detail.back' | translate}}</a> -->
60+
<!-- <a class="btn btn-light mt-3" [routerLink]="'/auditlogs'">{{'audit.detail.back' | translate}}</a> -->
6161

62-
</ng-container>
62+
</ng-container>
6363

64-
<h4 class="mt-4 mb-4" *ngIf="(auditsRD$ | async)?.statusCode === 404">{{'audit.object.overview.disabled.message' | translate}}</h4>
64+
<h4 class="mt-4 mb-4"
65+
*ngIf="(auditsRD$ | async)?.statusCode === 404">{{ 'audit.object.overview.disabled.message' | translate }}</h4>
6566

66-
</ng-container>
67+
</ng-container>
6768

6869
</div>

src/app/audit-page/object-audit-overview/object-audit-overview.component.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@ import {
2828
} from 'rxjs/operators';
2929

3030
import { COLLECTION_PAGE_LINKS_TO_FOLLOW } from '../../collection-page/collection-page.resolver';
31-
import { AuditDataService } from '../../core/audit/audit-data.service';
32-
import { Audit } from '../../core/audit/model/audit.model';
31+
import {
32+
AuditDataService,
33+
AuditDetails,
34+
} from '../../core/audit/audit-data.service';
3335
import { AuthService } from '../../core/auth/auth.service';
3436
import { SortDirection } from '../../core/cache/models/sort-options.model';
3537
import { CollectionDataService } from '../../core/data/collection-data.service';
@@ -46,7 +48,6 @@ import { Item } from '../../core/shared/item.model';
4648
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
4749
import { PaginationComponent } from '../../shared/pagination/pagination.component';
4850
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
49-
import { VarDirective } from '../../shared/utils/var.directive';
5051

5152
/**
5253
* Component displaying a list of all audit about a object in a paginated table
@@ -60,7 +61,6 @@ import { VarDirective } from '../../shared/utils/var.directive';
6061
AsyncPipe,
6162
TranslateModule,
6263
NgForOf,
63-
VarDirective,
6464
RouterLink,
6565
DatePipe,
6666
],
@@ -76,7 +76,7 @@ export class ObjectAuditOverviewComponent implements OnInit {
7676
/**
7777
* List of all audits
7878
*/
79-
auditsRD$: Observable<RemoteData<PaginatedList<Audit>>>;
79+
auditsRD$: Observable<RemoteData<PaginatedList<AuditDetails>>>;
8080

8181
/**
8282
* The current pagination configuration for the page used by the FindAll method
@@ -112,7 +112,8 @@ export class ObjectAuditOverviewComponent implements OnInit {
112112
protected authorizationService: AuthorizationDataService,
113113
protected paginationService: PaginationService,
114114
protected collectionDataService: CollectionDataService,
115-
) {}
115+
) {
116+
}
116117

117118
ngOnInit(): void {
118119
this.route.paramMap.pipe(
@@ -148,16 +149,21 @@ export class ObjectAuditOverviewComponent implements OnInit {
148149

149150

150151
this.auditsRD$ = combineLatest([isAdmin$, config$, this.owningCollection$, parentCommunity$]).pipe(
151-
mergeMap(([isAdmin, config, owningCollection, parentCommunity]) => {
152+
mergeMap(([isAdmin, config, owningCollection, parentCommunity]) => {
152153
if (isAdmin) {
153-
return this.auditService.findByObject(this.object.id, config, owningCollection.id, parentCommunity.id);
154+
return this.auditService.findByObject(this.object.id, config, owningCollection.id, parentCommunity.id)
155+
.pipe(
156+
getFirstCompletedRemoteData(),
157+
map(data => this.auditService.mapToAuditDetails(data)),
158+
);
154159
}
155160

156161
return of(null);
157162
}),
158163
);
159164
}
160165

166+
161167
isCurrentUserAdmin(): Observable<boolean> {
162168
return combineLatest([
163169
this.authorizationService.isAuthorized(FeatureID.IsCollectionAdmin),
@@ -172,15 +178,11 @@ export class ObjectAuditOverviewComponent implements OnInit {
172178
}
173179

174180
/**
175-
* Get the name of an EPerson by ID
176-
* @param audit Audit object
181+
* Method to prevent unnecessary for loop re-rendering
177182
*/
178-
getEpersonName(audit: Audit): Observable<string> {
179-
return this.auditService.getEpersonName(audit);
183+
trackById(index: number, audit: AuditDetails): string {
184+
return audit.id;
180185
}
181186

182-
getOtherObject(audit: Audit, contextObjectId: string): Observable<any> {
183-
return this.auditService.getOtherObject(audit, contextObjectId);
184-
}
185187

186188
}

src/app/audit-page/overview/audit-overview.component.html

Lines changed: 40 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,45 +3,50 @@
33
<h2 class="flex-grow-1">{{'audit.overview.title' | translate}}</h2>
44
</div>
55

6-
<ng-container *ngIf="isAdmin$ | async">
7-
<div *ngIf="(auditsRD$ | async)?.payload?.totalElements === 0">
6+
<ng-container *ngIf="isAdmin$ | async as isAdmin">
7+
<ng-container *ngIf="(auditsRD$ | async)?.payload as audits">
8+
<div *ngIf="audits?.totalElements === 0">
89
No audits found.
9-
</div>
10+
</div>
1011

11-
<ds-pagination *ngIf="(auditsRD$ | async)?.payload?.totalElements > 0"
12-
[paginationOptions]="pageConfig"
13-
[collectionSize]="(auditsRD$ | async)?.payload?.totalElements"
14-
[hideGear]="true"
15-
[hidePagerWhenSinglePage]="true">
12+
<ds-pagination *ngIf="audits?.totalElements > 0"
13+
[paginationOptions]="pageConfig"
14+
[collectionSize]="audits?.totalElements"
15+
[hideGear]="true"
16+
[hidePagerWhenSinglePage]="true">
1617
<div class="table-responsive">
17-
<table class="table table-striped table-hover">
18-
<thead>
19-
<tr>
20-
<th>{{ 'audit.overview.table.id' | translate }}</th>
21-
<th>{{ 'audit.overview.table.entityType' | translate }}</th>
22-
<th>{{ 'audit.overview.table.objectUUID' | translate }}</th>
23-
<th>{{ 'audit.overview.table.objectType' | translate }}</th>
24-
<th>{{ 'audit.overview.table.subjectUUID' | translate }}</th>
25-
<th>{{ 'audit.overview.table.subjectType' | translate }}</th>
26-
<th>{{ 'audit.overview.table.eperson' | translate }}</th>
27-
<th>{{ 'audit.overview.table.timestamp' | translate }}</th>
28-
</tr>
29-
</thead>
30-
<tbody>
31-
<tr *ngFor="let audit of (auditsRD$ | async)?.payload?.page">
32-
<td><a [routerLink]="['/auditlogs/', audit.id]">{{audit.id}}</a></td>
33-
<td>{{ audit.eventType }}</td>
34-
<td><a *ngIf="audit.objectUUID" [routerLink]="['/auditlogs/object/', audit.objectUUID]">{{audit.objectUUID}}</a></td>
35-
<td>{{ audit.objectType }}</td>
36-
<td>{{ audit.subjectUUID }}</td>
37-
<td>{{ audit.subjectType }}</td>
38-
<td *ngVar="(getEpersonName(audit) | async) as ePersonName">{{ePersonName}}</td>
39-
<td>{{ audit.timeStamp | date:dateFormat}}</td>
40-
</tr>
41-
</tbody>
42-
</table>
18+
<table class="table table-striped table-hover">
19+
<thead>
20+
<tr>
21+
<th>{{ 'audit.overview.table.id' | translate }}</th>
22+
<th>{{ 'audit.overview.table.entityType' | translate }}</th>
23+
<th>{{ 'audit.overview.table.objectUUID' | translate }}</th>
24+
<th>{{ 'audit.overview.table.objectType' | translate }}</th>
25+
<th>{{ 'audit.overview.table.subjectUUID' | translate }}</th>
26+
<th>{{ 'audit.overview.table.subjectType' | translate }}</th>
27+
<th>{{ 'audit.overview.table.eperson' | translate }}</th>
28+
<th>{{ 'audit.overview.table.timestamp' | translate }}</th>
29+
</tr>
30+
</thead>
31+
<tbody>
32+
<tr *ngFor="let audit of audits?.page; trackBy: trackById">
33+
<td><a [routerLink]="['/auditlogs/', audit.id]">{{audit.id}}</a></td>
34+
<td>{{ audit.eventType }}</td>
35+
<td><a *ngIf="audit.objectUUID" [routerLink]="['/auditlogs/object/', audit.objectUUID]">{{audit.objectUUID}}</a></td>
36+
<td>{{ audit.objectType }}</td>
37+
<td>{{ audit.subjectUUID }}</td>
38+
<td>{{ audit.subjectType }}</td>
39+
<td>
40+
<span *ngIf="(audit.epersonName | async) as epersonName; else noEperson">{{epersonName}}</span>
41+
<ng-template #noEperson><em>{{ 'audit.overview.table.eperson.anonymous' | translate }}</em></ng-template>
42+
</td>
43+
<td>{{ audit.timeStamp | date:dateFormat}}</td>
44+
</tr>
45+
</tbody>
46+
</table>
4347
</div>
44-
</ds-pagination>
48+
</ds-pagination>
49+
</ng-container>
4550
</ng-container>
4651

4752
</div>

0 commit comments

Comments
 (0)