Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Content reports ported from DSpace 6.x #2163

Merged
merged 46 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
f37122b
Content Reports
Nov 30, 2022
1d1c713
Fixed merge conflict
Dec 15, 2022
be97cad
Resolved conflict on pl.json5
Jan 9, 2023
bc73039
Merge branch 'main' of github.com:jeffmorin/dspace-angular
Jan 12, 2023
9533713
Synchronized API update with REST layer + i18n update in Greek and Uk…
Jan 12, 2023
9677de7
Fixed code style errors
Jan 12, 2023
97c6bf5
Merge branch 'DSpace:main' into main
jeffmorin Jan 12, 2023
18f913e
Merge branch 'DSpace:main' into main
jeffmorin Jan 16, 2023
2b8c377
Merge branch 'DSpace:main' into main
jeffmorin Jan 18, 2023
a105dd5
Fixed conflicts
Mar 24, 2023
2c0e0ab
Fixed conflicts and added strings for Content Reports
Mar 24, 2023
5a01670
Merge branch 'DSpace:main' into main
jeffmorin Apr 5, 2023
75ca560
Merge branch 'DSpace:main' into main
jeffmorin Apr 12, 2023
1cdbfc5
Resolved conflicts
Apr 20, 2023
0e2b767
Merge branch 'DSpace:main' into main
jeffmorin May 1, 2023
de83b35
Merge branch 'DSpace:main' into main
jeffmorin May 25, 2023
6d9768e
Updated to latest version from main branch
Nov 21, 2023
ef651a3
Resolved conflicts
Dec 18, 2023
16708d6
Merge branch 'DSpace:main' into main
jeffmorin Feb 12, 2024
d686cb1
Merge branch 'DSpace:main' into main
jeffmorin Feb 15, 2024
5f88a07
Removed non-working tests
Feb 15, 2024
4cd20d6
Removed unneeded actions file and fixed invalid TS file
Feb 15, 2024
85630ba
Fixed i18n files
Feb 15, 2024
872a670
Merge branch 'DSpace:main' into main
jeffmorin Feb 16, 2024
cadd1df
Applied Bootstrap styles to tables and form controls
Feb 19, 2024
998dd94
Merge branch 'main' of github.com:jeffmorin/dspace-angular
Feb 19, 2024
2d2a74a
Merge branch 'DSpace:main' into main
jeffmorin Feb 20, 2024
8bcd82e
Forgot styling on two buttons
Feb 21, 2024
27a9ce5
Merge branch 'main' of github.com:jeffmorin/dspace-angular
Feb 21, 2024
2a65bd8
Merge branch 'DSpace:main' into main
jeffmorin Feb 21, 2024
79993ce
Merge branch 'DSpace:main' into main
jeffmorin Feb 22, 2024
513b28b
Merge branch 'DSpace:main' into main
jeffmorin Feb 22, 2024
64e3149
Added enable/disable Conte Reports functionality
Feb 22, 2024
f1cfe99
Fixed single-quote constraint
Feb 22, 2024
5f41bc2
The newly added ConfigurationDataService seemed to be missing in the …
Feb 22, 2024
1c6216d
Revert to original version
Feb 22, 2024
c764950
Second attempt to fix menu.resolver.spec.ts
Feb 22, 2024
0497991
Merge branch 'DSpace:main' into main
jeffmorin Feb 23, 2024
e2bf9d2
Switched to GET requests for Content Reports
Feb 23, 2024
1cea469
Fixed styling errors
Feb 23, 2024
600c991
Fixed for loops over arrays
Feb 23, 2024
91d97f8
Fixed unit test
Feb 23, 2024
ba5f50e
Merge branch 'DSpace:main' into main
jeffmorin Feb 27, 2024
92553e0
Requested changes and fixes
Feb 27, 2024
26caab1
Merge branch 'main' of github.com:jeffmorin/dspace-angular
Feb 27, 2024
410a278
Resolved conflicts
Feb 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions src/app/admin/admin-reports/admin-reports-routing.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { FilteredCollectionsComponent } from './filtered-collections/filtered-collections.component';
import { FilteredItemsComponent } from './filtered-items/filtered-items.component';
import { RouterModule } from '@angular/router';
import { NgModule } from '@angular/core';
import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver';

@NgModule({
imports: [
RouterModule.forChild([
{
path: 'collections',
resolve: { breadcrumb: I18nBreadcrumbResolver },
data: {title: 'admin.reports.collections.title', breadcrumbKey: 'admin.reports.collections'},
children: [
{
path: '',
component: FilteredCollectionsComponent
}
]
},
{
path: 'queries',
resolve: { breadcrumb: I18nBreadcrumbResolver },
data: {title: 'admin.reports.items.title', breadcrumbKey: 'admin.reports.items'},
children: [
{
path: '',
component: FilteredItemsComponent
}
]
}
])
]
})
export class AdminReportsRoutingModule {

}
28 changes: 28 additions & 0 deletions src/app/admin/admin-reports/admin-reports.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FilteredCollectionsComponent } from './filtered-collections/filtered-collections.component';
import { RouterModule } from '@angular/router';
import { SharedModule } from '../../shared/shared.module';
import { FormModule } from '../../shared/form/form.module';
import { FilteredItemsComponent } from './filtered-items/filtered-items.component';
import { AdminReportsRoutingModule } from './admin-reports-routing.module';
import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap';
import { FiltersComponent } from './filters-section/filters-section.component';

@NgModule({
imports: [
CommonModule,
SharedModule,
RouterModule,
FormModule,
AdminReportsRoutingModule,
NgbAccordionModule
],
declarations: [
FilteredCollectionsComponent,
FilteredItemsComponent,
FiltersComponent
]
})
export class AdminReportsModule {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
export class FilteredCollection {

public label: string;
public handle: string;
public communityLabel: string;
public communityHandle: string;
public nbTotalItems: number;
public values = {};
public allFiltersValue: number;

public clear() {
this.label = '';
this.handle = '';
this.communityLabel = '';
this.communityHandle = '';
this.nbTotalItems = 0;
this.values = {};
this.allFiltersValue = 0;

Check warning on line 18 in src/app/admin/admin-reports/filtered-collections/filtered-collection.model.ts

View check run for this annotation

Codecov / codecov/patch

src/app/admin/admin-reports/filtered-collections/filtered-collection.model.ts#L12-L18

Added lines #L12 - L18 were not covered by tests
}

public deserialize(object: any) {
this.clear();
this.label = object.label;
this.handle = object.handle;
this.communityLabel = object.community_label;
this.communityHandle = object.community_handle;
this.nbTotalItems = object.nb_total_items;
let valuesPerFilter = object.values;
for (let filter in valuesPerFilter) {

Check warning on line 29 in src/app/admin/admin-reports/filtered-collections/filtered-collection.model.ts

View check run for this annotation

Codecov / codecov/patch

src/app/admin/admin-reports/filtered-collections/filtered-collection.model.ts#L22-L29

Added lines #L22 - L29 were not covered by tests
if (valuesPerFilter.hasOwnProperty(filter)) {
this.values[filter] = valuesPerFilter[filter];

Check warning on line 31 in src/app/admin/admin-reports/filtered-collections/filtered-collection.model.ts

View check run for this annotation

Codecov / codecov/patch

src/app/admin/admin-reports/filtered-collections/filtered-collection.model.ts#L31

Added line #L31 was not covered by tests
}
}
this.allFiltersValue = object.all_filters_value;

Check warning on line 34 in src/app/admin/admin-reports/filtered-collections/filtered-collection.model.ts

View check run for this annotation

Codecov / codecov/patch

src/app/admin/admin-reports/filtered-collections/filtered-collection.model.ts#L34

Added line #L34 was not covered by tests
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<div class="container">
<div class="metadata-registry row">
<div class="col-12">

<h1 id="header" class="border-bottom pb-2">{{ "admin.reports.collections.head" | translate }}</h1>

<div id="metadatadiv">
<ngb-accordion [closeOthers]="true" activeIds="filters" #acc="ngbAccordion">
<ngb-panel id="filters">
<ng-template ngbPanelTitle>
{{ "admin.reports.commons.filters" | translate }}
</ng-template>
<ng-template ngbPanelContent>
<div class="container">
<div class="row">
<span class="col-3"></span>
<button class="btn btn-primary mt-1 col-6" (click)="submit()">{{ "admin.reports.button.show-collections" | translate }}</button>
</div>
<ds-filters [filtersForm]="filtersFormGroup()"></ds-filters>
<div class="row">
<span class="col-3"></span>
<button class="btn btn-primary mt-1 col-6" (click)="submit()">{{ "admin.reports.button.show-collections" | translate }}</button>
</div>
</div>
</ng-template>
</ngb-panel>
<ngb-panel id="collections">
<ng-template ngbPanelTitle>
{{ "admin.reports.collections.collections-report" | translate }}
</ng-template>
<ng-template ngbPanelContent>
<table id="table" class="table table-striped">
<thead>
<tr class="header">
<th rowspan="2">{{ "admin.reports.collections.community" | translate }}</th>
<th rowspan="2">{{ "admin.reports.collections.collection" | translate }}</th>
<th>{{ "admin.reports.collections.nb_items" | translate }}</th>
<th>{{ "admin.reports.collections.match_all_selected_filters" | translate }}</th>
<th *ngFor="let filter of results.summary.values | keyvalue">{{ ("admin.reports.commons.filters." + getGroup(filter.key) + "." + filter.key) | translate }}</th>
</tr>
<tr class="header">
<th class="num">{{ results.summary.nbTotalItems }}</th>
<th class="num">{{ results.summary.allFiltersValue }}</th>
<th class="num" *ngFor="let filter of results.summary.values | keyvalue">{{ filter.value }}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let coll of results.collections">
<td><a href="/handle/{{ coll.communityHandle }}" rel="noopener noreferrer" target="_blank">{{ coll.communityLabel }}</a></td>
<td><a href="/handle/{{ coll.handle }}" rel="noopener noreferrer" target="_blank">{{ coll.label }}</a></td>
<td class="num">{{ coll.nbTotalItems }}</td>
<td class="num">{{ coll.allFiltersValue }}</td>
<td class="num" *ngFor="let filter of results.summary.values | keyvalue">{{ coll.values[filter.key] || 0 }}</td>
</tr>
</tbody>
</table>
</ng-template>
</ngb-panel>
</ngb-accordion>
</div>

</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.num {
text-align: center;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { waitForAsync, ComponentFixture, TestBed} from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateLoaderMock } from 'src/app/shared/mocks/translate-loader.mock';
import { FormBuilder } from '@angular/forms';
import { FilteredCollectionsComponent } from './filtered-collections.component';
import { DspaceRestService } from 'src/app/core/dspace-rest/dspace-rest.service';
import { NgbAccordion, NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { of as observableOf } from 'rxjs';
import { RawRestResponse } from 'src/app/core/dspace-rest/raw-rest-response.model';

describe('FiltersComponent', () => {
let component: FilteredCollectionsComponent;
let fixture: ComponentFixture<FilteredCollectionsComponent>;
let formBuilder: FormBuilder;

const expected = {
payload: {
collections: [],
summary: {
label: 'Test'
}
},
statusCode: 200,
statusText: 'OK'
} as RawRestResponse;

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [FilteredCollectionsComponent],
imports: [
NgbAccordionModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderMock
}
}),
HttpClientTestingModule
],
providers: [
FormBuilder,
DspaceRestService
],
schemas: [NO_ERRORS_SCHEMA]
});
}));

beforeEach(waitForAsync(() => {
formBuilder = TestBed.inject(FormBuilder);

fixture = TestBed.createComponent(FilteredCollectionsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));

it('should create the component', () => {
expect(component).toBeTruthy();
});

it('should be displaying the filters panel initially', () => {
let accordion: NgbAccordion = component.accordionComponent;
expect(accordion.isExpanded('filters')).toBeTrue();
});

describe('toggle', () => {
beforeEach(() => {
spyOn(component, 'getFilteredCollections').and.returnValue(observableOf(expected));
spyOn(component.results, 'deserialize');
spyOn(component.accordionComponent, 'expand').and.callThrough();
component.submit();
fixture.detectChanges();
});

it('should be displaying the collections panel after submitting', waitForAsync(() => {
fixture.whenStable().then(() => {
expect(component.accordionComponent.expand).toHaveBeenCalledWith('collections');
expect(component.accordionComponent.isExpanded('collections')).toBeTrue();
});
}));
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Component, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { NgbAccordion } from '@ng-bootstrap/ng-bootstrap';
import { Observable } from 'rxjs';
import { RestRequestMethod } from 'src/app/core/data/rest-request-method';
import { DspaceRestService } from 'src/app/core/dspace-rest/dspace-rest.service';
import { RawRestResponse } from 'src/app/core/dspace-rest/raw-rest-response.model';
import { environment } from 'src/environments/environment';
import { FiltersComponent } from '../filters-section/filters-section.component';
import { FilteredCollections } from './filtered-collections.model';

/**
* Component representing the Filtered Collections content report
*/
@Component({
selector: 'ds-report-filtered-collections',
templateUrl: './filtered-collections.component.html',
styleUrls: ['./filtered-collections.component.scss']
})
export class FilteredCollectionsComponent {
tdonohue marked this conversation as resolved.
Show resolved Hide resolved

queryForm: FormGroup;
results: FilteredCollections = new FilteredCollections();
@ViewChild('acc') accordionComponent: NgbAccordion;

constructor(
private formBuilder: FormBuilder,
private restService: DspaceRestService) {}

ngOnInit() {
this.queryForm = this.formBuilder.group({
filters: FiltersComponent.formGroup(this.formBuilder)
});
}

filtersFormGroup(): FormGroup {
return this.queryForm.get('filters') as FormGroup;
}

getGroup(filterId: string): string {
return FiltersComponent.getGroup(filterId).id;

Check warning on line 41 in src/app/admin/admin-reports/filtered-collections/filtered-collections.component.ts

View check run for this annotation

Codecov / codecov/patch

src/app/admin/admin-reports/filtered-collections/filtered-collections.component.ts#L41

Added line #L41 was not covered by tests
}

submit() {
this
.getFilteredCollections()
.subscribe(
response => {
this.results.deserialize(response.payload);
this.accordionComponent.expand('collections');
}
);
}

getFilteredCollections(): Observable<RawRestResponse> {
let params = this.toQueryString();

Check warning on line 56 in src/app/admin/admin-reports/filtered-collections/filtered-collections.component.ts

View check run for this annotation

Codecov / codecov/patch

src/app/admin/admin-reports/filtered-collections/filtered-collections.component.ts#L56

Added line #L56 was not covered by tests
if (params.length > 0) {
params = `?${params}`;

Check warning on line 58 in src/app/admin/admin-reports/filtered-collections/filtered-collections.component.ts

View check run for this annotation

Codecov / codecov/patch

src/app/admin/admin-reports/filtered-collections/filtered-collections.component.ts#L58

Added line #L58 was not covered by tests
}
let scheme = environment.rest.ssl ? 'https' : 'http';
let urlRestApp = `${scheme}://${environment.rest.host}:${environment.rest.port}${environment.rest.nameSpace}`;
return this.restService.request(RestRequestMethod.GET, `${urlRestApp}/api/contentreport/filteredcollections${params}`);

Check warning on line 62 in src/app/admin/admin-reports/filtered-collections/filtered-collections.component.ts

View check run for this annotation

Codecov / codecov/patch

src/app/admin/admin-reports/filtered-collections/filtered-collections.component.ts#L61-L62

Added lines #L61 - L62 were not covered by tests
}

private toQueryString(): string {
let params = FiltersComponent.toQueryString(this.queryForm.value.filters);
return params;

Check warning on line 67 in src/app/admin/admin-reports/filtered-collections/filtered-collections.component.ts

View check run for this annotation

Codecov / codecov/patch

src/app/admin/admin-reports/filtered-collections/filtered-collections.component.ts#L66-L67

Added lines #L66 - L67 were not covered by tests
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { FilteredCollection } from './filtered-collection.model';

export class FilteredCollections {

public collections: Array<FilteredCollection> = [];
public summary: FilteredCollection = new FilteredCollection();

public clear() {
this.collections.splice(0, this.collections.length);
this.summary.clear();

Check warning on line 10 in src/app/admin/admin-reports/filtered-collections/filtered-collections.model.ts

View check run for this annotation

Codecov / codecov/patch

src/app/admin/admin-reports/filtered-collections/filtered-collections.model.ts#L9-L10

Added lines #L9 - L10 were not covered by tests
}

public deserialize(object: any) {
this.clear();
let summary = object.summary;
this.summary.deserialize(summary);
let collections = object.collections;
for (let i = 0; i < collections.length; i++) {
let collection = collections[i];
let coll = new FilteredCollection();
coll.deserialize(collection);
this.collections.push(coll);

Check warning on line 22 in src/app/admin/admin-reports/filtered-collections/filtered-collections.model.ts

View check run for this annotation

Codecov / codecov/patch

src/app/admin/admin-reports/filtered-collections/filtered-collections.model.ts#L14-L22

Added lines #L14 - L22 were not covered by tests
}
}

}
23 changes: 23 additions & 0 deletions src/app/admin/admin-reports/filtered-items/filtered-items-model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Item } from 'src/app/core/shared/item.model';

export class FilteredItems {

public items: Item[] = [];
public itemCount: number;

public clear() {
this.items.splice(0, this.items.length);
}

public deserialize(object: any, offset: number = 0) {
this.clear();
this.itemCount = object.itemCount;
let items = object.items;
for (let i = 0; i < items.length; i++) {
let item = items[i];
item.index = this.items.length + offset + 1;
this.items.push(item);
}
}

}
Loading
Loading