From 25458900fe7112826e28d2ea9565bbbf63d13cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Thu, 13 Feb 2025 13:38:51 -0500 Subject: [PATCH 01/33] CSV export for Filtered Items content report --- .../filtered-items-export-csv.component.html | 7 + .../filtered-items-export-csv.component.scss | 4 + ...iltered-items-export-csv.component.spec.ts | 179 ++++++++++++++++++ .../filtered-items-export-csv.component.ts | 127 +++++++++++++ .../filtered-items.component.html | 6 +- .../filtered-items.component.ts | 2 + src/assets/i18n/en.json5 | 6 + src/assets/i18n/fr.json5 | 12 +- 8 files changed, 339 insertions(+), 4 deletions(-) create mode 100644 src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.html create mode 100644 src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.scss create mode 100644 src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts create mode 100644 src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.html b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.html new file mode 100644 index 00000000000..f5c8dc13f38 --- /dev/null +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.html @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.scss b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.scss new file mode 100644 index 00000000000..4b0ab3c44ad --- /dev/null +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.scss @@ -0,0 +1,4 @@ +.export-button { + background: var(--ds-admin-sidebar-bg); + border-color: var(--ds-admin-sidebar-bg); +} \ No newline at end of file diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts new file mode 100644 index 00000000000..5258651fafd --- /dev/null +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts @@ -0,0 +1,179 @@ +import { + ComponentFixture, + TestBed, + waitForAsync, +} from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { Router } from '@angular/router'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateModule } from '@ngx-translate/core'; +import { of as observableOf } from 'rxjs'; + +import { AuthorizationDataService } from '../../../../core/data/feature-authorization/authorization-data.service'; +import { ScriptDataService } from '../../../../core/data/processes/script-data.service'; +import { getProcessDetailRoute } from '../../../../process-page/process-page-routing.paths'; +import { Process } from '../../../../process-page/processes/process.model'; +import { Script } from '../../../../process-page/scripts/script.model'; +import { NotificationsService } from '../../../../shared/notifications/notifications.service'; +import { + createFailedRemoteDataObject$, + createSuccessfulRemoteDataObject$, +} from '../../../../shared/remote-data.utils'; +import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub'; +import { FilteredItemsExportCsvComponent } from './filtered-items-export-csv.component'; +import { FormControl, FormGroup } from '@angular/forms'; + +describe('FilteredItemsExportCsvComponent', () => { + let component: FilteredItemsExportCsvComponent; + let fixture: ComponentFixture; + + let scriptDataService: ScriptDataService; + let authorizationDataService: AuthorizationDataService; + let notificationsService; + let router; + + const script = Object.assign(new Script(), { id: 'metadata-export-filtered-items-report', name: 'metadata-export-filtered-items-report' }); + const process = Object.assign(new Process(), { processId: 5, scriptName: 'metadata-export-filtered-items-report' }); + + const params = new FormGroup({ + collections: new FormControl(), + queryPredicates: new FormControl(), + filters: new FormGroup({}) + }); + + function initBeforeEachAsync() { + scriptDataService = jasmine.createSpyObj('scriptDataService', { + findById: createSuccessfulRemoteDataObject$(script), + invoke: createSuccessfulRemoteDataObject$(process), + }); + authorizationDataService = jasmine.createSpyObj('authorizationService', { + isAuthorized: observableOf(true), + }); + + notificationsService = new NotificationsServiceStub(); + + router = jasmine.createSpyObj('authorizationService', ['navigateByUrl']); + TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot(), NgbModule, FilteredItemsExportCsvComponent], + providers: [ + { provide: ScriptDataService, useValue: scriptDataService }, + { provide: AuthorizationDataService, useValue: authorizationDataService }, + { provide: NotificationsService, useValue: notificationsService }, + { provide: Router, useValue: router }, + ], + }).compileComponents(); + } + + function initBeforeEach() { + fixture = TestBed.createComponent(FilteredItemsExportCsvComponent); + component = fixture.componentInstance; + component.reportParams = params; + fixture.detectChanges(); + } + + describe('init', () => { + describe('comp', () => { + beforeEach(waitForAsync(() => { + initBeforeEachAsync(); + })); + beforeEach(() => { + initBeforeEach(); + }); + it('should init the comp', () => { + expect(component).toBeTruthy(); + }); + }); + describe('when the user is an admin and the metadata-export-search script is present ', () => { + beforeEach(waitForAsync(() => { + initBeforeEachAsync(); + })); + beforeEach(() => { + initBeforeEach(); + }); + it('should add the button', () => { + const debugElement = fixture.debugElement.query(By.css('button.export-button')); + expect(debugElement).toBeDefined(); + }); + }); + describe('when the user is not an admin', () => { + beforeEach(waitForAsync(() => { + initBeforeEachAsync(); + (authorizationDataService.isAuthorized as jasmine.Spy).and.returnValue(observableOf(false)); + })); + beforeEach(() => { + initBeforeEach(); + }); + it('should not add the button', () => { + const debugElement = fixture.debugElement.query(By.css('button.export-button')); + expect(debugElement).toBeNull(); + }); + }); + describe('when the metadata-export-search script is not present', () => { + beforeEach(waitForAsync(() => { + initBeforeEachAsync(); + (scriptDataService.findById as jasmine.Spy).and.returnValue(createFailedRemoteDataObject$('Not found', 404)); + })); + beforeEach(() => { + initBeforeEach(); + }); + it('should should not add the button', () => { + const debugElement = fixture.debugElement.query(By.css('button.export-button')); + expect(debugElement).toBeNull(); + }); + }); + }); + describe('export', () => { + beforeEach(waitForAsync(() => { + initBeforeEachAsync(); + })); + beforeEach(() => { + initBeforeEach(); + }); + it('should call the invoke script method with the correct parameters', () => { + component.export(); + expect(scriptDataService.invoke).toHaveBeenCalledWith('metadata-export-search', + [ + { name: '-c', value: params.value.collections }, + { name: '-qp', value: params.value.queryPredicates }, + { name: '-f', value: params.value.filters } + ], []); + + component.reportParams = null; + fixture.detectChanges(); + + component.export(); + expect(scriptDataService.invoke).toHaveBeenCalledWith('metadata-export-search', [], []); + + }); + it('should show a success message when the script was invoked successfully and redirect to the corresponding process page', () => { + component.export(); + + expect(notificationsService.success).toHaveBeenCalled(); + expect(router.navigateByUrl).toHaveBeenCalledWith(getProcessDetailRoute(process.processId)); + }); + it('should show an error message when the script was not invoked successfully and stay on the current page', () => { + (scriptDataService.invoke as jasmine.Spy).and.returnValue(createFailedRemoteDataObject$('Error', 500)); + + component.export(); + + expect(notificationsService.error).toHaveBeenCalled(); + expect(router.navigateByUrl).not.toHaveBeenCalled(); + }); + }); + describe('clicking the button', () => { + beforeEach(waitForAsync(() => { + initBeforeEachAsync(); + })); + beforeEach(() => { + initBeforeEach(); + }); + it('should trigger the export function', () => { + spyOn(component, 'export'); + + const debugElement = fixture.debugElement.query(By.css('button.export-button')); + debugElement.triggerEventHandler('click', null); + + expect(component.export).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts new file mode 100644 index 00000000000..3b7513fbcda --- /dev/null +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts @@ -0,0 +1,127 @@ +import { + AsyncPipe, + NgIf, +} from '@angular/common'; +import { + Component, + Input, + OnInit, +} from '@angular/core'; +import { Router } from '@angular/router'; +import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; +import { + TranslateModule, + TranslateService, +} from '@ngx-translate/core'; +import { + combineLatest as observableCombineLatest, + Observable, +} from 'rxjs'; +import { map } from 'rxjs/operators'; + +import { AuthorizationDataService } from '../../../../core/data/feature-authorization/authorization-data.service'; +import { FeatureID } from '../../../../core/data/feature-authorization/feature-id'; +import { ScriptDataService } from '../../../../core/data/processes/script-data.service'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { getFirstCompletedRemoteData } from '../../../../core/shared/operators'; +import { getProcessDetailRoute } from '../../../../process-page/process-page-routing.paths'; +import { Process } from '../../../../process-page/processes/process.model'; +import { + hasValue, + isNotEmpty, +} from '../../../../shared/empty.util'; +import { NotificationsService } from '../../../../shared/notifications/notifications.service'; +import { FormGroup } from '@angular/forms'; +import { FiltersComponent } from '../../filters-section/filters-section.component'; + +@Component({ + selector: 'ds-filtered-items-export-csv', + styleUrls: ['./filtered-items-export-csv.component.scss'], + templateUrl: './filtered-items-export-csv.component.html', + standalone: true, + imports: [NgIf, NgbTooltipModule, AsyncPipe, TranslateModule], +}) +/** + * Display a button to export the current search results as csv + */ +export class FilteredItemsExportCsvComponent implements OnInit { + + /** + * The current configuration of the search + */ + @Input() reportParams: FormGroup; + + /** + * Observable used to determine whether the button should be shown + */ + shouldShowButton$: Observable; + + /** + * The message key used for the tooltip of the button + */ + tooltipMsg = 'metadata-export-filtered-items.tooltip'; + + constructor(private scriptDataService: ScriptDataService, + private authorizationDataService: AuthorizationDataService, + private notificationsService: NotificationsService, + private translateService: TranslateService, + private router: Router, + ) { + } + + ngOnInit(): void { + const scriptExists$ = this.scriptDataService.findById('metadata-export-filtered-items-report').pipe( + getFirstCompletedRemoteData(), + map((rd) => rd.isSuccess && hasValue(rd.payload)), + ); + + const isAuthorized$ = this.authorizationDataService.isAuthorized(FeatureID.AdministratorOf); + + this.shouldShowButton$ = observableCombineLatest([scriptExists$, isAuthorized$]).pipe( + map(([scriptExists, isAuthorized]: [boolean, boolean]) => scriptExists && isAuthorized), + ); + } + + /** + * Start the export of the items based on the selected parameters + */ + export() { + const parameters = []; + const colls = this.reportParams.value.collections; + for (let i = 0; i < colls.length; i++) { + if (colls[i]) { + parameters.push({ name: '-c', value: colls[i] }); + } + } + + const preds = this.reportParams.value.queryPredicates; + for (let i = 0; i < preds.length; i++) { + const field = preds[i].field; + const op = preds[i].operator; + if (field && op) { + const value = preds[i].value; + if (value) { + parameters.push({ name: '-qp', value: `${field}:${op}:${value}` }); + } else { + parameters.push({ name: '-qp', value: `${field}:${op}` }); + } + } + } + + const filters = FiltersComponent.toQueryString(this.reportParams.value.filters); + if (filters.length > 0) { + parameters.push({ name: '-f', value: filters }); + } + + this.scriptDataService.invoke('metadata-export-filtered-items-report', parameters, []).pipe( + getFirstCompletedRemoteData(), + ).subscribe((rd: RemoteData) => { + if (rd.hasSucceeded) { + this.notificationsService.success(this.translateService.get('metadata-export-filtered-items.submit.success')); + this.router.navigateByUrl(getProcessDetailRoute(rd.payload.processId)); + } else { + this.notificationsService.error(this.translateService.get('metadata-export-filtered-items.submit.error')); + } + }); + } +} diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items.component.html b/src/app/admin/admin-reports/filtered-items/filtered-items.component.html index a765c4a1909..f581bff2e8c 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items.component.html +++ b/src/app/admin/admin-reports/filtered-items/filtered-items.component.html @@ -160,9 +160,9 @@

{{'admin.reports.items.head' | transl
- +
+ +
diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts index 04ee4894ec9..9be5b0040a8 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts @@ -49,6 +49,7 @@ import { FilteredItems } from './filtered-items-model'; import { OptionVO } from './option-vo.model'; import { PresetQuery } from './preset-query.model'; import { QueryPredicate } from './query-predicate.model'; +import { FilteredItemsExportCsvComponent } from './filtered-items-export-csv/filtered-items-export-csv.component'; /** * Component representing the Filtered Items content report. @@ -66,6 +67,7 @@ import { QueryPredicate } from './query-predicate.model'; NgForOf, FiltersComponent, BtnDisabledDirective, + FilteredItemsExportCsvComponent ], standalone: true, }) diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 7da72f0fb3a..aac3f818f69 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -6787,4 +6787,10 @@ "live-region.ordering.dropped": "{{ itemName }}, dropped at position {{ index }} of {{ length }}.", "dynamic-form-array.sortable-list.label": "Sortable list", + + "metadata-export-filtered-items.tooltip": "Export report output as CSV", + + "metadata-export-filtered-items.submit.success": "CSV export succeeded.", + + "metadata-export-filtered-items.submit.error": "CSV export failed.", } diff --git a/src/assets/i18n/fr.json5 b/src/assets/i18n/fr.json5 index bee30294a96..c8468e6c574 100644 --- a/src/assets/i18n/fr.json5 +++ b/src/assets/i18n/fr.json5 @@ -8402,6 +8402,16 @@ "item.page.cc.license.disclaimer": "Sauf indication contraire, la licence de cet Item est décrite comme", //"browse.search-form.placeholder": "Search the repository", - "browse.search-form.placeholder": "Chercher dans le dépôt", + "browse.search-form.placeholder": "Chercher dans le dépôt", //"metadata-export-filtered-items.tooltip": "Export report output as CSV", + + //"metadata-export-filtered-items.tooltip": "Export report output as CSV", + "metadata-export-filtered-items.tooltip": "Exporter le rapport en CSV", + + //"metadata-export-filtered-items.submit.success": "CSV export succeeded.", + "metadata-export-filtered-items.submit.success": "Exportation CSV complétée.", + + //"metadata-export-filtered-items.submit.error": "CSV export failed.", + "metadata-export-filtered-items.submit.error": "L'exportation CSV n'a pas fonctionné.", + } From 7694dacd35e138d2edda3841849056e6de953a73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Fri, 14 Feb 2025 14:25:55 -0500 Subject: [PATCH 02/33] Fixed lint errors --- config/config.yml | 49 +++++++++++++++++-- ...iltered-items-export-csv.component.spec.ts | 9 ++-- .../filtered-items-export-csv.component.ts | 3 +- .../filtered-items.component.ts | 4 +- 4 files changed, 54 insertions(+), 11 deletions(-) diff --git a/config/config.yml b/config/config.yml index 109db60ca92..a51264f27b6 100644 --- a/config/config.yml +++ b/config/config.yml @@ -1,5 +1,46 @@ rest: - ssl: true - host: sandbox.dspace.org - port: 443 - nameSpace: /server + ssl: false + host: localhost + port: 8080 + nameSpace: /dspace-server + +form: + recaptcha: + v2SiteKey: 6Leado4hAAAAAA5sjp8htg4b9iFmjC4E4XBH4VrB + v3SiteKey: 6Le0eI4hAAAAAJEEmz-fOOSl6DTqzK35EEov-Ivn + +themes: + - name: dspace + headTags: + - tagName: link + attributes: + rel: icon + href: assets/dspace/images/favicons/favicon.ico + sizes: any + - tagName: link + attributes: + rel: icon + href: assets/dspace/images/favicons/favicon.svg + type: image/svg+xml + - tagName: link + attributes: + rel: apple-touch-icon + href: assets/dspace/images/favicons/apple-touch-icon.png + - tagName: link + attributes: + rel: manifest + href: assets/dspace/images/favicons/manifest.webmanifest + +item: + showAccessStatuses: true + +languages: + - code: fr + label: Français + active: true + - code: en + label: English + active: true + +browseBy: + showThumbnails: false diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts index 5258651fafd..5aa78a4082b 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts @@ -21,7 +21,10 @@ import { } from '../../../../shared/remote-data.utils'; import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub'; import { FilteredItemsExportCsvComponent } from './filtered-items-export-csv.component'; -import { FormControl, FormGroup } from '@angular/forms'; +import { + FormControl, + FormGroup, +} from '@angular/forms'; describe('FilteredItemsExportCsvComponent', () => { let component: FilteredItemsExportCsvComponent; @@ -38,7 +41,7 @@ describe('FilteredItemsExportCsvComponent', () => { const params = new FormGroup({ collections: new FormControl(), queryPredicates: new FormControl(), - filters: new FormGroup({}) + filters: new FormGroup({}), }); function initBeforeEachAsync() { @@ -135,7 +138,7 @@ describe('FilteredItemsExportCsvComponent', () => { [ { name: '-c', value: params.value.collections }, { name: '-qp', value: params.value.queryPredicates }, - { name: '-f', value: params.value.filters } + { name: '-f', value: params.value.filters }, ], []); component.reportParams = null; diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts index 3b7513fbcda..66a64439ed1 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts @@ -28,11 +28,10 @@ import { getProcessDetailRoute } from '../../../../process-page/process-page-rou import { Process } from '../../../../process-page/processes/process.model'; import { hasValue, - isNotEmpty, } from '../../../../shared/empty.util'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; -import { FormGroup } from '@angular/forms'; import { FiltersComponent } from '../../filters-section/filters-section.component'; +import { FormGroup } from '@angular/forms'; @Component({ selector: 'ds-filtered-items-export-csv', diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts index 9be5b0040a8..75e6ed701fb 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts @@ -45,11 +45,11 @@ import { environment } from 'src/environments/environment'; import { BtnDisabledDirective } from '../../../shared/btn-disabled.directive'; import { FiltersComponent } from '../filters-section/filters-section.component'; +import { FilteredItemsExportCsvComponent } from './filtered-items-export-csv/filtered-items-export-csv.component'; import { FilteredItems } from './filtered-items-model'; import { OptionVO } from './option-vo.model'; import { PresetQuery } from './preset-query.model'; import { QueryPredicate } from './query-predicate.model'; -import { FilteredItemsExportCsvComponent } from './filtered-items-export-csv/filtered-items-export-csv.component'; /** * Component representing the Filtered Items content report. @@ -67,7 +67,7 @@ import { FilteredItemsExportCsvComponent } from './filtered-items-export-csv/fil NgForOf, FiltersComponent, BtnDisabledDirective, - FilteredItemsExportCsvComponent + FilteredItemsExportCsvComponent, ], standalone: true, }) From cae31ae782d9b96f0da3fb16bd25387f51087ed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Fri, 14 Feb 2025 14:34:28 -0500 Subject: [PATCH 03/33] Fixed lint errors --- .../filtered-items-export-csv.component.spec.ts | 4 ++-- .../filtered-items-export-csv.component.ts | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts index 5aa78a4082b..61a26bd5253 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts @@ -22,8 +22,8 @@ import { import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub'; import { FilteredItemsExportCsvComponent } from './filtered-items-export-csv.component'; import { - FormControl, - FormGroup, + FormControl, + FormGroup, } from '@angular/forms'; describe('FilteredItemsExportCsvComponent', () => { diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts index 66a64439ed1..1b4d03a20c7 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts @@ -26,9 +26,7 @@ import { RemoteData } from '../../../../core/data/remote-data'; import { getFirstCompletedRemoteData } from '../../../../core/shared/operators'; import { getProcessDetailRoute } from '../../../../process-page/process-page-routing.paths'; import { Process } from '../../../../process-page/processes/process.model'; -import { - hasValue, -} from '../../../../shared/empty.util'; +import { hasValue } from '../../../../shared/empty.util'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { FiltersComponent } from '../../filters-section/filters-section.component'; import { FormGroup } from '@angular/forms'; From 4003193ba1d1ba83b98140d63d0ebecddc52660a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Fri, 14 Feb 2025 14:41:29 -0500 Subject: [PATCH 04/33] Fixed lint errors --- .../filtered-items-export-csv.component.spec.ts | 8 ++++---- .../filtered-items-export-csv.component.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts index 61a26bd5253..123addeb781 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts @@ -3,6 +3,10 @@ import { TestBed, waitForAsync, } from '@angular/core/testing'; +import { + FormControl, + FormGroup, +} from '@angular/forms'; import { By } from '@angular/platform-browser'; import { Router } from '@angular/router'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; @@ -21,10 +25,6 @@ import { } from '../../../../shared/remote-data.utils'; import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub'; import { FilteredItemsExportCsvComponent } from './filtered-items-export-csv.component'; -import { - FormControl, - FormGroup, -} from '@angular/forms'; describe('FilteredItemsExportCsvComponent', () => { let component: FilteredItemsExportCsvComponent; diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts index 1b4d03a20c7..8ea49f13893 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts @@ -7,6 +7,7 @@ import { Input, OnInit, } from '@angular/core'; +import { FormGroup } from '@angular/forms'; import { Router } from '@angular/router'; import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; import { @@ -29,7 +30,6 @@ import { Process } from '../../../../process-page/processes/process.model'; import { hasValue } from '../../../../shared/empty.util'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { FiltersComponent } from '../../filters-section/filters-section.component'; -import { FormGroup } from '@angular/forms'; @Component({ selector: 'ds-filtered-items-export-csv', From bc3fb27c0c36df7d17caaf3d4b2a4cd8d1aa33ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Fri, 14 Feb 2025 15:05:27 -0500 Subject: [PATCH 05/33] Make variables for CSV export null-proof --- .../filtered-items-export-csv.component.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts index 8ea49f13893..c6446eb23ac 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts @@ -84,14 +84,14 @@ export class FilteredItemsExportCsvComponent implements OnInit { */ export() { const parameters = []; - const colls = this.reportParams.value.collections; + const colls = this.reportParams.value.collections || []; for (let i = 0; i < colls.length; i++) { if (colls[i]) { parameters.push({ name: '-c', value: colls[i] }); } } - const preds = this.reportParams.value.queryPredicates; + const preds = this.reportParams.value.queryPredicates || []; for (let i = 0; i < preds.length; i++) { const field = preds[i].field; const op = preds[i].operator; @@ -105,7 +105,7 @@ export class FilteredItemsExportCsvComponent implements OnInit { } } - const filters = FiltersComponent.toQueryString(this.reportParams.value.filters); + const filters = FiltersComponent.toQueryString(this.reportParams.value.filters) || []; if (filters.length > 0) { parameters.push({ name: '-f', value: filters }); } From 417b289dfb603322ccdc4185d77e16c1fce4e346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Mon, 17 Feb 2025 09:07:59 -0500 Subject: [PATCH 06/33] Attempt to fix unit tests --- .../filtered-items-export-csv.component.spec.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts index 123addeb781..1705a8d5044 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts @@ -24,6 +24,10 @@ import { createSuccessfulRemoteDataObject$, } from '../../../../shared/remote-data.utils'; import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub'; +import { FiltersComponent } from '../../filters-section/filters-section.component'; +import { Filter } from '../../filters-section/filter.model'; +import { OptionVO } from '../option-vo.model'; +import { QueryPredicate } from '../query-predicate.model'; import { FilteredItemsExportCsvComponent } from './filtered-items-export-csv.component'; describe('FilteredItemsExportCsvComponent', () => { @@ -39,9 +43,9 @@ describe('FilteredItemsExportCsvComponent', () => { const process = Object.assign(new Process(), { processId: 5, scriptName: 'metadata-export-filtered-items-report' }); const params = new FormGroup({ - collections: new FormControl(), - queryPredicates: new FormControl(), - filters: new FormGroup({}), + collections: new FormControl([OptionVO.collection("1", "coll1")]), + queryPredicates: new FormControl([QueryPredicate.of("name", "equals", "coll1")]), + filters: new FormControl([FiltersComponent.getFilter("is_item")]), }); function initBeforeEachAsync() { From 9099c3a3659d9a45b03517b545f822462888d34f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Mon, 17 Feb 2025 09:14:30 -0500 Subject: [PATCH 07/33] Fixed styling errors --- .../filtered-items-export-csv.component.spec.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts index 1705a8d5044..27582e37694 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts @@ -25,7 +25,6 @@ import { } from '../../../../shared/remote-data.utils'; import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub'; import { FiltersComponent } from '../../filters-section/filters-section.component'; -import { Filter } from '../../filters-section/filter.model'; import { OptionVO } from '../option-vo.model'; import { QueryPredicate } from '../query-predicate.model'; import { FilteredItemsExportCsvComponent } from './filtered-items-export-csv.component'; @@ -43,9 +42,9 @@ describe('FilteredItemsExportCsvComponent', () => { const process = Object.assign(new Process(), { processId: 5, scriptName: 'metadata-export-filtered-items-report' }); const params = new FormGroup({ - collections: new FormControl([OptionVO.collection("1", "coll1")]), - queryPredicates: new FormControl([QueryPredicate.of("name", "equals", "coll1")]), - filters: new FormControl([FiltersComponent.getFilter("is_item")]), + collections: new FormControl([OptionVO.collection('1', 'coll1')]), + queryPredicates: new FormControl([QueryPredicate.of('name', 'equals', 'coll1')]), + filters: new FormControl([FiltersComponent.getFilter('is_item')]), }); function initBeforeEachAsync() { From b1ef0bce943ed1881997a10660fa685006bf1de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Mon, 17 Feb 2025 09:33:42 -0500 Subject: [PATCH 08/33] Fixed script references in unit tests --- .../filtered-items-export-csv.component.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts index 27582e37694..bffedadb4b9 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts @@ -89,7 +89,7 @@ describe('FilteredItemsExportCsvComponent', () => { expect(component).toBeTruthy(); }); }); - describe('when the user is an admin and the metadata-export-search script is present ', () => { + describe('when the user is an admin and the metadata-export-filtered-items-report script is present ', () => { beforeEach(waitForAsync(() => { initBeforeEachAsync(); })); @@ -114,7 +114,7 @@ describe('FilteredItemsExportCsvComponent', () => { expect(debugElement).toBeNull(); }); }); - describe('when the metadata-export-search script is not present', () => { + describe('when the metadata-export-filtered-items-report script is not present', () => { beforeEach(waitForAsync(() => { initBeforeEachAsync(); (scriptDataService.findById as jasmine.Spy).and.returnValue(createFailedRemoteDataObject$('Not found', 404)); @@ -137,7 +137,7 @@ describe('FilteredItemsExportCsvComponent', () => { }); it('should call the invoke script method with the correct parameters', () => { component.export(); - expect(scriptDataService.invoke).toHaveBeenCalledWith('metadata-export-search', + expect(scriptDataService.invoke).toHaveBeenCalledWith('metadata-export-filtered-items-reporth', [ { name: '-c', value: params.value.collections }, { name: '-qp', value: params.value.queryPredicates }, @@ -148,7 +148,7 @@ describe('FilteredItemsExportCsvComponent', () => { fixture.detectChanges(); component.export(); - expect(scriptDataService.invoke).toHaveBeenCalledWith('metadata-export-search', [], []); + expect(scriptDataService.invoke).toHaveBeenCalledWith('metadata-export-filtered-items-report', [], []); }); it('should show a success message when the script was invoked successfully and redirect to the corresponding process page', () => { From b3044882aa5eae7d18c8084a7b72561785725ba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Mon, 17 Feb 2025 09:48:38 -0500 Subject: [PATCH 09/33] Fixed typo in script name --- .../filtered-items-export-csv.component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts index bffedadb4b9..bc8b88ed9fa 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts @@ -137,7 +137,7 @@ describe('FilteredItemsExportCsvComponent', () => { }); it('should call the invoke script method with the correct parameters', () => { component.export(); - expect(scriptDataService.invoke).toHaveBeenCalledWith('metadata-export-filtered-items-reporth', + expect(scriptDataService.invoke).toHaveBeenCalledWith('metadata-export-filtered-items-report', [ { name: '-c', value: params.value.collections }, { name: '-qp', value: params.value.queryPredicates }, From 43a7f10f93f37b7b6b3df95f4efb132667415261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Mon, 17 Feb 2025 10:37:22 -0500 Subject: [PATCH 10/33] Fixed test parameterization --- .../filtered-items-export-csv.component.spec.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts index bc8b88ed9fa..f4e0637394b 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts @@ -26,7 +26,6 @@ import { import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub'; import { FiltersComponent } from '../../filters-section/filters-section.component'; import { OptionVO } from '../option-vo.model'; -import { QueryPredicate } from '../query-predicate.model'; import { FilteredItemsExportCsvComponent } from './filtered-items-export-csv.component'; describe('FilteredItemsExportCsvComponent', () => { @@ -42,8 +41,8 @@ describe('FilteredItemsExportCsvComponent', () => { const process = Object.assign(new Process(), { processId: 5, scriptName: 'metadata-export-filtered-items-report' }); const params = new FormGroup({ - collections: new FormControl([OptionVO.collection('1', 'coll1')]), - queryPredicates: new FormControl([QueryPredicate.of('name', 'equals', 'coll1')]), + collections: new FormControl(OptionVO.collection('1', 'coll1')), + queryPredicates: new FormControl(['name:equals:coll1']), filters: new FormControl([FiltersComponent.getFilter('is_item')]), }); From 6db3d41ef2a001d40662ef3d23590a4f986bac2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Mon, 17 Feb 2025 10:54:22 -0500 Subject: [PATCH 11/33] Parameterization attempt --- .../filtered-items-export-csv.component.spec.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts index f4e0637394b..bc8b88ed9fa 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts @@ -26,6 +26,7 @@ import { import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub'; import { FiltersComponent } from '../../filters-section/filters-section.component'; import { OptionVO } from '../option-vo.model'; +import { QueryPredicate } from '../query-predicate.model'; import { FilteredItemsExportCsvComponent } from './filtered-items-export-csv.component'; describe('FilteredItemsExportCsvComponent', () => { @@ -41,8 +42,8 @@ describe('FilteredItemsExportCsvComponent', () => { const process = Object.assign(new Process(), { processId: 5, scriptName: 'metadata-export-filtered-items-report' }); const params = new FormGroup({ - collections: new FormControl(OptionVO.collection('1', 'coll1')), - queryPredicates: new FormControl(['name:equals:coll1']), + collections: new FormControl([OptionVO.collection('1', 'coll1')]), + queryPredicates: new FormControl([QueryPredicate.of('name', 'equals', 'coll1')]), filters: new FormControl([FiltersComponent.getFilter('is_item')]), }); From cd50fb2c93e9a90e001d136ddd787abbbcf54fc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Mon, 17 Feb 2025 11:27:08 -0500 Subject: [PATCH 12/33] Parameterization test --- .../filtered-items-export-csv.component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts index bc8b88ed9fa..a1ebddb4637 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts @@ -42,7 +42,7 @@ describe('FilteredItemsExportCsvComponent', () => { const process = Object.assign(new Process(), { processId: 5, scriptName: 'metadata-export-filtered-items-report' }); const params = new FormGroup({ - collections: new FormControl([OptionVO.collection('1', 'coll1')]), + collections: new FormControl(OptionVO.collection('1', 'coll1')), queryPredicates: new FormControl([QueryPredicate.of('name', 'equals', 'coll1')]), filters: new FormControl([FiltersComponent.getFilter('is_item')]), }); From f543e0728360de672f4004a8ef0c843a303a38c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Mon, 17 Feb 2025 11:50:46 -0500 Subject: [PATCH 13/33] Parameterization rollback --- .../filtered-items-export-csv.component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts index a1ebddb4637..bc8b88ed9fa 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts @@ -42,7 +42,7 @@ describe('FilteredItemsExportCsvComponent', () => { const process = Object.assign(new Process(), { processId: 5, scriptName: 'metadata-export-filtered-items-report' }); const params = new FormGroup({ - collections: new FormControl(OptionVO.collection('1', 'coll1')), + collections: new FormControl([OptionVO.collection('1', 'coll1')]), queryPredicates: new FormControl([QueryPredicate.of('name', 'equals', 'coll1')]), filters: new FormControl([FiltersComponent.getFilter('is_item')]), }); From 80c88b1a22596fa5e4f1031629f1ba35839dfa0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Mon, 17 Feb 2025 14:40:06 -0500 Subject: [PATCH 14/33] Fixed predicate encoding bug --- .../filtered-items/filtered-items.component.ts | 9 ++------- .../filtered-items/query-predicate.model.ts | 7 +++++++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts index 75e6ed701fb..0862c04f0f2 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts @@ -350,13 +350,8 @@ export class FilteredItemsComponent implements OnInit { const preds = this.queryForm.value.queryPredicates; for (let i = 0; i < preds.length; i++) { - const field = preds[i].field; - const op = preds[i].operator; - const value = preds[i].value; - params += `&queryPredicates=${field}:${op}`; - if (value) { - params += `:${value}`; - } + const pred = encodeURIComponent(QueryPredicate.toString(preds[i])); + params += `&queryPredicates=${pred}`; } const filters = FiltersComponent.toQueryString(this.queryForm.value.filters); diff --git a/src/app/admin/admin-reports/filtered-items/query-predicate.model.ts b/src/app/admin/admin-reports/filtered-items/query-predicate.model.ts index 1c12d72e275..f16cb080834 100644 --- a/src/app/admin/admin-reports/filtered-items/query-predicate.model.ts +++ b/src/app/admin/admin-reports/filtered-items/query-predicate.model.ts @@ -37,4 +37,11 @@ export class QueryPredicate { }); } + static toString(pred: QueryPredicate): string { + if (pred.value) { + return `${pred.field}:${pred.operator}:${pred.value}`; + } + return `${pred.field}:${pred.operator}`; + } + } From 3fa60cabacc7e465f55224714d4c14039ee12bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Mon, 17 Feb 2025 14:40:29 -0500 Subject: [PATCH 15/33] Parameterization test --- .../filtered-items-export-csv.component.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts index bc8b88ed9fa..b3b2ea14a44 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts @@ -139,8 +139,8 @@ describe('FilteredItemsExportCsvComponent', () => { component.export(); expect(scriptDataService.invoke).toHaveBeenCalledWith('metadata-export-filtered-items-report', [ - { name: '-c', value: params.value.collections }, - { name: '-qp', value: params.value.queryPredicates }, + { name: '-c', value: params.value.collections[0] }, + { name: '-qp', value: params.value.queryPredicates[0] }, { name: '-f', value: params.value.filters }, ], []); From e23e6aca16dbe61e69cec959738e5d04035fa6c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Mon, 17 Feb 2025 14:46:36 -0500 Subject: [PATCH 16/33] Fixed styling error --- .../filtered-items/query-predicate.model.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/query-predicate.model.ts b/src/app/admin/admin-reports/filtered-items/query-predicate.model.ts index f16cb080834..1c91bfa7444 100644 --- a/src/app/admin/admin-reports/filtered-items/query-predicate.model.ts +++ b/src/app/admin/admin-reports/filtered-items/query-predicate.model.ts @@ -29,6 +29,13 @@ export class QueryPredicate { return pred; } + static toString(pred: QueryPredicate): string { + if (pred.value) { + return `${pred.field}:${pred.operator}:${pred.value}`; + } + return `${pred.field}:${pred.operator}`; + } + toFormGroup(formBuilder: FormBuilder): FormGroup { return formBuilder.group({ field: new FormControl(this.field), @@ -37,11 +44,4 @@ export class QueryPredicate { }); } - static toString(pred: QueryPredicate): string { - if (pred.value) { - return `${pred.field}:${pred.operator}:${pred.value}`; - } - return `${pred.field}:${pred.operator}`; - } - } From d0918300924ef254eadeb7912c9b51166348a77c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Mon, 17 Feb 2025 15:01:45 -0500 Subject: [PATCH 17/33] Fixed query predicate parameter --- .../filtered-items-export-csv.component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts index b3b2ea14a44..5875c19edf4 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts @@ -140,7 +140,7 @@ describe('FilteredItemsExportCsvComponent', () => { expect(scriptDataService.invoke).toHaveBeenCalledWith('metadata-export-filtered-items-report', [ { name: '-c', value: params.value.collections[0] }, - { name: '-qp', value: params.value.queryPredicates[0] }, + { name: '-qp', value: QueryPredicate.toString(params.value.queryPredicates[0]) }, { name: '-f', value: params.value.filters }, ], []); From 8ff97c26aae843d045071ffcdf6d234a6619ed7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Mon, 17 Feb 2025 15:23:03 -0500 Subject: [PATCH 18/33] Fixed collection parameterization --- .../filtered-items-export-csv.component.spec.ts | 4 ++-- .../filtered-items-export-csv.component.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts index 5875c19edf4..019bec28b74 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts @@ -139,9 +139,9 @@ describe('FilteredItemsExportCsvComponent', () => { component.export(); expect(scriptDataService.invoke).toHaveBeenCalledWith('metadata-export-filtered-items-report', [ - { name: '-c', value: params.value.collections[0] }, + { name: '-c', value: params.value.collections[0].id }, { name: '-qp', value: QueryPredicate.toString(params.value.queryPredicates[0]) }, - { name: '-f', value: params.value.filters }, + { name: '-f', value: FiltersComponent.toQueryString(params.value.filters) }, ], []); component.reportParams = null; diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts index c6446eb23ac..519d1e95ab9 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts @@ -87,7 +87,7 @@ export class FilteredItemsExportCsvComponent implements OnInit { const colls = this.reportParams.value.collections || []; for (let i = 0; i < colls.length; i++) { if (colls[i]) { - parameters.push({ name: '-c', value: colls[i] }); + parameters.push({ name: '-c', value: colls[i].id }); } } From d918de74d430778b19fc112e48df3f2eaa8a5378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Mon, 17 Feb 2025 15:43:02 -0500 Subject: [PATCH 19/33] Centralized string representation of a predicate --- .../filtered-items-export-csv.component.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts index 519d1e95ab9..a1ab92f8035 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts @@ -30,6 +30,7 @@ import { Process } from '../../../../process-page/processes/process.model'; import { hasValue } from '../../../../shared/empty.util'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { FiltersComponent } from '../../filters-section/filters-section.component'; +import { QueryPredicate } from '../query-predicate.model'; @Component({ selector: 'ds-filtered-items-export-csv', @@ -96,12 +97,7 @@ export class FilteredItemsExportCsvComponent implements OnInit { const field = preds[i].field; const op = preds[i].operator; if (field && op) { - const value = preds[i].value; - if (value) { - parameters.push({ name: '-qp', value: `${field}:${op}:${value}` }); - } else { - parameters.push({ name: '-qp', value: `${field}:${op}` }); - } + parameters.push({ name: '-qp', value: QueryPredicate.toString(preds[i]) }); } } From a2cf15153d90aea2c96cf2ead1e02bdc36c5e569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Mon, 17 Feb 2025 16:00:55 -0500 Subject: [PATCH 20/33] Fixed parameterization --- .../filtered-items-export-csv.component.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts index 019bec28b74..7bd2d4ef2dc 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts @@ -144,7 +144,6 @@ describe('FilteredItemsExportCsvComponent', () => { { name: '-f', value: FiltersComponent.toQueryString(params.value.filters) }, ], []); - component.reportParams = null; fixture.detectChanges(); component.export(); From 51cb5bfbf73e7edacc551ff19c9c2e101c164b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Tue, 18 Feb 2025 08:50:12 -0500 Subject: [PATCH 21/33] Fixed second export test --- .../filtered-items-export-csv.component.spec.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts index 7bd2d4ef2dc..8e85fa101c1 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts @@ -136,6 +136,7 @@ describe('FilteredItemsExportCsvComponent', () => { initBeforeEach(); }); it('should call the invoke script method with the correct parameters', () => { + // Parameterized export component.export(); expect(scriptDataService.invoke).toHaveBeenCalledWith('metadata-export-filtered-items-report', [ @@ -146,6 +147,8 @@ describe('FilteredItemsExportCsvComponent', () => { fixture.detectChanges(); + // Non-parameterized export + component.reportParams = null; component.export(); expect(scriptDataService.invoke).toHaveBeenCalledWith('metadata-export-filtered-items-report', [], []); From 058eaa0c1c3da7127ec666e70a5aab20514d1a40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Tue, 18 Feb 2025 09:10:13 -0500 Subject: [PATCH 22/33] Replaced null payload by an empty non-null one --- .../filtered-items-export-csv.component.spec.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts index 8e85fa101c1..d9627dff701 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.spec.ts @@ -47,6 +47,12 @@ describe('FilteredItemsExportCsvComponent', () => { filters: new FormControl([FiltersComponent.getFilter('is_item')]), }); + const emptyParams = new FormGroup({ + collections: new FormControl([]), + queryPredicates: new FormControl([]), + filters: new FormControl([]), + }); + function initBeforeEachAsync() { scriptDataService = jasmine.createSpyObj('scriptDataService', { findById: createSuccessfulRemoteDataObject$(script), @@ -148,7 +154,8 @@ describe('FilteredItemsExportCsvComponent', () => { fixture.detectChanges(); // Non-parameterized export - component.reportParams = null; + component.reportParams = emptyParams; + fixture.detectChanges(); component.export(); expect(scriptDataService.invoke).toHaveBeenCalledWith('metadata-export-filtered-items-report', [], []); From 699975333814e717cd78c76fbe4634fdc9656630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Mon, 10 Mar 2025 14:31:22 -0400 Subject: [PATCH 23/33] Requested changes --- config/config.yml | 8 ++++---- .../filtered-items-export-csv.component.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/config/config.yml b/config/config.yml index a51264f27b6..dd7645fc1e5 100644 --- a/config/config.yml +++ b/config/config.yml @@ -1,8 +1,8 @@ rest: - ssl: false - host: localhost - port: 8080 - nameSpace: /dspace-server + ssl: true + host: sandbox.dspace.org + port: 443 + nameSpace: /server form: recaptcha: diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts index a1ab92f8035..4acb38c4e84 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts @@ -40,7 +40,7 @@ import { QueryPredicate } from '../query-predicate.model'; imports: [NgIf, NgbTooltipModule, AsyncPipe, TranslateModule], }) /** - * Display a button to export the current search results as csv + * Display a button to export the MetadataQuery (aka Filtered Items) Report results as csv */ export class FilteredItemsExportCsvComponent implements OnInit { From c5fc638f6eefba341f176115333bbbaf81a987c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Mon, 10 Mar 2025 16:00:42 -0400 Subject: [PATCH 24/33] Fixed remaining bugs --- .../filtered-items-export-csv.component.ts | 2 +- .../admin-reports/filtered-items/filtered-items.component.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts index 4acb38c4e84..4c3709afc0f 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts @@ -88,7 +88,7 @@ export class FilteredItemsExportCsvComponent implements OnInit { const colls = this.reportParams.value.collections || []; for (let i = 0; i < colls.length; i++) { if (colls[i]) { - parameters.push({ name: '-c', value: colls[i].id }); + parameters.push({ name: '-c', value: colls[i] }); } } diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts index 0862c04f0f2..59a2af07b51 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts @@ -173,10 +173,10 @@ export class FilteredItemsComponent implements OnInit { QueryPredicate.of('dc.description.provenance', QueryPredicate.DOES_NOT_MATCH, '^.*No\. of bitstreams(.|\r|\n|\r\n)*\.(PDF|pdf|DOC|doc|PPT|ppt|DOCX|docx|PPTX|pptx).*$'), ]), PresetQuery.of('q9', 'admin.reports.items.preset.hasEmptyMetadata', [ - QueryPredicate.of('*', QueryPredicate.MATCHES, '^\s*$'), + QueryPredicate.of('*', QueryPredicate.MATCHES, '^\\s*$'), ]), PresetQuery.of('q10', 'admin.reports.items.preset.hasUnbreakingDataInDescription', [ - QueryPredicate.of('dc.description.*', QueryPredicate.MATCHES, '^.*[^\s]{50,}.*$'), + QueryPredicate.of('dc.description.*', QueryPredicate.MATCHES, '^.*(\\S){50,}.*$'), ]), PresetQuery.of('q12', 'admin.reports.items.preset.hasXmlEntityInMetadata', [ QueryPredicate.of('*', QueryPredicate.MATCHES, '^.*&#.*$'), From 8444ea9ea5bfb552421a5bf20aaa232f990e446b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Tue, 11 Mar 2025 17:08:10 -0400 Subject: [PATCH 25/33] Updated Angular control flow syntax --- .../filtered-items-export-csv.component.html | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.html b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.html index f5c8dc13f38..a8f5463ce18 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.html +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.html @@ -1,7 +1,8 @@ - \ No newline at end of file + +} \ No newline at end of file From 1817f42be8ec0c26071d3a505bc6e3d0788fbac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Wed, 12 Mar 2025 13:28:31 -0400 Subject: [PATCH 26/33] Improved collection parameter handling --- .../filtered-items-export-csv.component.ts | 3 ++- .../admin-reports/filtered-items/option-vo.model.ts | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts index 4c3709afc0f..51f9f7ceb4f 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts @@ -30,6 +30,7 @@ import { Process } from '../../../../process-page/processes/process.model'; import { hasValue } from '../../../../shared/empty.util'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { FiltersComponent } from '../../filters-section/filters-section.component'; +import { OptionVO } from '../option-vo.model'; import { QueryPredicate } from '../query-predicate.model'; @Component({ @@ -88,7 +89,7 @@ export class FilteredItemsExportCsvComponent implements OnInit { const colls = this.reportParams.value.collections || []; for (let i = 0; i < colls.length; i++) { if (colls[i]) { - parameters.push({ name: '-c', value: colls[i] }); + parameters.push({ name: '-c', value: OptionVO.toString(colls[i]) }); } } diff --git a/src/app/admin/admin-reports/filtered-items/option-vo.model.ts b/src/app/admin/admin-reports/filtered-items/option-vo.model.ts index b26a42a8d8c..067e4788354 100644 --- a/src/app/admin/admin-reports/filtered-items/option-vo.model.ts +++ b/src/app/admin/admin-reports/filtered-items/option-vo.model.ts @@ -46,6 +46,16 @@ export class OptionVO { subscriber.next(value); subscriber.complete(); }); + } + static toString(obj: any): string { + if (obj) { + if (obj instanceof OptionVO && obj.id) { + return obj.id; + } + return obj as string; + } + return ""; } + } From 172e6f3e8dce51fa2076dda771337340cc87075e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Wed, 12 Mar 2025 13:35:46 -0400 Subject: [PATCH 27/33] Fixed styling error --- src/app/admin/admin-reports/filtered-items/option-vo.model.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/admin/admin-reports/filtered-items/option-vo.model.ts b/src/app/admin/admin-reports/filtered-items/option-vo.model.ts index 067e4788354..a598fb9a3b6 100644 --- a/src/app/admin/admin-reports/filtered-items/option-vo.model.ts +++ b/src/app/admin/admin-reports/filtered-items/option-vo.model.ts @@ -55,7 +55,7 @@ export class OptionVO { } return obj as string; } - return ""; + return ''; } } From a2a7a130da05d7cf74b29ccc0f67908ebfdaadbc Mon Sep 17 00:00:00 2001 From: jeffmorin Date: Wed, 12 Mar 2025 14:26:54 -0400 Subject: [PATCH 28/33] Updated config.yml to match the central dspace-angular repo --- config/config.yml | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/config/config.yml b/config/config.yml index dd7645fc1e5..109db60ca92 100644 --- a/config/config.yml +++ b/config/config.yml @@ -3,44 +3,3 @@ rest: host: sandbox.dspace.org port: 443 nameSpace: /server - -form: - recaptcha: - v2SiteKey: 6Leado4hAAAAAA5sjp8htg4b9iFmjC4E4XBH4VrB - v3SiteKey: 6Le0eI4hAAAAAJEEmz-fOOSl6DTqzK35EEov-Ivn - -themes: - - name: dspace - headTags: - - tagName: link - attributes: - rel: icon - href: assets/dspace/images/favicons/favicon.ico - sizes: any - - tagName: link - attributes: - rel: icon - href: assets/dspace/images/favicons/favicon.svg - type: image/svg+xml - - tagName: link - attributes: - rel: apple-touch-icon - href: assets/dspace/images/favicons/apple-touch-icon.png - - tagName: link - attributes: - rel: manifest - href: assets/dspace/images/favicons/manifest.webmanifest - -item: - showAccessStatuses: true - -languages: - - code: fr - label: Français - active: true - - code: en - label: English - active: true - -browseBy: - showThumbnails: false From b221ef3c6c9ccdeee646ef424d6ebbb5c9a10d4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Thu, 13 Mar 2025 11:26:02 -0400 Subject: [PATCH 29/33] Removed repeated content --- src/assets/i18n/fr.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/i18n/fr.json5 b/src/assets/i18n/fr.json5 index a7d0c72b4d0..a1e9979ae3e 100644 --- a/src/assets/i18n/fr.json5 +++ b/src/assets/i18n/fr.json5 @@ -8555,7 +8555,7 @@ "item.page.cc.license.disclaimer": "Sauf indication contraire, la licence de cet Item est décrite comme", //"browse.search-form.placeholder": "Search the repository", - "browse.search-form.placeholder": "Chercher dans le dépôt", //"metadata-export-filtered-items.tooltip": "Export report output as CSV", + "browse.search-form.placeholder": "Chercher dans le dépôt", //"metadata-export-filtered-items.tooltip": "Export report output as CSV", "metadata-export-filtered-items.tooltip": "Exporter le rapport en CSV", From 6499913b844beb2ab971160aa548d59b6a60fbf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Thu, 13 Mar 2025 12:26:18 -0400 Subject: [PATCH 30/33] Cleaned up a now useless import --- .../filtered-items-export-csv.component.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts index 51f9f7ceb4f..c673d89f78d 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts @@ -1,7 +1,4 @@ -import { - AsyncPipe, - NgIf, -} from '@angular/common'; +import { AsyncPipe } from '@angular/common'; import { Component, Input, @@ -38,7 +35,7 @@ import { QueryPredicate } from '../query-predicate.model'; styleUrls: ['./filtered-items-export-csv.component.scss'], templateUrl: './filtered-items-export-csv.component.html', standalone: true, - imports: [NgIf, NgbTooltipModule, AsyncPipe, TranslateModule], + imports: [NgbTooltipModule, AsyncPipe, TranslateModule], }) /** * Display a button to export the MetadataQuery (aka Filtered Items) Report results as csv From 4af63103a749ea4ab602e4b1c44d05d93778b76e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Thu, 20 Mar 2025 10:44:12 -0400 Subject: [PATCH 31/33] Fixed collections loading and added warning message about CSV export --- .../filtered-items-export-csv.component.ts | 19 ++++++++++++++++-- .../filtered-items.component.html | 19 +++++++++++++----- .../filtered-items.component.scss | 6 ++++++ .../filtered-items.component.ts | 20 +++++++++++++++++++ src/assets/i18n/en.json5 | 2 ++ src/assets/i18n/fr.json5 | 2 ++ 6 files changed, 61 insertions(+), 7 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts index c673d89f78d..592a14387f4 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts @@ -66,7 +66,7 @@ export class FilteredItemsExportCsvComponent implements OnInit { } ngOnInit(): void { - const scriptExists$ = this.scriptDataService.findById('metadata-export-filtered-items-report').pipe( + /*const scriptExists$ = this.scriptDataService.findById('metadata-export-filtered-items-report').pipe( getFirstCompletedRemoteData(), map((rd) => rd.isSuccess && hasValue(rd.payload)), ); @@ -75,7 +75,8 @@ export class FilteredItemsExportCsvComponent implements OnInit { this.shouldShowButton$ = observableCombineLatest([scriptExists$, isAuthorized$]).pipe( map(([scriptExists, isAuthorized]: [boolean, boolean]) => scriptExists && isAuthorized), - ); + );*/ + this.shouldShowButton$ = FilteredItemsExportCsvComponent.csvExportEnabled(this.scriptDataService, this.authorizationDataService); } /** @@ -115,4 +116,18 @@ export class FilteredItemsExportCsvComponent implements OnInit { } }); } + + static csvExportEnabled(scriptDataService: ScriptDataService, authorizationDataService: AuthorizationDataService): Observable { + const scriptExists$ = scriptDataService.findById('metadata-export-filtered-items-report').pipe( + getFirstCompletedRemoteData(), + map((rd) => rd.isSuccess && hasValue(rd.payload)), + ); + + const isAuthorized$ = authorizationDataService.isAuthorized(FeatureID.AdministratorOf); + + return observableCombineLatest([scriptExists$, isAuthorized$]).pipe( + map(([scriptExists, isAuthorized]: [boolean, boolean]) => scriptExists && isAuthorized), + ); + } + } diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items.component.html b/src/app/admin/admin-reports/filtered-items/filtered-items.component.html index dbe07b184c8..dd3f45c216d 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items.component.html +++ b/src/app/admin/admin-reports/filtered-items/filtered-items.component.html @@ -11,11 +11,16 @@

{{'admin.reports.items.head' | transl {{'admin.reports.items.section.collectionSelector' | translate}} - + @if (loadingCollections$ | async) { + + } + @if ((loadingCollections$ | async) !== true) { + + }
@@ -132,6 +137,10 @@

{{'admin.reports.items.head' | transl

+ @if (csvExportEnabled$ | async) { + +
{{ 'metadata-export-filtered-items.columns.warning' | translate }}
+ }
diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items.component.scss b/src/app/admin/admin-reports/filtered-items/filtered-items.component.scss index 73ce5275e5b..a1dbba77f40 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items.component.scss +++ b/src/app/admin/admin-reports/filtered-items/filtered-items.component.scss @@ -1,3 +1,9 @@ .num { text-align: center; } + +.warning { + color: red; + font-style: italic; + text-align: center; +} \ No newline at end of file diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts index affbe46a12a..1daea4168ec 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items.component.ts @@ -20,13 +20,16 @@ import { TranslateService, } from '@ngx-translate/core'; import { + BehaviorSubject, map, Observable, } from 'rxjs'; import { CollectionDataService } from 'src/app/core/data/collection-data.service'; import { CommunityDataService } from 'src/app/core/data/community-data.service'; +import { AuthorizationDataService } from 'src/app/core/data/feature-authorization/authorization-data.service'; import { MetadataFieldDataService } from 'src/app/core/data/metadata-field-data.service'; import { MetadataSchemaDataService } from 'src/app/core/data/metadata-schema-data.service'; +import { ScriptDataService } from 'src/app/core/data/processes/script-data.service'; 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'; @@ -36,6 +39,7 @@ import { Collection } from 'src/app/core/shared/collection.model'; import { Community } from 'src/app/core/shared/community.model'; import { getFirstSucceededRemoteListPayload } from 'src/app/core/shared/operators'; import { isEmpty } from 'src/app/shared/empty.util'; +import { ThemedLoadingComponent } from 'src/app/shared/loading/themed-loading.component'; import { environment } from 'src/environments/environment'; import { BtnDisabledDirective } from '../../../shared/btn-disabled.directive'; @@ -64,12 +68,18 @@ import { QueryPredicate } from './query-predicate.model'; FiltersComponent, BtnDisabledDirective, FilteredItemsExportCsvComponent, + ThemedLoadingComponent, ], standalone: true, }) export class FilteredItemsComponent implements OnInit { collections: OptionVO[]; + /** + * A Boolean representing if loading the list of collections is pending + */ + loadingCollections$: BehaviorSubject = new BehaviorSubject(false); + presetQueries: PresetQuery[]; metadataFields: OptionVO[]; metadataFieldsWithAny: OptionVO[]; @@ -81,6 +91,10 @@ export class FilteredItemsComponent implements OnInit { results: FilteredItems = new FilteredItems(); results$: Observable; @ViewChild('acc') accordionComponent: NgbAccordion; + /** + * Observable used to determine whether CSV export is enabled + */ + csvExportEnabled$: Observable; constructor( private communityService: CommunityDataService, @@ -88,6 +102,8 @@ export class FilteredItemsComponent implements OnInit { private metadataSchemaService: MetadataSchemaDataService, private metadataFieldService: MetadataFieldDataService, private translateService: TranslateService, + private scriptDataService: ScriptDataService, + private authorizationDataService: AuthorizationDataService, private formBuilder: FormBuilder, private restService: DspaceRestService) {} @@ -102,6 +118,8 @@ export class FilteredItemsComponent implements OnInit { new QueryPredicate().toFormGroup(this.formBuilder), ]; + this.csvExportEnabled$ = FilteredItemsExportCsvComponent.csvExportEnabled(this.scriptDataService, this.authorizationDataService); + this.queryForm = this.formBuilder.group({ collections: this.formBuilder.control([''], []), presetQuery: this.formBuilder.control('new', []), @@ -113,6 +131,7 @@ export class FilteredItemsComponent implements OnInit { } loadCollections(): void { + this.loadingCollections$.next(true); this.collections = []; const wholeRepo$ = this.translateService.stream('admin.reports.items.wholeRepo'); this.collections.push(OptionVO.collectionLoc('', wholeRepo$)); @@ -134,6 +153,7 @@ export class FilteredItemsComponent implements OnInit { const collVO = OptionVO.collection(collection.uuid, '–' + collection.name); this.collections.push(collVO); }); + this.loadingCollections$.next(false); }, ); }); diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index d4c2ee7eeee..2ff3b1c41d8 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -6825,4 +6825,6 @@ "metadata-export-filtered-items.submit.success": "CSV export succeeded.", "metadata-export-filtered-items.submit.error": "CSV export failed.", + + "metadata-export-filtered-items.columns.warning": "CSV export automatically includes all relevant fields, so selections in this list are not taken into account.", } diff --git a/src/assets/i18n/fr.json5 b/src/assets/i18n/fr.json5 index 84fa90b10c9..9e8866c47d7 100644 --- a/src/assets/i18n/fr.json5 +++ b/src/assets/i18n/fr.json5 @@ -8593,4 +8593,6 @@ //"metadata-export-filtered-items.submit.error": "CSV export failed.", "metadata-export-filtered-items.submit.error": "L'exportation CSV n'a pas fonctionné.", + //"metadata-export-filtered-items.columns.warning": "CSV export automatically includes all relevant fields, so selections in this list are not taken into account.", + "metadata-export-filtered-items.columns.warning": "L'exportation CSV inclut automatiquement tous les champs pertinents, sans égard au contenu sélectionné de cette liste.", } From ed7ebd239e7c07ff132154c7a7b8a7f6042c9139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Thu, 20 Mar 2025 10:49:48 -0400 Subject: [PATCH 32/33] Fixed styling error --- .../filtered-items-export-csv.component.ts | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts index 592a14387f4..1185b1ca745 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts @@ -65,6 +65,19 @@ export class FilteredItemsExportCsvComponent implements OnInit { ) { } + static csvExportEnabled(scriptDataService: ScriptDataService, authorizationDataService: AuthorizationDataService): Observable { + const scriptExists$ = scriptDataService.findById('metadata-export-filtered-items-report').pipe( + getFirstCompletedRemoteData(), + map((rd) => rd.isSuccess && hasValue(rd.payload)), + ); + + const isAuthorized$ = authorizationDataService.isAuthorized(FeatureID.AdministratorOf); + + return observableCombineLatest([scriptExists$, isAuthorized$]).pipe( + map(([scriptExists, isAuthorized]: [boolean, boolean]) => scriptExists && isAuthorized), + ); + } + ngOnInit(): void { /*const scriptExists$ = this.scriptDataService.findById('metadata-export-filtered-items-report').pipe( getFirstCompletedRemoteData(), @@ -117,17 +130,4 @@ export class FilteredItemsExportCsvComponent implements OnInit { }); } - static csvExportEnabled(scriptDataService: ScriptDataService, authorizationDataService: AuthorizationDataService): Observable { - const scriptExists$ = scriptDataService.findById('metadata-export-filtered-items-report').pipe( - getFirstCompletedRemoteData(), - map((rd) => rd.isSuccess && hasValue(rd.payload)), - ); - - const isAuthorized$ = authorizationDataService.isAuthorized(FeatureID.AdministratorOf); - - return observableCombineLatest([scriptExists$, isAuthorized$]).pipe( - map(([scriptExists, isAuthorized]: [boolean, boolean]) => scriptExists && isAuthorized), - ); - } - } From 1fcfcacaeb533a50f5aa2c633aa7a271eb6a419e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Morin?= Date: Thu, 20 Mar 2025 16:06:29 -0400 Subject: [PATCH 33/33] Forgot to clean up old code --- .../filtered-items-export-csv.component.ts | 10 ---------- .../filtered-items/filtered-items.component.scss | 1 + 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts index 1185b1ca745..50a0ca32b7d 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts +++ b/src/app/admin/admin-reports/filtered-items/filtered-items-export-csv/filtered-items-export-csv.component.ts @@ -79,16 +79,6 @@ export class FilteredItemsExportCsvComponent implements OnInit { } ngOnInit(): void { - /*const scriptExists$ = this.scriptDataService.findById('metadata-export-filtered-items-report').pipe( - getFirstCompletedRemoteData(), - map((rd) => rd.isSuccess && hasValue(rd.payload)), - ); - - const isAuthorized$ = this.authorizationDataService.isAuthorized(FeatureID.AdministratorOf); - - this.shouldShowButton$ = observableCombineLatest([scriptExists$, isAuthorized$]).pipe( - map(([scriptExists, isAuthorized]: [boolean, boolean]) => scriptExists && isAuthorized), - );*/ this.shouldShowButton$ = FilteredItemsExportCsvComponent.csvExportEnabled(this.scriptDataService, this.authorizationDataService); } diff --git a/src/app/admin/admin-reports/filtered-items/filtered-items.component.scss b/src/app/admin/admin-reports/filtered-items/filtered-items.component.scss index a1dbba77f40..15e8b54bc77 100644 --- a/src/app/admin/admin-reports/filtered-items/filtered-items.component.scss +++ b/src/app/admin/admin-reports/filtered-items/filtered-items.component.scss @@ -6,4 +6,5 @@ color: red; font-style: italic; text-align: center; + width: 100%; } \ No newline at end of file