From 193d7bbcaf9af43414b8482013c4d1ce54941007 Mon Sep 17 00:00:00 2001 From: Vlad0n20 Date: Wed, 6 May 2026 16:58:50 +0300 Subject: [PATCH] feat(ENG-9833): cleanup and delete dead code --- .../add-to-collection.component.html | 3 - .../add-to-collection.component.spec.ts | 10 - .../add-to-collection.component.ts | 48 +--- .../collection-metadata-step.component.html | 86 ++---- ...collection-metadata-step.component.spec.ts | 73 +---- .../collection-metadata-step.component.ts | 201 ++----------- .../collections-discover.component.html | 9 +- .../collections-discover.component.spec.ts | 192 +++---------- .../collections-discover.component.ts | 135 +-------- .../collections-filter-chips.component.html | 13 - .../collections-filter-chips.component.scss | 0 ...collections-filter-chips.component.spec.ts | 162 ----------- .../collections-filter-chips.component.ts | 95 ------ .../collections-filters.component.html | 26 -- .../collections-filters.component.scss | 11 - .../collections-filters.component.spec.ts | 131 --------- .../collections-filters.component.ts | 113 -------- .../collections-main-content.component.html | 86 ------ .../collections-main-content.component.scss | 19 -- ...collections-main-content.component.spec.ts | 130 --------- .../collections-main-content.component.ts | 76 ----- ...lections-search-result-card.component.html | 34 --- ...lections-search-result-card.component.scss | 29 -- ...tions-search-result-card.component.spec.ts | 157 ---------- ...ollections-search-result-card.component.ts | 31 -- .../collections-search-results.component.html | 31 -- .../collections-search-results.component.scss | 3 - ...llections-search-results.component.spec.ts | 74 ----- .../collections-search-results.component.ts | 42 --- .../constants/filter-names.const.ts | 12 - .../constants/filter-types.const.ts | 14 - .../features/collections/constants/index.ts | 4 - .../constants/query-params-keys.const.ts | 1 - .../constants/sort-options.const.ts | 7 - .../enums/collection-filter-type.enum.ts | 12 - src/app/features/collections/enums/index.ts | 1 - .../models/collection-filter-entry.model.ts | 6 - .../models/collections-query-params.model.ts | 6 - .../services/add-to-collection.service.ts | 10 - .../collections-query-sync.service.ts | 272 ------------------ .../features/collections/services/index.ts | 1 - .../add-to-collection.actions.ts | 6 - .../add-to-collection.state.ts | 10 +- .../metadata-collection-item.component.html | 10 - ...metadata-collection-item.component.spec.ts | 96 +------ .../metadata-collection-item.component.ts | 37 +-- .../metadata-collections.component.html | 1 - .../metadata-collections.component.spec.ts | 7 +- .../metadata-collections.component.ts | 1 - .../features/metadata/metadata.component.html | 1 - .../features/metadata/metadata.component.ts | 2 - ...ection-moderation-submissions.component.ts | 21 +- .../collection-submission-item.component.html | 14 +- ...llection-submission-item.component.spec.ts | 33 --- .../collection-submission-item.component.ts | 13 - .../overview-collections.component.html | 43 +-- .../overview-collections.component.spec.ts | 50 +--- .../overview-collections.component.ts | 36 +-- .../helpers/convert-to-snake-case.helper.ts | 10 - .../mappers/collections/collections.mapper.ts | 93 +----- .../collection-submission-payload.model.ts | 1 - .../collections/collections-filters.model.ts | 12 - .../collections/collections-json-api.model.ts | 50 ---- .../models/collections/collections.model.ts | 34 --- src/app/shared/models/environment.model.ts | 1 - .../shared/services/collections.service.ts | 93 +----- .../stores/collections/collections.actions.ts | 120 -------- .../stores/collections/collections.model.ts | 42 --- .../collections/collections.selectors.ts | 57 ---- .../stores/collections/collections.state.ts | 240 ---------------- src/assets/config/template.json | 3 +- src/assets/i18n/en.json | 55 ---- .../data/collections/cedar-metadata.mock.ts | 10 - .../collection-submissions.mock.ts | 20 -- src/testing/mocks/collections-filters.mock.ts | 51 ---- .../mocks/collections-submissions.mock.ts | 50 +--- src/testing/mocks/submission.mock.ts | 10 - .../providers/environment.token.mock.ts | 1 - 78 files changed, 136 insertions(+), 3564 deletions(-) delete mode 100644 src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.html delete mode 100644 src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.scss delete mode 100644 src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.spec.ts delete mode 100644 src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.ts delete mode 100644 src/app/features/collections/components/collections-filters/collections-filters.component.html delete mode 100644 src/app/features/collections/components/collections-filters/collections-filters.component.scss delete mode 100644 src/app/features/collections/components/collections-filters/collections-filters.component.spec.ts delete mode 100644 src/app/features/collections/components/collections-filters/collections-filters.component.ts delete mode 100644 src/app/features/collections/components/collections-main-content/collections-main-content.component.html delete mode 100644 src/app/features/collections/components/collections-main-content/collections-main-content.component.scss delete mode 100644 src/app/features/collections/components/collections-main-content/collections-main-content.component.spec.ts delete mode 100644 src/app/features/collections/components/collections-main-content/collections-main-content.component.ts delete mode 100644 src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.html delete mode 100644 src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.scss delete mode 100644 src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.spec.ts delete mode 100644 src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.ts delete mode 100644 src/app/features/collections/components/collections-search-results/collections-search-results.component.html delete mode 100644 src/app/features/collections/components/collections-search-results/collections-search-results.component.scss delete mode 100644 src/app/features/collections/components/collections-search-results/collections-search-results.component.spec.ts delete mode 100644 src/app/features/collections/components/collections-search-results/collections-search-results.component.ts delete mode 100644 src/app/features/collections/constants/filter-names.const.ts delete mode 100644 src/app/features/collections/constants/filter-types.const.ts delete mode 100644 src/app/features/collections/constants/index.ts delete mode 100644 src/app/features/collections/constants/query-params-keys.const.ts delete mode 100644 src/app/features/collections/constants/sort-options.const.ts delete mode 100644 src/app/features/collections/enums/collection-filter-type.enum.ts delete mode 100644 src/app/features/collections/models/collection-filter-entry.model.ts delete mode 100644 src/app/features/collections/models/collections-query-params.model.ts delete mode 100644 src/app/features/collections/services/collections-query-sync.service.ts delete mode 100644 src/app/shared/helpers/convert-to-snake-case.helper.ts delete mode 100644 src/app/shared/models/collections/collections-filters.model.ts delete mode 100644 src/testing/mocks/collections-filters.mock.ts diff --git a/src/app/features/collections/components/add-to-collection/add-to-collection.component.html b/src/app/features/collections/components/add-to-collection/add-to-collection.component.html index d76299fba..15486dc58 100644 --- a/src/app/features/collections/components/add-to-collection/add-to-collection.component.html +++ b/src/app/features/collections/components/add-to-collection/add-to-collection.component.html @@ -47,11 +47,8 @@

{{ collectionProvider()? [stepperActiveValue]="stepperActiveValue()" [targetStepValue]="AddToCollectionSteps.CollectionMetadata" [isDisabled]="isCollectionMetadataDisabled()" - [primaryCollectionId]="primaryCollectionId()" - [isCedarMode]="isCedarMode()" [cedarTemplate]="requiredMetadataTemplate()" [existingCedarRecord]="existingCedarRecord()" - (metadataSaved)="handleCollectionMetadataSaved($event)" (cedarDataSaved)="handleCedarDataSaved($event)" (stepChange)="handleChangeStep($event)" /> diff --git a/src/app/features/collections/components/add-to-collection/add-to-collection.component.spec.ts b/src/app/features/collections/components/add-to-collection/add-to-collection.component.spec.ts index b7c9645b7..06e373db4 100644 --- a/src/app/features/collections/components/add-to-collection/add-to-collection.component.spec.ts +++ b/src/app/features/collections/components/add-to-collection/add-to-collection.component.spec.ts @@ -1,7 +1,6 @@ import { MockComponents, MockProvider } from 'ng-mocks'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { FormGroup } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { UserSelectors } from '@core/store/user'; @@ -118,15 +117,6 @@ describe('AddToCollectionComponent', () => { expect(component.projectContributorsSaved()).toBe(true); }); - it('should handle collection metadata saved', () => { - const mockForm = new FormGroup({}); - component.handleCollectionMetadataSaved(mockForm); - - expect(component.collectionMetadataForm).toBe(mockForm); - expect(component.collectionMetadataSaved()).toBe(true); - expect(component.stepperActiveValue()).toBe(AddToCollectionSteps.Complete); - }); - it('should handle cedar data saved', () => { const mockCedarData: CedarRecordDataBinding = { data: {} as CedarRecordDataBinding['data'], diff --git a/src/app/features/collections/components/add-to-collection/add-to-collection.component.ts b/src/app/features/collections/components/add-to-collection/add-to-collection.component.ts index c90a8cee2..c7533e3bf 100644 --- a/src/app/features/collections/components/add-to-collection/add-to-collection.component.ts +++ b/src/app/features/collections/components/add-to-collection/add-to-collection.component.ts @@ -20,10 +20,8 @@ import { signal, } from '@angular/core'; import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; -import { FormGroup } from '@angular/forms'; import { ActivatedRoute, Router, RouterLink } from '@angular/router'; -import { ENVIRONMENT } from '@core/provider/environment.provider'; import { UserSelectors } from '@core/store/user'; import { CedarMetadataRecordData, CedarRecordDataBinding } from '@osf/features/metadata/models'; import { @@ -52,7 +50,6 @@ import { ClearAddToCollectionState, GetCurrentCollectionSubmission, RemoveCollectionSubmission, - UpdateCollectionSubmission, } from '../../store/add-to-collection'; import { AddToCollectionConfirmationDialogComponent } from './add-to-collection-confirmation-dialog/add-to-collection-confirmation-dialog.component'; @@ -90,7 +87,6 @@ export class AddToCollectionComponent implements CanDeactivateComponent { private readonly headerStyleHelper = inject(HeaderStyleService); private readonly platformId = inject(PLATFORM_ID); private readonly isBrowser = isPlatformBrowser(this.platformId); - private readonly environment = inject(ENVIRONMENT); readonly selectedProjectId = toSignal( this.route.params.pipe(map((params) => params['id'])) ?? of(null) @@ -98,8 +94,6 @@ export class AddToCollectionComponent implements CanDeactivateComponent { readonly AddToCollectionSteps = AddToCollectionSteps; - collectionMetadataForm = new FormGroup({}); - isProviderLoading = select(CollectionsSelectors.getCollectionProviderLoading); collectionProvider = select(CollectionsSelectors.getCollectionProvider); requiredMetadataTemplate = select(CollectionsSelectors.getRequiredMetadataTemplate); @@ -123,7 +117,6 @@ export class AddToCollectionComponent implements CanDeactivateComponent { isCollectionMetadataDisabled = computed( () => !this.selectedProject() || !this.projectMetadataSaved() || !this.projectContributorsSaved() ); - isCedarMode = computed(() => this.environment.collectionSubmissionWithCedar && !!this.requiredMetadataTemplate()); existingCedarRecord = computed(() => { const records = this.cedarRecords(); const templateId = this.requiredMetadataTemplate()?.id; @@ -134,7 +127,6 @@ export class AddToCollectionComponent implements CanDeactivateComponent { readonly actions = createDispatchMap({ getCollectionProvider: GetCollectionProvider, clearAddToCollectionState: ClearAddToCollectionState, - updateCollectionSubmission: UpdateCollectionSubmission, deleteCollectionSubmission: RemoveCollectionSubmission, setSelectedProject: SetSelectedProject, getCurrentCollectionSubmission: GetCurrentCollectionSubmission, @@ -191,12 +183,6 @@ export class AddToCollectionComponent implements CanDeactivateComponent { this.projectContributorsSaved.set(true); } - handleCollectionMetadataSaved(form: FormGroup): void { - this.collectionMetadataForm = form; - this.collectionMetadataSaved.set(true); - this.stepperActiveValue.set(AddToCollectionSteps.Complete); - } - handleCedarDataSaved(data: CedarRecordDataBinding): void { this.pendingCedarData.set(data); this.collectionMetadataSaved.set(true); @@ -207,19 +193,14 @@ export class AddToCollectionComponent implements CanDeactivateComponent { const payload = { collectionId: this.primaryCollectionId() || '', projectId: this.selectedProject()?.id || '', - collectionMetadata: this.isCedarMode() ? {} : this.collectionMetadataForm.value || {}, userId: this.currentUser()?.id || '', }; - const isEditMode = this.isEditMode(); - - if (isEditMode) { + if (this.isEditMode()) { this.loaderService.show(); - this.actions - .updateCollectionSubmission(payload) + this.saveCedarRecordIfNeeded() .pipe( - switchMap(() => this.saveCedarRecordIfNeeded()), finalize(() => this.loaderService.hide()), takeUntilDestroyed(this.destroyRef) ) @@ -234,15 +215,17 @@ export class AddToCollectionComponent implements CanDeactivateComponent { }, }); } else { - this.customDialogService - .open(AddToCollectionConfirmationDialogComponent, { - header: 'collections.addToCollection.confirmationDialogHeader', - width: '500px', - data: { payload, project: this.selectedProject() }, - }) - .onClose.pipe( - filter((res) => !!res), - switchMap(() => this.saveCedarRecordIfNeeded()), + this.saveCedarRecordIfNeeded() + .pipe( + switchMap(() => + this.customDialogService + .open(AddToCollectionConfirmationDialogComponent, { + header: 'collections.addToCollection.confirmationDialogHeader', + width: '500px', + data: { payload, project: this.selectedProject() }, + }) + .onClose.pipe(filter((res) => !!res)) + ), takeUntilDestroyed(this.destroyRef) ) .subscribe({ @@ -294,8 +277,6 @@ export class AddToCollectionComponent implements CanDeactivateComponent { } private saveCedarRecordIfNeeded(): Observable { - if (!this.isCedarMode()) return of(null); - const cedarData = this.pendingCedarData(); const projectId = this.selectedProject()?.id; const templateId = this.requiredMetadataTemplate()?.id; @@ -348,8 +329,7 @@ export class AddToCollectionComponent implements CanDeactivateComponent { effect(() => { const projectId = this.selectedProjectId(); - const isCedar = this.isCedarMode(); - if (isCedar && projectId) { + if (projectId) { this.actions.getCedarRecords(projectId, ResourceType.Project); } }); diff --git a/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.html b/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.html index 0b0cd6498..93d39a9d5 100644 --- a/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.html +++ b/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.html @@ -10,27 +10,13 @@

{{ 'collections.addToCollection.collectionMetadata' | translate }}

@if (!isDisabled() && stepperActiveValue() !== targetStepValue()) { - @if (collectionMetadataSaved()) { - @if (isCedarMode()) { - @if (cedarTemplate()) { - - } - } @else { - @for (filterEntry of availableFilterEntries(); track filterEntry.key) { -
-

{{ filterEntry.labelKey | translate }}

- -

- {{ collectionMetadataForm().get(filterEntry.key)?.value }} -

-
- } - } + @if (collectionMetadataSaved() && cedarTemplate()) { + } {{ 'collections.addToCollection.collectionMetadata' | translate }}

- @if (isCedarMode()) { - @if (cedarTemplate()) { -
- -
- -
- - -
- } @else { -

{{ 'collections.addToCollection.cedarFormNotAvailable' | translate }}

- } - } @else { -
- @for (filterEntry of availableFilterEntries(); track filterEntry.key) { -
- - -
- } -
+ @if (cedarTemplate()) { +
+ +
{{ 'collections.addToCollection.collectionMetadata' | translate }} [label]="'common.buttons.discardChanges' | translate" (onClick)="handleDiscardChanges()" /> - +
+ } @else { +

{{ 'collections.addToCollection.cedarFormNotAvailable' | translate }}

}
diff --git a/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.spec.ts b/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.spec.ts index f6dc67b64..f185b47ae 100644 --- a/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.spec.ts +++ b/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.spec.ts @@ -3,12 +3,8 @@ import { MockComponents } from 'ng-mocks'; import { Step, StepItem, StepPanel } from 'primeng/stepper'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { AddToCollectionSteps } from '@osf/features/collections/enums'; -import { AddToCollectionSelectors } from '@osf/features/collections/store/add-to-collection'; import { CedarMetadataDataTemplateJsonApi, CedarMetadataRecordData } from '@osf/features/metadata/models'; -import { CollectionsSelectors } from '@shared/stores/collections'; import { MOCK_CEDAR_TEMPLATE } from '@testing/data/collections/cedar-metadata.mock'; import { provideOSFCore } from '@testing/osf.testing.provider'; @@ -20,20 +16,10 @@ describe('CollectionMetadataStepComponent', () => { let component: CollectionMetadataStepComponent; let fixture: ComponentFixture; - function setup(isCedarMode = false, cedarTemplate: CedarMetadataDataTemplateJsonApi | null = null) { + function setup(cedarTemplate: CedarMetadataDataTemplateJsonApi | null = null) { TestBed.configureTestingModule({ imports: [CollectionMetadataStepComponent, MockComponents(StepPanel, Step, StepItem)], - providers: [ - provideOSFCore(), - provideMockStore({ - signals: [ - { selector: CollectionsSelectors.getCollectionProvider, value: null }, - { selector: CollectionsSelectors.getCollectionProviderLoading, value: false }, - { selector: CollectionsSelectors.getAllFiltersOptions, value: {} }, - { selector: AddToCollectionSelectors.getCurrentCollectionSubmission, value: null }, - ], - }), - ], + providers: [provideOSFCore(), provideMockStore({ signals: [] })], }); fixture = TestBed.createComponent(CollectionMetadataStepComponent); @@ -42,8 +28,6 @@ describe('CollectionMetadataStepComponent', () => { fixture.componentRef.setInput('stepperActiveValue', 0); fixture.componentRef.setInput('targetStepValue', 1); fixture.componentRef.setInput('isDisabled', false); - fixture.componentRef.setInput('primaryCollectionId', 'test-collection-id'); - fixture.componentRef.setInput('isCedarMode', isCedarMode); if (cedarTemplate) { fixture.componentRef.setInput('cedarTemplate', cedarTemplate); } @@ -63,33 +47,6 @@ describe('CollectionMetadataStepComponent', () => { expect(component.stepperActiveValue()).toBe(0); expect(component.targetStepValue()).toBe(1); expect(component.isDisabled()).toBe(false); - expect(component.isCedarMode()).toBe(false); - }); - - it('should handle save metadata in filter mode', () => { - const mockForm = new FormGroup({}); - component.collectionMetadataForm.set(mockForm); - - const emitSpy = vi.spyOn(component.metadataSaved, 'emit'); - const stepChangeSpy = vi.spyOn(component.stepChange, 'emit'); - - component.handleSaveMetadata(); - - expect(emitSpy).toHaveBeenCalledWith(mockForm); - expect(stepChangeSpy).toHaveBeenCalledWith(AddToCollectionSteps.Complete); - expect(component.collectionMetadataSaved()).toBe(true); - }); - - it('should handle form validation', () => { - const validForm = new FormGroup({ - title: new FormControl('Test Collection', [Validators.required]), - }); - const invalidForm = new FormGroup({ - title: new FormControl('', [Validators.required]), - }); - - expect(validForm.valid).toBe(true); - expect(invalidForm.valid).toBe(false); }); it('should handle step navigation', () => { @@ -100,21 +57,6 @@ describe('CollectionMetadataStepComponent', () => { expect(navigateSpy).toHaveBeenCalledWith(component.targetStepValue()); }); - it('should handle discard changes in filter mode', () => { - const mockForm = new FormGroup({}); - component.collectionMetadataForm.set(mockForm); - component.collectionMetadataSaved.set(true); - - component.handleDiscardChanges(); - - expect(component.collectionMetadataSaved()).toBe(false); - }); - - it('should have collection metadata form', () => { - expect(component.collectionMetadataForm()).toBeDefined(); - expect(component.collectionMetadataSaved()).toBe(false); - }); - it('should handle different input values', () => { fixture.componentRef.setInput('stepperActiveValue', 2); fixture.componentRef.setInput('targetStepValue', 3); @@ -128,15 +70,14 @@ describe('CollectionMetadataStepComponent', () => { describe('CEDAR mode', () => { beforeEach(() => { - setup(true, MOCK_CEDAR_TEMPLATE); + setup(MOCK_CEDAR_TEMPLATE); }); - it('should initialize in CEDAR mode', () => { - expect(component.isCedarMode()).toBe(true); + it('should accept cedar template', () => { expect(component.cedarTemplate()).toEqual(MOCK_CEDAR_TEMPLATE); }); - it('should handle discard changes in CEDAR mode', () => { + it('should handle discard changes', () => { component.cedarFormData.set({ field: 'value' }); component.collectionMetadataSaved.set(true); @@ -146,7 +87,7 @@ describe('CollectionMetadataStepComponent', () => { expect(component.cedarFormData()).toEqual({}); }); - it('should handle discard changes with existing record in CEDAR mode', () => { + it('should handle discard changes with existing record', () => { const existingRecord: CedarMetadataRecordData = { attributes: { metadata: { field: 'original' } as unknown as CedarMetadataRecordData['attributes']['metadata'], @@ -183,7 +124,7 @@ describe('CollectionMetadataStepComponent', () => { expect(component.cedarFormData()).toEqual({ field: 'existing' }); }); - it('should emit cedarDataSaved when handleSaveCedarMetadata is called without editor', () => { + it('should not emit cedarDataSaved without editor', () => { const cedarDataSavedSpy = vi.spyOn(component.cedarDataSaved, 'emit'); const stepChangeSpy = vi.spyOn(component.stepChange, 'emit'); diff --git a/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.ts b/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.ts index b4fe45f64..316d188c8 100644 --- a/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.ts +++ b/src/app/features/collections/components/add-to-collection/collection-metadata-step/collection-metadata-step.component.ts @@ -1,16 +1,12 @@ -import { createDispatchMap, select } from '@ngxs/store'; - import { TranslatePipe } from '@ngx-translate/core'; import { Button } from 'primeng/button'; -import { Select } from 'primeng/select'; import { Step, StepItem, StepPanel } from 'primeng/stepper'; import { Tooltip } from 'primeng/tooltip'; import { ChangeDetectionStrategy, Component, - computed, CUSTOM_ELEMENTS_SCHEMA, effect, ElementRef, @@ -20,12 +16,8 @@ import { viewChild, ViewEncapsulation, } from '@angular/core'; -import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; -import { collectionFilterTypes } from '@osf/features/collections/constants'; -import { AddToCollectionSteps, CollectionFilterType } from '@osf/features/collections/enums'; -import { CollectionFilterEntry } from '@osf/features/collections/models/collection-filter-entry.model'; -import { AddToCollectionSelectors } from '@osf/features/collections/store/add-to-collection'; +import { AddToCollectionSteps } from '@osf/features/collections/enums'; import { CEDAR_CONFIG, CEDAR_VIEWER_CONFIG } from '@osf/features/metadata/constants'; import { CedarEditorElement, @@ -33,12 +25,10 @@ import { CedarMetadataRecordData, CedarRecordDataBinding, } from '@osf/features/metadata/models'; -import { CollectionSubmissionWithGuid } from '@osf/shared/models/collections/collections.model'; -import { CollectionsSelectors, GetCollectionDetails } from '@osf/shared/stores/collections'; @Component({ selector: 'osf-collection-metadata-step', - imports: [Button, TranslatePipe, Select, ReactiveFormsModule, Step, StepItem, StepPanel, Tooltip], + imports: [Button, TranslatePipe, Step, StepItem, StepPanel, Tooltip], templateUrl: './collection-metadata-step.component.html', styleUrl: './collection-metadata-step.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, @@ -46,38 +36,16 @@ import { CollectionsSelectors, GetCollectionDetails } from '@osf/shared/stores/c encapsulation: ViewEncapsulation.None, }) export class CollectionMetadataStepComponent { - private readonly filterTypes = collectionFilterTypes; - readonly collectionFilterOptions = select(CollectionsSelectors.getAllFiltersOptions); - readonly currentCollectionSubmission = select(AddToCollectionSelectors.getCurrentCollectionSubmission); - readonly availableFilterEntries = computed(() => { - const options = this.collectionFilterOptions(); - - return this.filterTypes - .map((key: string, index: number) => ({ - key, - value: index.toString(), - options: options[key as keyof typeof options] || [], - labelKey: `collections.filters.${key}.label`, - })) - .filter((entry: CollectionFilterEntry) => entry.options.length); - }); - stepperActiveValue = input.required(); targetStepValue = input.required(); isDisabled = input.required(); - primaryCollectionId = input(); - isCedarMode = input(false); cedarTemplate = input(null); existingCedarRecord = input(null); stepChange = output(); - metadataSaved = output(); cedarDataSaved = output(); - collectionMetadataForm = signal(new FormGroup({})); collectionMetadataSaved = signal(false); - originalFormValues = signal>({}); - formPopulatedFromSubmission = signal(false); cedarFormData = signal>({}); cedarConfig = CEDAR_CONFIG; @@ -86,10 +54,18 @@ export class CollectionMetadataStepComponent { cedarEditor = viewChild>('cedarEditor'); cedarViewer = viewChild>('cedarViewer'); - private readonly actions = createDispatchMap({ getCollectionDetails: GetCollectionDetails }); - constructor() { - this.setupEffects(); + effect(() => { + const record = this.existingCedarRecord(); + if (record?.attributes?.metadata) { + const metadata = record.attributes.metadata as Record; + this.cedarFormData.set(metadata); + const editor = this.cedarEditor()?.nativeElement; + if (editor) editor.instanceObject = metadata; + const viewer = this.cedarViewer()?.nativeElement; + if (viewer) viewer.instanceObject = metadata; + } + }); } handleEditStep() { @@ -97,39 +73,15 @@ export class CollectionMetadataStepComponent { } handleDiscardChanges() { - if (this.isCedarMode()) { - const record = this.existingCedarRecord(); - this.cedarFormData.set( - record?.attributes?.metadata ? (record.attributes.metadata as Record) : {} - ); - const editor = this.cedarEditor()?.nativeElement; - if (editor) { - editor.instanceObject = this.cedarFormData(); - } - this.collectionMetadataSaved.set(false); - return; - } - - const form = this.collectionMetadataForm(); - const originalValues = this.originalFormValues(); - - if (this.hasFormChanges(form, originalValues)) { - this.restoreFormValues(form, originalValues); + const record = this.existingCedarRecord(); + this.cedarFormData.set(record?.attributes?.metadata ? (record.attributes.metadata as Record) : {}); + const editor = this.cedarEditor()?.nativeElement; + if (editor) { + editor.instanceObject = this.cedarFormData(); } - this.collectionMetadataSaved.set(false); } - handleSaveMetadata() { - const form = this.collectionMetadataForm(); - - this.updateOriginalValues(form); - - this.collectionMetadataSaved.set(true); - this.metadataSaved.emit(form); - this.stepChange.emit(AddToCollectionSteps.Complete); - } - handleSaveCedarMetadata() { const editor = this.cedarEditor()?.nativeElement; const template = this.cedarTemplate(); @@ -162,121 +114,4 @@ export class CollectionMetadataStepComponent { } } } - - private buildCollectionMetadataForm() { - const filterEntries = this.availableFilterEntries(); - const formControls: Record = {}; - - filterEntries.forEach((entry: CollectionFilterEntry) => { - formControls[entry.key] = new FormControl('', [Validators.required]); - }); - - const newForm = new FormGroup(formControls); - this.collectionMetadataForm.set(newForm); - this.formPopulatedFromSubmission.set(false); - - const submission = this.currentCollectionSubmission(); - - if (submission) { - this.populateFormFromSubmission(submission.submission); - this.formPopulatedFromSubmission.set(true); - } else { - this.updateOriginalValues(newForm); - } - } - - private setupEffects(): void { - effect(() => { - const collectionId = this.primaryCollectionId(); - if (collectionId) { - this.actions.getCollectionDetails(collectionId); - } - }); - - effect(() => { - const record = this.existingCedarRecord(); - if (record?.attributes?.metadata) { - const metadata = record.attributes.metadata as Record; - this.cedarFormData.set(metadata); - const editor = this.cedarEditor()?.nativeElement; - if (editor) editor.instanceObject = metadata; - const viewer = this.cedarViewer()?.nativeElement; - if (viewer) viewer.instanceObject = metadata; - } - }); - - effect(() => { - const filterEntries = this.availableFilterEntries(); - if (filterEntries.length && !this.isCedarMode()) { - this.buildCollectionMetadataForm(); - } - }); - - effect(() => { - const submission = this.currentCollectionSubmission(); - const form = this.collectionMetadataForm(); - const filterEntries = this.availableFilterEntries(); - const alreadyPopulated = this.formPopulatedFromSubmission(); - - if ( - submission && - form.controls && - Object.keys(form.controls).length > 0 && - filterEntries.length > 0 && - !alreadyPopulated && - !this.isCedarMode() - ) { - this.populateFormFromSubmission(submission.submission); - this.formPopulatedFromSubmission.set(true); - } - }); - - effect(() => { - if (!this.collectionMetadataSaved() && this.stepperActiveValue() !== AddToCollectionSteps.CollectionMetadata) { - if (!this.isCedarMode()) { - this.collectionMetadataForm().reset(); - this.formPopulatedFromSubmission.set(false); - } - } - }); - } - - private hasFormChanges(form: FormGroup, originalValues: Record): boolean { - return Object.keys(originalValues).some((key) => { - const currentValue = form.get(key)?.value; - const originalValue = originalValues[key]; - return currentValue !== originalValue; - }); - } - - private restoreFormValues(form: FormGroup, originalValues: Record): void { - Object.keys(originalValues).forEach((key) => { - form.get(key)?.setValue(originalValues[key]); - }); - } - - private updateOriginalValues(form: FormGroup): void { - const currentValues: Record = {}; - Object.keys(form.controls).forEach((key) => { - currentValues[key] = form.get(key)?.value; - }); - this.originalFormValues.set(currentValues); - } - - private populateFormFromSubmission(submission: CollectionSubmissionWithGuid): void { - const form = this.collectionMetadataForm(); - if (!form || !form.controls) return; - - Object.values(CollectionFilterType).forEach((filterType) => { - const control = form.get(filterType); - if (control) { - const value = submission[filterType as keyof CollectionSubmissionWithGuid] as string; - if (value) { - control.setValue(value, { emitEvent: false }); - } - } - }); - - this.updateOriginalValues(form); - } } diff --git a/src/app/features/collections/components/collections-discover/collections-discover.component.html b/src/app/features/collections/components/collections-discover/collections-discover.component.html index d6971525e..ea5c5cd98 100644 --- a/src/app/features/collections/components/collections-discover/collections-discover.component.html +++ b/src/app/features/collections/components/collections-discover/collections-discover.component.html @@ -29,7 +29,6 @@

{{ collectionProvider()? [showHelpIcon]="true" [placeholder]="'collections.searchInput.placeholder' | translate" (helpClicked)="openHelpDialog()" - (triggerSearch)="onSearchTriggered($event)" /> @if (collectionProvider()?.description) {
@@ -37,12 +36,8 @@

{{ collectionProvider()?
- @if (useShareTroveSearch) { - @if (defaultSearchFiltersInitialized()) { - - } - } @else { - + @if (defaultSearchFiltersInitialized()) { + }
diff --git a/src/app/features/collections/components/collections-discover/collections-discover.component.spec.ts b/src/app/features/collections/components/collections-discover/collections-discover.component.spec.ts index 7be0470cd..85f20c949 100644 --- a/src/app/features/collections/components/collections-discover/collections-discover.component.spec.ts +++ b/src/app/features/collections/components/collections-discover/collections-discover.component.spec.ts @@ -4,7 +4,7 @@ import { MockComponents, MockProvider } from 'ng-mocks'; import { Mock } from 'vitest'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { ActivatedRoute } from '@angular/router'; import { ENVIRONMENT } from '@core/provider/environment.provider'; @@ -23,9 +23,6 @@ import { ActivatedRouteMockBuilder } from '@testing/providers/route-provider.moc import { provideMockStore } from '@testing/providers/store-provider.mock'; import { ToastServiceMock } from '@testing/providers/toast-provider.mock'; -import { CollectionsQuerySyncService } from '../../services'; -import { CollectionsMainContentComponent } from '../collections-main-content/collections-main-content.component'; - import { CollectionsDiscoverComponent } from './collections-discover.component'; const MOCK_COLLECTION_PROVIDER = { @@ -63,12 +60,11 @@ const MOCK_COLLECTION_PROVIDER_WITH_TEMPLATE = { }; interface SetupOptions { - collectionSubmissionWithCedar?: boolean; provider?: typeof MOCK_COLLECTION_PROVIDER | typeof MOCK_COLLECTION_PROVIDER_WITH_TEMPLATE; } function setup(options: SetupOptions = {}) { - const { collectionSubmissionWithCedar = false, provider = MOCK_COLLECTION_PROVIDER } = options; + const { provider = MOCK_COLLECTION_PROVIDER } = options; const toastServiceMock = ToastServiceMock.simple(); const mockCustomDialogService = CustomDialogServiceMockBuilder.create().build(); @@ -77,35 +73,21 @@ function setup(options: SetupOptions = {}) { TestBed.configureTestingModule({ imports: [ CollectionsDiscoverComponent, - ...MockComponents( - SearchInputComponent, - CollectionsMainContentComponent, - GlobalSearchComponent, - LoadingSpinnerComponent - ), + ...MockComponents(SearchInputComponent, GlobalSearchComponent, LoadingSpinnerComponent), ], providers: [ provideOSFCore(), - { provide: ENVIRONMENT, useValue: { apiDomainUrl: 'http://localhost:8000', collectionSubmissionWithCedar } }, + { provide: ENVIRONMENT, useValue: { apiDomainUrl: 'http://localhost:8000' } }, MockProvider(ToastService, toastServiceMock), MockProvider(CustomDialogService, mockCustomDialogService), MockProvider(ActivatedRoute, mockRoute), provideMockStore({ signals: [ { selector: CollectionsSelectors.getCollectionProvider, value: provider }, - { selector: CollectionsSelectors.getCollectionDetails, value: null }, - { selector: CollectionsSelectors.getAllSelectedFilters, value: {} }, - { selector: CollectionsSelectors.getSortBy, value: 'date' }, - { selector: CollectionsSelectors.getSearchText, value: '' }, - { selector: CollectionsSelectors.getPageNumber, value: '1' }, { selector: CollectionsSelectors.getCollectionProviderLoading, value: false }, ], }), ], - }).overrideComponent(CollectionsDiscoverComponent, { - set: { - providers: [MockProvider(CollectionsQuerySyncService)], - }, }); const fixture = TestBed.createComponent(CollectionsDiscoverComponent); @@ -117,145 +99,49 @@ function setup(options: SetupOptions = {}) { } describe('CollectionsDiscoverComponent', () => { - describe('legacy mode (collectionSubmissionWithCedar = false)', () => { - let component: CollectionsDiscoverComponent; - let fixture: ComponentFixture; - - beforeEach(() => { - ({ fixture, component } = setup()); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should set useShareTroveSearch to false', () => { - expect(component.useShareTroveSearch).toBe(false); - }); - - it('should initialize with default values', () => { - expect(component.providerId()).toBe('provider-1'); - expect(component.searchControl.value).toBe(''); - }); - - it('should have collection provider data', () => { - expect(component.collectionProvider()).toEqual(MOCK_COLLECTION_PROVIDER); - }); - - it('should have collection details as null', () => { - expect(component.collectionDetails()).toBeNull(); - }); - - it('should have selected filters', () => { - expect(component.selectedFilters()).toEqual({}); - }); - - it('should have sort by value', () => { - expect(component.sortBy()).toBe('date'); - }); - - it('should have search text', () => { - expect(component.searchText()).toBe(''); - }); - - it('should have page number', () => { - expect(component.pageNumber()).toBe('1'); - }); - - it('should have loading state', () => { - expect(component.isProviderLoading()).toBe(false); - }); - - it('should compute primary collection id', () => { - expect(component.primaryCollectionId()).toBe('collection-1'); - }); - - it('should handle search control value changes', () => { - component.searchControl.setValue('new search value'); - expect(component.searchControl.value).toBe('new search value'); - }); - - it('should not initialize default search filters', () => { - expect(component.defaultSearchFiltersInitialized()).toBe(false); - }); - - it('should render CollectionsMainContentComponent', () => { - const el = fixture.nativeElement as HTMLElement; - expect(el.querySelector('osf-collections-main-content')).toBeTruthy(); - expect(el.querySelector('osf-global-search')).toBeNull(); - }); - - it('should dispatch setSearchValue and setPageNumber on search triggered', () => { - const { component: localComponent, store: localStore } = setup(); - (localStore.dispatch as Mock).mockClear(); - - localComponent.onSearchTriggered('my query'); - - const calls = (localStore.dispatch as Mock).mock.calls.flat(); - expect(calls.some((c: unknown) => c instanceof SetDefaultFilterValue)).toBe(false); - }); + it('should create', () => { + const { component } = setup(); + expect(component).toBeTruthy(); }); - describe('shtrove mode (collectionSubmissionWithCedar = true)', () => { - it('should set useShareTroveSearch to true', () => { - const { component } = setup({ collectionSubmissionWithCedar: true }); - expect(component.useShareTroveSearch).toBe(true); - }); - - it('should initialize default search filters', () => { - const { component } = setup({ collectionSubmissionWithCedar: true }); - expect(component.defaultSearchFiltersInitialized()).toBe(true); - }); - - it('should dispatch SetDefaultFilterValue with collection IRI', () => { - const { store } = setup({ collectionSubmissionWithCedar: true }); - const dispatched = (store.dispatch as Mock).mock.calls.flat(); - const setDefaultFilter = dispatched.find( - (c: unknown) => c instanceof SetDefaultFilterValue - ) as SetDefaultFilterValue; - - expect(setDefaultFilter).toBeDefined(); - expect(setDefaultFilter.filterKey).toBe('isContainedBy'); - expect(setDefaultFilter.value).toBe('http://localhost:8000/v2/collections/collection-1/'); - }); - - it('should not dispatch SetExtraFilters when provider has no requiredMetadataTemplate', () => { - const { store } = setup({ collectionSubmissionWithCedar: true }); - const dispatched = (store.dispatch as Mock).mock.calls.flat(); - - expect(dispatched.some((c: unknown) => c instanceof SetExtraFilters)).toBe(false); - }); - - it('should dispatch SetExtraFilters when provider has a requiredMetadataTemplate', () => { - const { store } = setup({ - collectionSubmissionWithCedar: true, - provider: MOCK_COLLECTION_PROVIDER_WITH_TEMPLATE, - }); + it('should initialize default search filters', () => { + const { component } = setup(); + expect(component.defaultSearchFiltersInitialized()).toBe(true); + }); - const dispatched = (store.dispatch as Mock).mock.calls.flat(); - const setExtraFilters = dispatched.find((c: unknown) => c instanceof SetExtraFilters) as SetExtraFilters; + it('should dispatch SetDefaultFilterValue with collection IRI', () => { + const { store } = setup(); + const dispatched = (store.dispatch as Mock).mock.calls.flat(); + const setDefaultFilter = dispatched.find( + (c: unknown) => c instanceof SetDefaultFilterValue + ) as SetDefaultFilterValue; - expect(setExtraFilters).toBeDefined(); - expect(setExtraFilters.filters).toHaveLength(1); - expect(setExtraFilters.filters[0].key).toBe('field1'); - expect(setExtraFilters.filters[0].label).toBe('Field One'); - }); + expect(setDefaultFilter).toBeDefined(); + expect(setDefaultFilter.filterKey).toBe('isContainedBy'); + expect(setDefaultFilter.value).toBe('http://localhost:8000/v2/collections/collection-1/'); + }); - it('should render GlobalSearchComponent when filters are initialized', () => { - const { fixture } = setup({ collectionSubmissionWithCedar: true }); - const el = fixture.nativeElement as HTMLElement; + it('should not dispatch SetExtraFilters when provider has no requiredMetadataTemplate', () => { + const { store } = setup(); + const dispatched = (store.dispatch as Mock).mock.calls.flat(); + expect(dispatched.some((c: unknown) => c instanceof SetExtraFilters)).toBe(false); + }); - expect(el.querySelector('osf-global-search')).toBeTruthy(); - expect(el.querySelector('osf-collections-main-content')).toBeNull(); - }); + it('should dispatch SetExtraFilters when provider has a requiredMetadataTemplate', () => { + const { store } = setup({ provider: MOCK_COLLECTION_PROVIDER_WITH_TEMPLATE }); - it('should not dispatch any action on onSearchTriggered in shtrove mode', () => { - const { component, store } = setup({ collectionSubmissionWithCedar: true }); - (store.dispatch as Mock).mockClear(); + const dispatched = (store.dispatch as Mock).mock.calls.flat(); + const setExtraFilters = dispatched.find((c: unknown) => c instanceof SetExtraFilters) as SetExtraFilters; - component.onSearchTriggered('query'); + expect(setExtraFilters).toBeDefined(); + expect(setExtraFilters.filters).toHaveLength(1); + expect(setExtraFilters.filters[0].key).toBe('field1'); + expect(setExtraFilters.filters[0].label).toBe('Field One'); + }); - expect(store.dispatch).not.toHaveBeenCalled(); - }); + it('should render GlobalSearchComponent when filters are initialized', () => { + const { fixture } = setup(); + const el = fixture.nativeElement as HTMLElement; + expect(el.querySelector('osf-global-search')).toBeTruthy(); }); }); diff --git a/src/app/features/collections/components/collections-discover/collections-discover.component.ts b/src/app/features/collections/components/collections-discover/collections-discover.component.ts index af6994b7e..b0f4a3b8b 100644 --- a/src/app/features/collections/components/collections-discover/collections-discover.component.ts +++ b/src/app/features/collections/components/collections-discover/collections-discover.component.ts @@ -4,8 +4,6 @@ import { TranslatePipe } from '@ngx-translate/core'; import { Button } from 'primeng/button'; -import { debounceTime } from 'rxjs'; - import { isPlatformBrowser } from '@angular/common'; import { ChangeDetectionStrategy, @@ -17,7 +15,6 @@ import { PLATFORM_ID, signal, } from '@angular/core'; -import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormControl } from '@angular/forms'; import { ActivatedRoute, Router, RouterLink } from '@angular/router'; @@ -26,47 +23,25 @@ import { GlobalSearchComponent } from '@osf/shared/components/global-search/glob import { LoadingSpinnerComponent } from '@osf/shared/components/loading-spinner/loading-spinner.component'; import { SearchInputComponent } from '@osf/shared/components/search-input/search-input.component'; import { CedarTemplateFilterMapper } from '@osf/shared/mappers/filters/cedar-template-filter.mapper'; -import { CollectionsFilters } from '@osf/shared/models/collections/collections-filters.model'; import { BrandService } from '@osf/shared/services/brand.service'; import { CustomDialogService } from '@osf/shared/services/custom-dialog.service'; import { HeaderStyleService } from '@osf/shared/services/header-style.service'; -import { - ClearCollections, - ClearCollectionSubmissions, - CollectionsSelectors, - GetCollectionDetails, - GetCollectionProvider, - SearchCollectionSubmissions, - SetPageNumber, - SetSearchValue, -} from '@osf/shared/stores/collections'; +import { ClearCollections, CollectionsSelectors, GetCollectionProvider } from '@osf/shared/stores/collections'; import { ResetSearchState, SetDefaultFilterValue, SetExtraFilters } from '@osf/shared/stores/global-search'; -import { CollectionsQuerySyncService } from '../../services'; import { CollectionsHelpDialogComponent } from '../collections-help-dialog/collections-help-dialog.component'; -import { CollectionsMainContentComponent } from '../collections-main-content/collections-main-content.component'; @Component({ selector: 'osf-collections-discover', - imports: [ - Button, - RouterLink, - SearchInputComponent, - CollectionsMainContentComponent, - GlobalSearchComponent, - LoadingSpinnerComponent, - TranslatePipe, - ], + imports: [Button, RouterLink, SearchInputComponent, GlobalSearchComponent, LoadingSpinnerComponent, TranslatePipe], templateUrl: './collections-discover.component.html', styleUrl: './collections-discover.component.scss', - providers: [CollectionsQuerySyncService], changeDetection: ChangeDetectionStrategy.OnPush, }) export class CollectionsDiscoverComponent { private router = inject(Router); private route = inject(ActivatedRoute); private customDialogService = inject(CustomDialogService); - private querySyncService = inject(CollectionsQuerySyncService); private destroyRef = inject(DestroyRef); private brandService = inject(BrandService); private headerStyleHelper = inject(HeaderStyleService); @@ -78,26 +53,14 @@ export class CollectionsDiscoverComponent { providerId = signal(''); defaultSearchFiltersInitialized = signal(false); - readonly useShareTroveSearch = this.environment.collectionSubmissionWithCedar; - collectionProvider = select(CollectionsSelectors.getCollectionProvider); - collectionDetails = select(CollectionsSelectors.getCollectionDetails); - selectedFilters = select(CollectionsSelectors.getAllSelectedFilters); - sortBy = select(CollectionsSelectors.getSortBy); - searchText = select(CollectionsSelectors.getSearchText); - pageNumber = select(CollectionsSelectors.getPageNumber); isProviderLoading = select(CollectionsSelectors.getCollectionProviderLoading); primaryCollectionId = computed(() => this.collectionProvider()?.primaryCollection?.id); actions = createDispatchMap({ getCollectionProvider: GetCollectionProvider, - getCollectionDetails: GetCollectionDetails, - setSearchValue: SetSearchValue, - searchCollectionSubmissions: SearchCollectionSubmissions, - setPageNumber: SetPageNumber, clearCollections: ClearCollections, - clearCollectionsSubmissions: ClearCollectionSubmissions, setDefaultFilterValue: SetDefaultFilterValue, setExtraFilters: SetExtraFilters, resetSearchState: ResetSearchState, @@ -106,22 +69,12 @@ export class CollectionsDiscoverComponent { constructor() { this.initializeProvider(); this.setupBrandingEffect(); - - if (this.useShareTroveSearch) { - this.setupShareTroveSearchEffect(); - } else { - this.setupCollectionDetailsEffect(); - this.setupUrlSyncEffect(); - this.setupLegacySearchEffect(); - this.setupSearchBinding(); - } + this.setupShareTroveSearchEffect(); this.destroyRef.onDestroy(() => { if (this.isBrowser) { this.actions.clearCollections(); - if (this.useShareTroveSearch) { - this.actions.resetSearchState(); - } + this.actions.resetSearchState(); this.headerStyleHelper.resetToDefaults(); this.brandService.resetBranding(); } @@ -132,13 +85,6 @@ export class CollectionsDiscoverComponent { this.customDialogService.open(CollectionsHelpDialogComponent, { header: 'collections.helpDialog.header' }); } - onSearchTriggered(searchValue: string): void { - if (!this.useShareTroveSearch) { - this.actions.setSearchValue(searchValue); - this.actions.setPageNumber('1'); - } - } - private initializeProvider(): void { const id = this.route.snapshot.paramMap.get('providerId'); if (!id) { @@ -181,77 +127,4 @@ export class CollectionsDiscoverComponent { this.defaultSearchFiltersInitialized.set(true); }); } - - private setupCollectionDetailsEffect(): void { - effect(() => { - const collectionId = this.primaryCollectionId(); - if (collectionId) { - this.actions.getCollectionDetails(collectionId); - } - }); - } - - private setupUrlSyncEffect(): void { - this.querySyncService.initializeFromUrl(); - - effect(() => { - const searchText = this.searchText(); - const sortBy = this.sortBy(); - const selectedFilters = this.selectedFilters(); - const pageNumber = this.pageNumber(); - - if (searchText !== undefined && sortBy !== undefined && selectedFilters && pageNumber) { - this.querySyncService.syncStoreToUrl(searchText, sortBy, selectedFilters, pageNumber); - } - }); - } - - private setupLegacySearchEffect(): void { - effect(() => { - const searchText = this.searchText(); - const sortBy = this.sortBy(); - const selectedFilters = this.selectedFilters(); - const pageNumber = this.pageNumber(); - const providerId = this.providerId(); - const collectionDetails = this.collectionDetails(); - - if (searchText !== undefined && selectedFilters && pageNumber && providerId && collectionDetails) { - const activeFilters = this.getActiveFilters(selectedFilters); - this.actions.clearCollectionsSubmissions(); - this.actions.searchCollectionSubmissions(providerId, searchText, activeFilters, pageNumber, sortBy); - } - }); - } - - private getActiveFilters(filters: CollectionsFilters): Record { - return Object.entries(filters) - .filter(([, value]) => value.length) - .reduce( - (acc, [key, value]) => { - acc[key] = value; - return acc; - }, - {} as Record - ); - } - - private setupSearchBinding(): void { - effect(() => { - const storeSearchText = this.searchText(); - const currentControlValue = this.searchControl.value; - - if (storeSearchText !== currentControlValue) { - this.searchControl.setValue(storeSearchText, { emitEvent: false }); - } - }); - - this.searchControl.valueChanges - .pipe(debounceTime(300), takeUntilDestroyed(this.destroyRef)) - .subscribe((searchValue) => { - const trimmedValue = searchValue?.trim() || ''; - if (trimmedValue !== this.searchText()) { - this.actions.setSearchValue(trimmedValue); - } - }); - } } diff --git a/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.html b/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.html deleted file mode 100644 index 8ca68fb59..000000000 --- a/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.html +++ /dev/null @@ -1,13 +0,0 @@ -
- @for (filterEntry of activeFilterEntries(); track filterEntry.key) { - @for (filter of filterEntry.filters; track filter) { - - - } - } -
diff --git a/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.scss b/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.spec.ts b/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.spec.ts deleted file mode 100644 index 39b990092..000000000 --- a/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.spec.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { Store } from '@ngxs/store'; - -import { Mock } from 'vitest'; - -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { - CollectionsSelectors, - SetCollectedTypeFilters, - SetDataTypeFilters, - SetDiseaseFilters, - SetGradeLevelsFilters, - SetIssueFilters, - SetProgramAreaFilters, - SetSchoolTypeFilters, - SetStatusFilters, - SetStudyDesignFilters, - SetVolumeFilters, -} from '@shared/stores/collections'; - -import { - MOCK_COLLECTIONS_ACTIVE_FILTERS, - MOCK_COLLECTIONS_EMPTY_FILTERS, -} from '@testing/mocks/collections-filters.mock'; -import { provideOSFCore } from '@testing/osf.testing.provider'; -import { - BaseSetupOverrides, - mergeSignalOverrides, - provideMockStore, - SignalOverride, -} from '@testing/providers/store-provider.mock'; - -import { CollectionFilterType } from '../../enums'; - -import { CollectionsFilterChipsComponent } from './collections-filter-chips.component'; - -describe('CollectionsFilterChipsComponent', () => { - let component: CollectionsFilterChipsComponent; - let fixture: ComponentFixture; - let store: Store; - let dispatchMock: Mock; - - const mockActiveFilters = MOCK_COLLECTIONS_ACTIVE_FILTERS; - const defaultSignals: SignalOverride[] = [ - { selector: CollectionsSelectors.getAllSelectedFilters, value: mockActiveFilters }, - ]; - - function setup(overrides: BaseSetupOverrides = {}): void { - TestBed.configureTestingModule({ - imports: [CollectionsFilterChipsComponent], - providers: [ - provideOSFCore(), - provideMockStore({ signals: mergeSignalOverrides(defaultSignals, overrides.selectorOverrides) }), - ], - }); - - store = TestBed.inject(Store); - dispatchMock = store.dispatch as Mock; - fixture = TestBed.createComponent(CollectionsFilterChipsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - } - - it('should create', () => { - setup(); - expect(component).toBeTruthy(); - }); - - it('should have active filters from store', () => { - setup(); - expect(component.activeFilters()).toEqual(mockActiveFilters); - }); - - it('should compute only non-empty active filter entries', () => { - setup({ - selectorOverrides: [ - { selector: CollectionsSelectors.getAllSelectedFilters, value: MOCK_COLLECTIONS_EMPTY_FILTERS }, - ], - }); - - expect(component.activeFilterEntries()).toEqual([]); - }); - - it('should dispatch SetProgramAreaFilters when removing program area filter', () => { - setup(); - component.onRemoveFilter(CollectionFilterType.ProgramArea, 'Science'); - - expect(store.dispatch).toHaveBeenCalledWith(new SetProgramAreaFilters(['Technology'])); - }); - - it('should dispatch SetCollectedTypeFilters when removing collected type filter', () => { - setup(); - component.onRemoveFilter(CollectionFilterType.CollectedType, 'preprint'); - - expect(store.dispatch).toHaveBeenCalledWith(new SetCollectedTypeFilters([])); - }); - - it('should dispatch SetStatusFilters when removing status filter', () => { - setup(); - component.onRemoveFilter(CollectionFilterType.Status, 'pending'); - - expect(store.dispatch).toHaveBeenCalledWith(new SetStatusFilters([])); - }); - - it('should dispatch SetDataTypeFilters when removing data type filter', () => { - setup(); - component.onRemoveFilter(CollectionFilterType.DataType, 'Quantitative'); - - expect(store.dispatch).toHaveBeenCalledWith(new SetDataTypeFilters([])); - }); - - it('should dispatch SetDiseaseFilters when removing disease filter', () => { - setup(); - component.onRemoveFilter(CollectionFilterType.Disease, 'Cancer'); - - expect(store.dispatch).toHaveBeenCalledWith(new SetDiseaseFilters([])); - }); - - it('should dispatch SetGradeLevelsFilters when removing grade levels filter', () => { - setup(); - component.onRemoveFilter(CollectionFilterType.GradeLevels, 'Graduate'); - - expect(store.dispatch).toHaveBeenCalledWith(new SetGradeLevelsFilters([])); - }); - - it('should dispatch SetIssueFilters when removing issue filter', () => { - setup(); - component.onRemoveFilter(CollectionFilterType.Issue, '1'); - - expect(store.dispatch).toHaveBeenCalledWith(new SetIssueFilters([])); - }); - - it('should dispatch SetSchoolTypeFilters when removing school type filter', () => { - setup(); - component.onRemoveFilter(CollectionFilterType.SchoolType, 'University'); - - expect(store.dispatch).toHaveBeenCalledWith(new SetSchoolTypeFilters([])); - }); - - it('should dispatch SetStudyDesignFilters when removing study design filter', () => { - setup(); - component.onRemoveFilter(CollectionFilterType.StudyDesign, 'Experimental'); - - expect(store.dispatch).toHaveBeenCalledWith(new SetStudyDesignFilters([])); - }); - - it('should dispatch SetVolumeFilters when removing volume filter', () => { - setup(); - component.onRemoveFilter(CollectionFilterType.Volume, '1'); - - expect(store.dispatch).toHaveBeenCalledWith(new SetVolumeFilters([])); - }); - - it('should remove only the selected filter value', () => { - setup(); - dispatchMock.mockClear(); - - component.onRemoveFilter(CollectionFilterType.ProgramArea, 'Technology'); - - expect(store.dispatch).toHaveBeenCalledWith(new SetProgramAreaFilters(['Science'])); - }); -}); diff --git a/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.ts b/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.ts deleted file mode 100644 index 67a36c4ff..000000000 --- a/src/app/features/collections/components/collections-filter-chips/collections-filter-chips.component.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { createDispatchMap, select } from '@ngxs/store'; - -import { Chip } from 'primeng/chip'; - -import { ChangeDetectionStrategy, Component, computed } from '@angular/core'; - -import { - CollectionsSelectors, - SetCollectedTypeFilters, - SetDataTypeFilters, - SetDiseaseFilters, - SetGradeLevelsFilters, - SetIssueFilters, - SetProgramAreaFilters, - SetSchoolTypeFilters, - SetStatusFilters, - SetStudyDesignFilters, - SetVolumeFilters, -} from '@shared/stores/collections'; - -import { collectionFilterTypes } from '../../constants'; -import { CollectionFilterType } from '../../enums'; - -@Component({ - selector: 'osf-collections-filter-chips', - imports: [Chip], - templateUrl: './collections-filter-chips.component.html', - styleUrl: './collections-filter-chips.component.scss', - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class CollectionsFilterChipsComponent { - activeFilters = select(CollectionsSelectors.getAllSelectedFilters); - - private readonly filterTypes = collectionFilterTypes; - - actions = createDispatchMap({ - programArea: SetProgramAreaFilters, - collectedType: SetCollectedTypeFilters, - status: SetStatusFilters, - dataType: SetDataTypeFilters, - disease: SetDiseaseFilters, - gradeLevels: SetGradeLevelsFilters, - issue: SetIssueFilters, - schoolType: SetSchoolTypeFilters, - studyDesign: SetStudyDesignFilters, - volume: SetVolumeFilters, - }); - - activeFilterEntries = computed(() => { - const filters = this.activeFilters(); - return this.filterTypes - .map((key) => ({ - key, - filters: filters[key] || [], - })) - .filter((entry) => entry.filters.length); - }); - - onRemoveFilter(filterType: CollectionFilterType, removedFilter: string): void { - const currentFilters = this.activeFilters()[filterType].filter((filter: string) => filter !== removedFilter); - - switch (filterType) { - case CollectionFilterType.ProgramArea: - this.actions.programArea(currentFilters); - break; - case CollectionFilterType.CollectedType: - this.actions.collectedType(currentFilters); - break; - case CollectionFilterType.Status: - this.actions.status(currentFilters); - break; - case CollectionFilterType.DataType: - this.actions.dataType(currentFilters); - break; - case CollectionFilterType.Disease: - this.actions.disease(currentFilters); - break; - case CollectionFilterType.GradeLevels: - this.actions.gradeLevels(currentFilters); - break; - case CollectionFilterType.Issue: - this.actions.issue(currentFilters); - break; - case CollectionFilterType.SchoolType: - this.actions.schoolType(currentFilters); - break; - case CollectionFilterType.StudyDesign: - this.actions.studyDesign(currentFilters); - break; - case CollectionFilterType.Volume: - this.actions.volume(currentFilters); - break; - } - } -} diff --git a/src/app/features/collections/components/collections-filters/collections-filters.component.html b/src/app/features/collections/components/collections-filters/collections-filters.component.html deleted file mode 100644 index 1031d9214..000000000 --- a/src/app/features/collections/components/collections-filters/collections-filters.component.html +++ /dev/null @@ -1,26 +0,0 @@ -
- - @for (filterEntry of availableFilterEntries(); track filterEntry.key) { - - {{ filterEntry.translationKeys.label | translate }} - - - - - } - -
diff --git a/src/app/features/collections/components/collections-filters/collections-filters.component.scss b/src/app/features/collections/components/collections-filters/collections-filters.component.scss deleted file mode 100644 index bd2451693..000000000 --- a/src/app/features/collections/components/collections-filters/collections-filters.component.scss +++ /dev/null @@ -1,11 +0,0 @@ -@use "styles/mixins" as mix; - -.filters { - border: 1px solid var(--grey-2); - border-radius: mix.rem(12px); - padding: 0 mix.rem(20px); - display: flex; - flex-direction: column; - gap: mix.rem(12px); - height: fit-content; -} diff --git a/src/app/features/collections/components/collections-filters/collections-filters.component.spec.ts b/src/app/features/collections/components/collections-filters/collections-filters.component.spec.ts deleted file mode 100644 index 58de20c7b..000000000 --- a/src/app/features/collections/components/collections-filters/collections-filters.component.spec.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { CollectionsSelectors } from '@shared/stores/collections'; - -import { - MOCK_COLLECTIONS_FILTERS_OPTIONS, - MOCK_COLLECTIONS_SELECTED_FILTERS, -} from '@testing/mocks/collections-filters.mock'; -import { provideOSFCore } from '@testing/osf.testing.provider'; -import { provideMockStore } from '@testing/providers/store-provider.mock'; - -import { CollectionsFiltersComponent } from './collections-filters.component'; - -describe('CollectionsFiltersComponent', () => { - let component: CollectionsFiltersComponent; - let fixture: ComponentFixture; - - const mockFiltersOptions = MOCK_COLLECTIONS_FILTERS_OPTIONS; - const mockSelectedFilters = MOCK_COLLECTIONS_SELECTED_FILTERS; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [CollectionsFiltersComponent], - providers: [ - provideOSFCore(), - provideMockStore({ - signals: [ - { selector: CollectionsSelectors.getAllFiltersOptions, value: mockFiltersOptions }, - { selector: CollectionsSelectors.getAllSelectedFilters, value: mockSelectedFilters }, - ], - }), - ], - }); - - fixture = TestBed.createComponent(CollectionsFiltersComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should compute available filter entries correctly', () => { - const availableFilterEntries = component.availableFilterEntries(); - - expect(availableFilterEntries).toBeDefined(); - expect(Array.isArray(availableFilterEntries)).toBe(true); - - expect(availableFilterEntries.length).toBeGreaterThan(0); - - availableFilterEntries.forEach((entry) => { - expect(entry.key).toBeDefined(); - expect(entry.value).toBeDefined(); - expect(Array.isArray(entry.options)).toBe(true); - expect(Array.isArray(entry.selectedFilters)).toBe(true); - expect(entry.translationKeys).toBeDefined(); - expect(entry.translationKeys.label).toBeDefined(); - expect(entry.translationKeys.description).toBeDefined(); - expect(entry.translationKeys.placeholder).toBeDefined(); - }); - }); - - it('should filter out filter types with no options', () => { - const availableFilterEntries = component.availableFilterEntries(); - expect(availableFilterEntries.length).toBeGreaterThan(0); - - availableFilterEntries.forEach((entry) => { - expect(entry.options.length).toBeGreaterThan(0); - }); - }); - - it('should handle completely empty filter options', () => { - const availableFilterEntries = component.availableFilterEntries(); - expect(availableFilterEntries.length).toBeGreaterThan(0); - - availableFilterEntries.forEach((entry) => { - expect(entry.key).toBeDefined(); - expect(entry.value).toBeDefined(); - expect(Array.isArray(entry.options)).toBe(true); - expect(Array.isArray(entry.selectedFilters)).toBe(true); - }); - }); - - it('should handle empty selected filters', () => { - const availableFilterEntries = component.availableFilterEntries(); - - availableFilterEntries.forEach((entry) => { - expect(Array.isArray(entry.selectedFilters)).toBe(true); - expect(entry.selectedFilters.length).toBeGreaterThanOrEqual(0); - }); - }); - - it('should handle set filters without errors', () => { - const mockEvent = { value: ['Science', 'Technology'] } as any; - - expect(() => { - component.setFilters('programArea' as any, mockEvent); - }).not.toThrow(); - - expect(() => { - component.setFilters('collectedType' as any, { value: ['preprint'] } as any); - }).not.toThrow(); - - expect(() => { - component.setFilters('status' as any, { value: ['pending'] } as any); - }).not.toThrow(); - }); - - it('should handle clear filters without errors', () => { - expect(() => { - component.clearFilters('programArea' as any); - }).not.toThrow(); - - expect(() => { - component.clearFilters('collectedType' as any); - }).not.toThrow(); - - expect(() => { - component.clearFilters('status' as any); - }).not.toThrow(); - }); - - it('should have filters options from store', () => { - expect(component.filtersOptions()).toEqual(mockFiltersOptions); - }); - - it('should have selected filters from store', () => { - expect(component.selectedFilters()).toEqual(mockSelectedFilters); - }); -}); diff --git a/src/app/features/collections/components/collections-filters/collections-filters.component.ts b/src/app/features/collections/components/collections-filters/collections-filters.component.ts deleted file mode 100644 index d7805d97a..000000000 --- a/src/app/features/collections/components/collections-filters/collections-filters.component.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { createDispatchMap, select } from '@ngxs/store'; - -import { TranslatePipe } from '@ngx-translate/core'; - -import { Accordion, AccordionContent, AccordionHeader, AccordionPanel } from 'primeng/accordion'; -import { MultiSelect, MultiSelectChangeEvent } from 'primeng/multiselect'; - -import { ChangeDetectionStrategy, Component, computed } from '@angular/core'; -import { FormsModule } from '@angular/forms'; - -import { - CollectionsSelectors, - SetCollectedTypeFilters, - SetDataTypeFilters, - SetDiseaseFilters, - SetGradeLevelsFilters, - SetIssueFilters, - SetProgramAreaFilters, - SetSchoolTypeFilters, - SetStatusFilters, - SetStudyDesignFilters, - SetVolumeFilters, -} from '@shared/stores/collections'; - -import { collectionFilterTypes } from '../../constants'; -import { CollectionFilterType } from '../../enums'; - -@Component({ - selector: 'osf-collections-filters', - imports: [FormsModule, Accordion, AccordionContent, AccordionHeader, AccordionPanel, MultiSelect, TranslatePipe], - templateUrl: './collections-filters.component.html', - styleUrl: './collections-filters.component.scss', - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class CollectionsFiltersComponent { - private readonly filterTypes = collectionFilterTypes; - - filtersOptions = select(CollectionsSelectors.getAllFiltersOptions); - selectedFilters = select(CollectionsSelectors.getAllSelectedFilters); - - actions = createDispatchMap({ - programArea: SetProgramAreaFilters, - collectedType: SetCollectedTypeFilters, - status: SetStatusFilters, - dataType: SetDataTypeFilters, - disease: SetDiseaseFilters, - gradeLevels: SetGradeLevelsFilters, - issue: SetIssueFilters, - schoolType: SetSchoolTypeFilters, - studyDesign: SetStudyDesignFilters, - volume: SetVolumeFilters, - }); - - availableFilterEntries = computed(() => { - const options = this.filtersOptions(); - const selectedFilters = this.selectedFilters(); - - return this.filterTypes - .map((key, index) => ({ - key, - value: index.toString(), - options: options[key] || [], - selectedFilters: selectedFilters[key] || [], - translationKeys: { - label: `collections.filters.${key}.label`, - description: `collections.filters.${key}.description`, - placeholder: `collections.filters.${key}.placeholder`, - }, - })) - .filter((entry) => entry.options.length > 0); - }); - - setFilters(filterType: CollectionFilterType, $event: MultiSelectChangeEvent): void { - const filters = $event.value; - - switch (filterType) { - case CollectionFilterType.ProgramArea: - this.actions.programArea(filters); - break; - case CollectionFilterType.CollectedType: - this.actions.collectedType(filters); - break; - case CollectionFilterType.Status: - this.actions.status(filters); - break; - case CollectionFilterType.DataType: - this.actions.dataType(filters); - break; - case CollectionFilterType.Disease: - this.actions.disease(filters); - break; - case CollectionFilterType.GradeLevels: - this.actions.gradeLevels(filters); - break; - case CollectionFilterType.Issue: - this.actions.issue(filters); - break; - case CollectionFilterType.SchoolType: - this.actions.schoolType(filters); - break; - case CollectionFilterType.StudyDesign: - this.actions.studyDesign(filters); - break; - case CollectionFilterType.Volume: - this.actions.volume(filters); - break; - } - } - - clearFilters(filterType: CollectionFilterType): void { - this.setFilters(filterType, { value: [] } as MultiSelectChangeEvent); - } -} diff --git a/src/app/features/collections/components/collections-main-content/collections-main-content.component.html b/src/app/features/collections/components/collections-main-content/collections-main-content.component.html deleted file mode 100644 index 7bc4a1f67..000000000 --- a/src/app/features/collections/components/collections-main-content/collections-main-content.component.html +++ /dev/null @@ -1,86 +0,0 @@ -
-
- @if (totalSubmissions()) { -

{{ totalSubmissions() }} {{ 'collections.searchResults.results' | translate }}

- } @else { -

{{ 'collections.searchResults.noResults' | translate }}

- } -
- -
- @if (isWeb()) { -

{{ 'collections.filters.sort.label' | translate }}

- - - {{ selectedOption.label | translate }} - - - {{ option.label | translate }} - - - } @else { - - - - } -
-
- -@if (isFiltersOpen()) { -
- -
-} @else if (isSortingOpen()) { -
- @for (option of sortOptions; track option.value) { -
- {{ option.label | translate }} -
- } -
-} @else { - @if (hasAnySelectedFilters()) { - - } -} - -
- @if (isWeb()) { -
- @if (!isCollectionLoading()) { - - } @else { - - } -
- } - - -
diff --git a/src/app/features/collections/components/collections-main-content/collections-main-content.component.scss b/src/app/features/collections/components/collections-main-content/collections-main-content.component.scss deleted file mode 100644 index 75d67818b..000000000 --- a/src/app/features/collections/components/collections-main-content/collections-main-content.component.scss +++ /dev/null @@ -1,19 +0,0 @@ -@use "styles/mixins" as mix; - -.sort-card { - @include mix.flex-center; - width: 100%; - height: mix.rem(48px); - border: 1px solid var(--grey-2); - border-radius: mix.rem(12px); - padding: 0 mix.rem(28px); - cursor: pointer; -} - -.card-selected { - background: var(--bg-blue-2); -} - -.filters-column { - flex: 0 0 22rem; -} diff --git a/src/app/features/collections/components/collections-main-content/collections-main-content.component.spec.ts b/src/app/features/collections/components/collections-main-content/collections-main-content.component.spec.ts deleted file mode 100644 index 5322d6212..000000000 --- a/src/app/features/collections/components/collections-main-content/collections-main-content.component.spec.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { MockComponents } from 'ng-mocks'; - -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { CollectionsSelectors } from '@shared/stores/collections'; - -import { MOCK_COLLECTIONS_SELECTED_FILTERS } from '@testing/mocks/collections-filters.mock'; -import { provideOSFCore } from '@testing/osf.testing.provider'; -import { provideMockStore } from '@testing/providers/store-provider.mock'; - -import { CollectionsFilterChipsComponent } from '../collections-filter-chips/collections-filter-chips.component'; -import { CollectionsFiltersComponent } from '../collections-filters/collections-filters.component'; -import { CollectionsSearchResultsComponent } from '../collections-search-results/collections-search-results.component'; - -import { CollectionsMainContentComponent } from './collections-main-content.component'; - -describe('CollectionsMainContentComponent', () => { - let component: CollectionsMainContentComponent; - let fixture: ComponentFixture; - - const mockSelectedFilters = MOCK_COLLECTIONS_SELECTED_FILTERS; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - CollectionsMainContentComponent, - ...MockComponents( - CollectionsFilterChipsComponent, - CollectionsFiltersComponent, - CollectionsSearchResultsComponent - ), - ], - providers: [ - provideOSFCore(), - provideMockStore({ - signals: [ - { selector: CollectionsSelectors.getSortBy, value: 'date' }, - { selector: CollectionsSelectors.getAllSelectedFilters, value: mockSelectedFilters }, - { selector: CollectionsSelectors.getCollectionProviderLoading, value: false }, - { selector: CollectionsSelectors.getCollectionDetailsLoading, value: false }, - ], - }), - ], - }); - - fixture = TestBed.createComponent(CollectionsMainContentComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should handle open filters', () => { - expect(component.isFiltersOpen()).toBe(false); - expect(component.isSortingOpen()).toBe(false); - - component.openFilters(); - - expect(component.isFiltersOpen()).toBe(true); - expect(component.isSortingOpen()).toBe(false); - }); - - it('should toggle filters when already open', () => { - component.openFilters(); - expect(component.isFiltersOpen()).toBe(true); - - component.openFilters(); - expect(component.isFiltersOpen()).toBe(false); - }); - - it('should handle open sorting', () => { - expect(component.isSortingOpen()).toBe(false); - expect(component.isFiltersOpen()).toBe(false); - - component.openSorting(); - - expect(component.isSortingOpen()).toBe(true); - expect(component.isFiltersOpen()).toBe(false); - }); - - it('should toggle sorting when already open', () => { - component.openSorting(); - expect(component.isSortingOpen()).toBe(true); - - component.openSorting(); - expect(component.isSortingOpen()).toBe(false); - }); - - it('should handle sort by selection', () => { - const newSortValue = 'title'; - - component.handleSortBy(newSortValue); - - expect(component.isSortingOpen()).toBe(false); - }); - - it('should close sorting when sort is selected', () => { - component.openSorting(); - expect(component.isSortingOpen()).toBe(true); - - component.handleSortBy('title'); - - expect(component.isSortingOpen()).toBe(false); - }); - - it('should have actions defined', () => { - expect(component.actions).toBeDefined(); - expect(component.actions.setSortBy).toBeDefined(); - }); - - it('should handle filters and sorting mutual exclusivity', () => { - component.openFilters(); - expect(component.isFiltersOpen()).toBe(true); - expect(component.isSortingOpen()).toBe(false); - - component.openSorting(); - expect(component.isFiltersOpen()).toBe(false); - expect(component.isSortingOpen()).toBe(true); - - component.openFilters(); - expect(component.isFiltersOpen()).toBe(true); - expect(component.isSortingOpen()).toBe(false); - }); - - it('should handle partial selected filters', () => { - expect(component.hasAnySelectedFilters()).toBe(true); - }); -}); diff --git a/src/app/features/collections/components/collections-main-content/collections-main-content.component.ts b/src/app/features/collections/components/collections-main-content/collections-main-content.component.ts deleted file mode 100644 index d20c638c4..000000000 --- a/src/app/features/collections/components/collections-main-content/collections-main-content.component.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { createDispatchMap, select } from '@ngxs/store'; - -import { TranslatePipe } from '@ngx-translate/core'; - -import { Button } from 'primeng/button'; -import { Select } from 'primeng/select'; -import { Skeleton } from 'primeng/skeleton'; - -import { ChangeDetectionStrategy, Component, computed, inject, signal } from '@angular/core'; -import { toSignal } from '@angular/core/rxjs-interop'; -import { FormsModule } from '@angular/forms'; - -import { collectionsSortOptions } from '@osf/features/collections/constants'; -import { IS_WEB } from '@osf/shared/helpers/breakpoints.tokens'; -import { CollectionsSelectors, SetSortBy } from '@shared/stores/collections'; - -import { CollectionsFilterChipsComponent } from '../collections-filter-chips/collections-filter-chips.component'; -import { CollectionsFiltersComponent } from '../collections-filters/collections-filters.component'; -import { CollectionsSearchResultsComponent } from '../collections-search-results/collections-search-results.component'; - -@Component({ - selector: 'osf-collections-main-content', - imports: [ - Button, - Select, - Skeleton, - FormsModule, - TranslatePipe, - CollectionsFilterChipsComponent, - CollectionsFiltersComponent, - CollectionsSearchResultsComponent, - ], - templateUrl: './collections-main-content.component.html', - styleUrl: './collections-main-content.component.scss', - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class CollectionsMainContentComponent { - readonly sortOptions = collectionsSortOptions; - - isWeb = toSignal(inject(IS_WEB)); - - actions = createDispatchMap({ setSortBy: SetSortBy }); - - selectedSort = select(CollectionsSelectors.getSortBy); - totalSubmissions = select(CollectionsSelectors.getTotalSubmissions); - selectedFilters = select(CollectionsSelectors.getAllSelectedFilters); - isCollectionProviderLoading = select(CollectionsSelectors.getCollectionProviderLoading); - isCollectionDetailsLoading = select(CollectionsSelectors.getCollectionDetailsLoading); - - isFiltersOpen = signal(false); - isSortingOpen = signal(false); - - isCollectionLoading = computed(() => this.isCollectionProviderLoading() || this.isCollectionDetailsLoading()); - - hasAnySelectedFilters = computed(() => { - const currentFilters = this.selectedFilters(); - const hasSelectedFiltersOptions = Object.values(currentFilters).some((value) => value.length); - - return hasSelectedFiltersOptions; - }); - - openFilters(): void { - this.isFiltersOpen.set(!this.isFiltersOpen()); - this.isSortingOpen.set(false); - } - - openSorting(): void { - this.isSortingOpen.set(!this.isSortingOpen()); - this.isFiltersOpen.set(false); - } - - handleSortBy(value: string): void { - this.actions.setSortBy(value); - this.isSortingOpen.set(false); - } -} diff --git a/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.html b/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.html deleted file mode 100644 index d12b43292..000000000 --- a/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.html +++ /dev/null @@ -1,34 +0,0 @@ -@let item = cardItem(); - -
- -

{{ item?.title }}

-
- - @if (item?.contributors?.length) { -
-

{{ 'collections.common.by' | translate }}

- - -
- } - -

{{ item?.description }}

- -

- {{ 'collections.common.dateCreated' | translate }} - {{ item?.dateCreated | date: 'longDate' }} - | - {{ 'collections.common.dateModified' | translate }} - {{ item?.dateModified | date: 'longDate' }} -

- -
- @for (attribute of presentSubmissionAttributes(); track attribute.key) { - @if (!$first) { - | - } - {{ attribute.label }}: {{ attribute.value }} - } -
-
diff --git a/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.scss b/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.scss deleted file mode 100644 index f2cbf1140..000000000 --- a/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.scss +++ /dev/null @@ -1,29 +0,0 @@ -@use "styles/mixins" as mix; - -:host { - width: 100%; - flex: 1; - - .card { - border: 1px solid var(--grey-2); - border-radius: mix.rem(8px); - - .card-title { - font-size: mix.rem(18px); - } - - .card-description { - display: -webkit-box; - overflow: hidden; - text-overflow: ellipsis; - line-clamp: 2; - line-height: mix.rem(28px); - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - } - - .separator { - margin: 0 mix.rem(6px); - } - } -} diff --git a/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.spec.ts b/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.spec.ts deleted file mode 100644 index 1ee1f3617..000000000 --- a/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.spec.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { MockComponent } from 'ng-mocks'; - -import { ComponentRef } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ContributorsListComponent } from '@osf/shared/components/contributors-list/contributors-list.component'; -import { CollectionSubmissionWithGuid } from '@osf/shared/models/collections/collections.model'; - -import { MOCK_COLLECTION_SUBMISSION_WITH_GUID } from '@testing/mocks/submission.mock'; -import { provideOSFCore } from '@testing/osf.testing.provider'; - -import { CollectionsSearchResultCardComponent } from './collections-search-result-card.component'; - -describe('CollectionsSearchResultCardComponent', () => { - let component: CollectionsSearchResultCardComponent; - let componentRef: ComponentRef; - let fixture: ComponentFixture; - - const mockCardItem: CollectionSubmissionWithGuid = MOCK_COLLECTION_SUBMISSION_WITH_GUID; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [CollectionsSearchResultCardComponent, MockComponent(ContributorsListComponent)], - providers: [provideOSFCore()], - }); - - fixture = TestBed.createComponent(CollectionsSearchResultCardComponent); - component = fixture.componentInstance; - componentRef = fixture.componentRef; - - componentRef.setInput('cardItem', mockCardItem); - - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should have cardItem input', () => { - expect(component.cardItem()).toEqual(mockCardItem); - }); - - it('should compute present submission attributes correctly', () => { - const presentAttributes = component.presentSubmissionAttributes(); - - expect(presentAttributes).toBeDefined(); - expect(Array.isArray(presentAttributes)).toBe(true); - expect(presentAttributes.length).toBeGreaterThan(0); - - presentAttributes.forEach((attribute) => { - expect(attribute.value).toBeTruthy(); - expect(attribute.key).toBeDefined(); - expect(attribute.label).toBeDefined(); - }); - }); - - it('should include all filter attributes with values', () => { - const presentAttributes = component.presentSubmissionAttributes(); - const attributeKeys = presentAttributes.map((attr) => attr.key); - - expect(attributeKeys).toContain('programArea'); - expect(attributeKeys).toContain('collectedType'); - expect(attributeKeys).toContain('status'); - expect(attributeKeys).toContain('volume'); - expect(attributeKeys).toContain('issue'); - expect(attributeKeys).toContain('schoolType'); - expect(attributeKeys).toContain('studyDesign'); - expect(attributeKeys).toContain('dataType'); - expect(attributeKeys).toContain('disease'); - expect(attributeKeys).toContain('gradeLevels'); - }); - - it('should have correct attribute structure', () => { - const presentAttributes = component.presentSubmissionAttributes(); - - presentAttributes.forEach((attribute) => { - expect(attribute).toHaveProperty('key'); - expect(attribute).toHaveProperty('label'); - expect(attribute).toHaveProperty('value'); - expect(typeof attribute.key).toBe('string'); - expect(typeof attribute.label).toBe('string'); - expect(typeof attribute.value).toBe('string'); - }); - }); - - it('should handle partial attributes', () => { - const partialCardItem: CollectionSubmissionWithGuid = { - ...mockCardItem, - programArea: 'Science', - collectedType: 'preprint', - status: 'pending', - volume: '', - issue: '', - schoolType: '', - studyDesign: '', - dataType: '', - disease: '', - gradeLevels: '', - }; - - componentRef.setInput('cardItem', partialCardItem); - fixture.detectChanges(); - - const presentAttributes = component.presentSubmissionAttributes(); - - expect(presentAttributes.length).toBe(3); - expect(presentAttributes.map((attr) => attr.key)).toEqual(['programArea', 'collectedType', 'status']); - }); - - it('should handle cardItem with only some attributes', () => { - const minimalCardItem: CollectionSubmissionWithGuid = { - ...mockCardItem, - programArea: 'Science', - collectedType: '', - status: '', - volume: '', - issue: '', - schoolType: '', - studyDesign: '', - dataType: '', - disease: '', - gradeLevels: '', - }; - - componentRef.setInput('cardItem', minimalCardItem); - fixture.detectChanges(); - - const presentAttributes = component.presentSubmissionAttributes(); - - expect(presentAttributes.length).toBe(1); - expect(presentAttributes[0].key).toBe('programArea'); - expect(presentAttributes[0].value).toBe('Science'); - }); - - it('should handle empty string values', () => { - const emptyStringCardItem: CollectionSubmissionWithGuid = { - ...mockCardItem, - programArea: '', - collectedType: '', - status: '', - volume: '', - issue: '', - schoolType: '', - studyDesign: '', - dataType: '', - disease: '', - gradeLevels: '', - }; - - componentRef.setInput('cardItem', emptyStringCardItem); - fixture.detectChanges(); - - const presentAttributes = component.presentSubmissionAttributes(); - expect(presentAttributes.length).toBe(0); - }); -}); diff --git a/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.ts b/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.ts deleted file mode 100644 index 2a7b91117..000000000 --- a/src/app/features/collections/components/collections-search-result-card/collections-search-result-card.component.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { TranslatePipe } from '@ngx-translate/core'; - -import { DatePipe } from '@angular/common'; -import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core'; - -import { collectionFilterNames } from '@osf/features/collections/constants'; -import { ContributorsListComponent } from '@osf/shared/components/contributors-list/contributors-list.component'; -import { CollectionSubmissionWithGuid } from '@osf/shared/models/collections/collections.model'; - -@Component({ - selector: 'osf-collections-search-result-card', - imports: [DatePipe, TranslatePipe, ContributorsListComponent], - templateUrl: './collections-search-result-card.component.html', - styleUrl: './collections-search-result-card.component.scss', - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class CollectionsSearchResultCardComponent { - cardItem = input.required(); - - presentSubmissionAttributes = computed(() => { - const item = this.cardItem(); - if (!item) return []; - - return collectionFilterNames - .map((attribute) => ({ - ...attribute, - value: item[attribute.key as keyof CollectionSubmissionWithGuid] as string, - })) - .filter((attribute) => attribute.value); - }); -} diff --git a/src/app/features/collections/components/collections-search-results/collections-search-results.component.html b/src/app/features/collections/components/collections-search-results/collections-search-results.component.html deleted file mode 100644 index badb44087..000000000 --- a/src/app/features/collections/components/collections-search-results/collections-search-results.component.html +++ /dev/null @@ -1,31 +0,0 @@ - - -
- @if (isLoading()) { - - - - } @else { - @if (items.length) { - @for (item of items; track item.id) { - - } - -
- -
- } @else { -

- {{ 'collections.searchResults.noResultsFound' | translate }} -

-

{{ 'collections.searchResults.noResultsFoundMessage' | translate }}

- } - } -
-
-
diff --git a/src/app/features/collections/components/collections-search-results/collections-search-results.component.scss b/src/app/features/collections/components/collections-search-results/collections-search-results.component.scss deleted file mode 100644 index b9bc65ea4..000000000 --- a/src/app/features/collections/components/collections-search-results/collections-search-results.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -:host { - width: 100%; -} diff --git a/src/app/features/collections/components/collections-search-results/collections-search-results.component.spec.ts b/src/app/features/collections/components/collections-search-results/collections-search-results.component.spec.ts deleted file mode 100644 index 5b8c1dbe2..000000000 --- a/src/app/features/collections/components/collections-search-results/collections-search-results.component.spec.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { MockComponents } from 'ng-mocks'; - -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { CustomPaginatorComponent } from '@osf/shared/components/custom-paginator/custom-paginator.component'; -import { CollectionsSelectors } from '@shared/stores/collections'; - -import { MOCK_COLLECTION_SUBMISSION_WITH_GUID } from '@testing/mocks/submission.mock'; -import { provideOSFCore } from '@testing/osf.testing.provider'; -import { provideMockStore } from '@testing/providers/store-provider.mock'; - -import { CollectionsSearchResultCardComponent } from '../collections-search-result-card/collections-search-result-card.component'; - -import { CollectionsSearchResultsComponent } from './collections-search-results.component'; - -describe('CollectionsSearchResultsComponent', () => { - let component: CollectionsSearchResultsComponent; - let fixture: ComponentFixture; - - const mockSearchResults = [ - MOCK_COLLECTION_SUBMISSION_WITH_GUID, - { ...MOCK_COLLECTION_SUBMISSION_WITH_GUID, id: '2', title: 'Second Submission' }, - { ...MOCK_COLLECTION_SUBMISSION_WITH_GUID, id: '3', title: 'Third Submission' }, - ]; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - CollectionsSearchResultsComponent, - ...MockComponents(CustomPaginatorComponent, CollectionsSearchResultCardComponent), - ], - providers: [ - provideOSFCore(), - provideMockStore({ - signals: [ - { selector: CollectionsSelectors.getCollectionSubmissionsSearchResult, value: mockSearchResults }, - { selector: CollectionsSelectors.getCollectionDetailsLoading, value: false }, - { selector: CollectionsSelectors.getCollectionSubmissionsLoading, value: false }, - { selector: CollectionsSelectors.getTotalSubmissions, value: 25 }, - { selector: CollectionsSelectors.getPageNumber, value: '1' }, - ], - }), - ], - }); - - fixture = TestBed.createComponent(CollectionsSearchResultsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should compute first index correctly for page 1', () => { - expect(component.firstIndex()).toBe(0); - }); - - it('should handle page change with valid page number', () => { - const mockEvent = { page: 1, first: 10, rows: 10, pageCount: 3 }; - - component.onPageChange(mockEvent); - - expect(component.actions.setPageNumber).toBeDefined(); - }); - - it('should handle page change with page 0', () => { - const mockEvent = { page: 0, first: 0, rows: 10, pageCount: 3 }; - - component.onPageChange(mockEvent); - - expect(component.actions.setPageNumber).toBeDefined(); - }); -}); diff --git a/src/app/features/collections/components/collections-search-results/collections-search-results.component.ts b/src/app/features/collections/components/collections-search-results/collections-search-results.component.ts deleted file mode 100644 index 30c96b7a0..000000000 --- a/src/app/features/collections/components/collections-search-results/collections-search-results.component.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { createDispatchMap, select } from '@ngxs/store'; - -import { TranslatePipe } from '@ngx-translate/core'; - -import { DataView } from 'primeng/dataview'; -import { PaginatorState } from 'primeng/paginator'; -import { Skeleton } from 'primeng/skeleton'; - -import { ChangeDetectionStrategy, Component, computed } from '@angular/core'; - -import { CustomPaginatorComponent } from '@osf/shared/components/custom-paginator/custom-paginator.component'; -import { CollectionsSelectors, SetPageNumber } from '@shared/stores/collections'; - -import { CollectionsSearchResultCardComponent } from '../collections-search-result-card/collections-search-result-card.component'; - -@Component({ - selector: 'osf-collections-search-results', - imports: [DataView, Skeleton, CustomPaginatorComponent, CollectionsSearchResultCardComponent, TranslatePipe], - templateUrl: './collections-search-results.component.html', - styleUrl: './collections-search-results.component.scss', - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class CollectionsSearchResultsComponent { - searchResults = select(CollectionsSelectors.getCollectionSubmissionsSearchResult); - isCollectionDetailsLoading = select(CollectionsSelectors.getCollectionDetailsLoading); - isCollectionSubmissionsLoading = select(CollectionsSelectors.getCollectionSubmissionsLoading); - totalSubmissions = select(CollectionsSelectors.getTotalSubmissions); - pageNumber = select(CollectionsSelectors.getPageNumber); - - actions = createDispatchMap({ setPageNumber: SetPageNumber }); - - isLoading = computed(() => this.isCollectionDetailsLoading() || this.isCollectionSubmissionsLoading()); - - firstIndex = computed(() => (parseInt(this.pageNumber()) - 1) * 10); - - onPageChange(event: PaginatorState): void { - if (event.page !== undefined) { - const pageNumber = (event.page + 1).toString(); - this.actions.setPageNumber(pageNumber); - } - } -} diff --git a/src/app/features/collections/constants/filter-names.const.ts b/src/app/features/collections/constants/filter-names.const.ts deleted file mode 100644 index f5c055878..000000000 --- a/src/app/features/collections/constants/filter-names.const.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const collectionFilterNames = [ - { key: 'programArea', label: 'Program Area' }, - { key: 'collectedType', label: 'Type' }, - { key: 'dataType', label: 'Data Type' }, - { key: 'disease', label: 'Disease' }, - { key: 'gradeLevels', label: 'Grade Levels' }, - { key: 'issue', label: 'Issue' }, - { key: 'schoolType', label: 'School Type' }, - { key: 'status', label: 'Status' }, - { key: 'studyDesign', label: 'Study Design' }, - { key: 'volume', label: 'Volume' }, -]; diff --git a/src/app/features/collections/constants/filter-types.const.ts b/src/app/features/collections/constants/filter-types.const.ts deleted file mode 100644 index 0cfc6f232..000000000 --- a/src/app/features/collections/constants/filter-types.const.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { CollectionFilterType } from '../enums'; - -export const collectionFilterTypes: CollectionFilterType[] = [ - CollectionFilterType.ProgramArea, - CollectionFilterType.CollectedType, - CollectionFilterType.Status, - CollectionFilterType.DataType, - CollectionFilterType.Disease, - CollectionFilterType.GradeLevels, - CollectionFilterType.Issue, - CollectionFilterType.SchoolType, - CollectionFilterType.StudyDesign, - CollectionFilterType.Volume, -]; diff --git a/src/app/features/collections/constants/index.ts b/src/app/features/collections/constants/index.ts deleted file mode 100644 index 5e7661ebb..000000000 --- a/src/app/features/collections/constants/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './filter-names.const'; -export * from './filter-types.const'; -export * from './query-params-keys.const'; -export * from './sort-options.const'; diff --git a/src/app/features/collections/constants/query-params-keys.const.ts b/src/app/features/collections/constants/query-params-keys.const.ts deleted file mode 100644 index 2f7804b21..000000000 --- a/src/app/features/collections/constants/query-params-keys.const.ts +++ /dev/null @@ -1 +0,0 @@ -export const queryParamsKeys = ['page', 'search', 'sort', 'activeFilters']; diff --git a/src/app/features/collections/constants/sort-options.const.ts b/src/app/features/collections/constants/sort-options.const.ts deleted file mode 100644 index 2a95d3a56..000000000 --- a/src/app/features/collections/constants/sort-options.const.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const collectionsSortOptions = [ - { label: 'common.sort.relevance', value: '' }, - { label: 'common.sort.createdNewest', value: '-created' }, - { label: 'common.sort.createdOldest', value: 'created' }, - { label: 'common.sort.modifiedNewest', value: '-modified' }, - { label: 'common.sort.modifiedOldest', value: 'modified' }, -]; diff --git a/src/app/features/collections/enums/collection-filter-type.enum.ts b/src/app/features/collections/enums/collection-filter-type.enum.ts deleted file mode 100644 index 286ed507f..000000000 --- a/src/app/features/collections/enums/collection-filter-type.enum.ts +++ /dev/null @@ -1,12 +0,0 @@ -export enum CollectionFilterType { - ProgramArea = 'programArea', - CollectedType = 'collectedType', - Status = 'status', - DataType = 'dataType', - Disease = 'disease', - GradeLevels = 'gradeLevels', - Issue = 'issue', - SchoolType = 'schoolType', - StudyDesign = 'studyDesign', - Volume = 'volume', -} diff --git a/src/app/features/collections/enums/index.ts b/src/app/features/collections/enums/index.ts index 28ab29dad..e9ac748d0 100644 --- a/src/app/features/collections/enums/index.ts +++ b/src/app/features/collections/enums/index.ts @@ -1,3 +1,2 @@ export * from './add-to-collection-steps.enum'; -export * from './collection-filter-type.enum'; export * from './project-metadata-form-controls.enum'; diff --git a/src/app/features/collections/models/collection-filter-entry.model.ts b/src/app/features/collections/models/collection-filter-entry.model.ts deleted file mode 100644 index f04210a83..000000000 --- a/src/app/features/collections/models/collection-filter-entry.model.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface CollectionFilterEntry { - key: string; - value: string; - options: string[]; - labelKey: string; -} diff --git a/src/app/features/collections/models/collections-query-params.model.ts b/src/app/features/collections/models/collections-query-params.model.ts deleted file mode 100644 index f9e85635c..000000000 --- a/src/app/features/collections/models/collections-query-params.model.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface CollectionQueryParams { - page?: string; - search?: string; - sort?: string; - activeFilters?: string | null; -} diff --git a/src/app/features/collections/services/add-to-collection.service.ts b/src/app/features/collections/services/add-to-collection.service.ts index 94d36d32e..c2e8a1c1b 100644 --- a/src/app/features/collections/services/add-to-collection.service.ts +++ b/src/app/features/collections/services/add-to-collection.service.ts @@ -41,16 +41,6 @@ export class AddToCollectionService { return this.jsonApiService.post(`${this.apiUrl}/collections/${collectionId}/collection_submissions/`, metadata); } - updateCollectionSubmission(payload: CollectionSubmissionPayload): Observable { - const collectionId = payload.collectionId; - const metadata = CollectionsMapper.collectionSubmissionUpdateRequest(payload); - - return this.jsonApiService.patch( - `${this.apiUrl}/collections/${collectionId}/collection_submissions/${payload.projectId}/`, - metadata - ); - } - removeCollectionSubmission(payload: RemoveCollectionSubmissionPayload): Observable { const reviewActionPayload: ReviewActionPayload = { action: 'remove', diff --git a/src/app/features/collections/services/collections-query-sync.service.ts b/src/app/features/collections/services/collections-query-sync.service.ts deleted file mode 100644 index 22bb19bb4..000000000 --- a/src/app/features/collections/services/collections-query-sync.service.ts +++ /dev/null @@ -1,272 +0,0 @@ -import { createDispatchMap, select } from '@ngxs/store'; - -import { effect, inject, Injectable, signal } from '@angular/core'; -import { toSignal } from '@angular/core/rxjs-interop'; -import { ActivatedRoute, Router } from '@angular/router'; - -import { SENTRY_TOKEN } from '@core/provider/sentry.provider'; -import { collectionsSortOptions } from '@osf/features/collections/constants'; -import { queryParamsKeys } from '@osf/features/collections/constants/query-params-keys.const'; -import { CollectionsFilters } from '@osf/shared/models/collections/collections-filters.model'; -import { CollectionsSelectors, SetAllFilters, SetSearchValue, SetSortBy } from '@shared/stores/collections'; -import { SetPageNumber } from '@shared/stores/collections/collections.actions'; - -import { CollectionQueryParams } from '../models/collections-query-params.model'; - -@Injectable() -export class CollectionsQuerySyncService { - private readonly Sentry = inject(SENTRY_TOKEN); - private readonly router = inject(Router); - private readonly route = inject(ActivatedRoute); - - private readonly queryParams = toSignal(this.route.queryParams); - private readonly isInitialized = signal(false); - private readonly pendingFilters = signal(null); - private readonly pendingSort = signal(null); - - private readonly filtersOptions = select(CollectionsSelectors.getAllFiltersOptions); - - private readonly actions = createDispatchMap({ - setSortBy: SetSortBy, - setSearchValue: SetSearchValue, - setAllFilters: SetAllFilters, - setPageNumber: SetPageNumber, - }); - - constructor() { - this.setupFilterValidationEffect(); - this.setupSortValidationEffect(); - } - - initializeFromUrl(): void { - this.initializeSearchAndSort(); - this.initializeFilters(); - this.isInitialized.set(true); - } - - syncStoreToUrl(searchText: string, sortBy: string, selectedFilters: CollectionsFilters, page: string): void { - if (!this.isInitialized() || this.pendingFilters()) return; - - const updates = this.calculateUrlUpdates(searchText, sortBy, selectedFilters, page); - if (this.hasUrlUpdates(updates)) { - this.updateUrlQueryParams(updates); - } - } - - private setupFilterValidationEffect(): void { - effect(() => { - const options = this.filtersOptions(); - const pending = this.pendingFilters(); - - if (pending && this.hasAvailableFilterOptions(options)) { - this.validateAndApplyPendingFilters(pending, options); - } - }); - } - - private setupSortValidationEffect(): void { - effect(() => { - const pending = this.pendingSort(); - - if (pending !== null && this.isInitialized()) { - this.validateAndApplyPendingSort(pending); - } - }); - } - - private initializeSearchAndSort(): void { - const params = this.queryParams(); - if (!params) return; - - if (params['search'] || params['q']) { - this.actions.setSearchValue(params['search'] || params['q']); - } - - if (params['sort']) { - this.handleSortFromUrl(params['sort']); - } - - if (params['page']) { - this.actions.setPageNumber(params['page'].toString()); - } - } - - private handleSortFromUrl(sortValue: string): void { - if (this.isValidSortValue(sortValue)) { - this.actions.setSortBy(sortValue); - } else { - this.pendingSort.set(sortValue); - } - } - - private validateAndApplyPendingSort(sortValue: string): void { - if (this.isValidSortValue(sortValue)) { - this.actions.setSortBy(sortValue); - } else { - this.actions.setSortBy(collectionsSortOptions[0].value); - } - this.pendingSort.set(null); - } - - private isValidSortValue(sortValue: string): boolean { - return collectionsSortOptions.some((option) => option.value === sortValue); - } - - private initializeFilters(): void { - const params = this.queryParams(); - const activeFilters = params?.['activeFilters']; - - if (!activeFilters) return; - - try { - const parsedFilters: CollectionsFilters = JSON.parse(activeFilters); - this.handleParsedFilters(parsedFilters); - } catch (error) { - this.Sentry.captureException(error); - } - } - - private handleParsedFilters(filters: CollectionsFilters): void { - const options = this.filtersOptions(); - - if (this.hasAvailableFilterOptions(options)) { - this.validateAndApplyFiltersImmediately(filters, options); - } else { - this.pendingFilters.set(filters); - } - } - - private validateAndApplyPendingFilters(filters: CollectionsFilters, options: CollectionsFilters): void { - const validatedFilters = this.validateFilters(filters, options); - const selectedFilters = this.getSelectedFilters(validatedFilters); - - if (Object.keys(selectedFilters).length) { - this.actions.setAllFilters(selectedFilters); - } - - this.pendingFilters.set(null); - } - - private validateAndApplyFiltersImmediately(filters: CollectionsFilters, options: CollectionsFilters): void { - const validatedFilters = this.validateFilters(filters, options); - const selectedFilters = this.getSelectedFilters(validatedFilters); - - if (Object.keys(selectedFilters).length) { - this.actions.setAllFilters(selectedFilters); - } - } - - private validateFilters(filters: CollectionsFilters, availableOptions: CollectionsFilters): CollectionsFilters { - const validatedFilters: Partial = {}; - - Object.keys(filters).forEach((filterKey) => { - const key = filterKey as keyof CollectionsFilters; - const filterValues = filters[key]; - const availableValues = availableOptions[key]; - - if (this.isValidFilterArray(filterValues, availableValues)) { - const validValues = this.getValidFilterValues(filterValues, availableValues); - if (validValues.length) { - validatedFilters[key] = validValues; - } - } - }); - - return validatedFilters as CollectionsFilters; - } - - private calculateUrlUpdates( - searchText: string, - sortBy: string, - selectedFilters: CollectionsFilters, - page: string - ): Partial { - const currentParams = this.queryParams(); - if (!currentParams) return {}; - - const updates: Partial = {}; - - if (searchText !== currentParams['search']) { - updates.search = searchText || undefined; - } - - if (sortBy !== currentParams['sort']) { - updates.sort = sortBy; - } - - if (page !== currentParams['page']) { - updates.page = page; - } - - const activeFiltersParam = this.createActiveFiltersParam(selectedFilters); - if (activeFiltersParam !== currentParams['activeFilters']) { - updates.activeFilters = activeFiltersParam; - } - - return updates; - } - - private createActiveFiltersParam(selectedFilters: CollectionsFilters): string | null { - const hasFilters = this.hasActiveFilters(selectedFilters); - return hasFilters ? JSON.stringify(this.getSelectedFilters(selectedFilters)) : null; - } - - private hasUrlUpdates(updates: Partial): boolean { - return Object.keys(updates).length > 0; - } - - private updateUrlQueryParams(updates: Partial): void { - const currentParams = this.queryParams() || {}; - const queryParams: Record = {}; - - queryParamsKeys.forEach((key) => { - const updateValue = updates[key as keyof CollectionQueryParams]; - const currentValue = currentParams[key]; - - if (key in updates) { - queryParams[key] = updateValue ? updateValue.toString() : null; - } else if (currentValue) { - queryParams[key] = currentValue; - } - }); - - this.router.navigate([], { - relativeTo: this.route, - queryParams, - }); - } - - private hasAvailableFilterOptions(options: CollectionsFilters): boolean { - return Object.values(options).some((filterArray) => Array.isArray(filterArray) && filterArray.length); - } - - private isValidFilterArray(filterValues: unknown, availableValues: unknown): boolean { - return Array.isArray(filterValues) && Array.isArray(availableValues); - } - - private getValidFilterValues(filterValues: string[], availableValues: (string | { value: string })[]): string[] { - return filterValues.filter((value) => - availableValues.some((option: string | { value: string }) => { - return typeof option === 'string' ? option === value : option.value === value; - }) - ); - } - - private getSelectedFilters(filters: CollectionsFilters): Partial { - const result: Partial = {}; - const filterKeys = Object.keys(filters) as (keyof CollectionsFilters)[]; - - filterKeys.forEach((key) => { - const filterArray = filters[key]; - if (Array.isArray(filterArray) && filterArray.length) { - result[key] = filterArray; - } - }); - - return result; - } - - private hasActiveFilters(filters: CollectionsFilters): boolean { - return Object.values(filters).some((filterArray) => Array.isArray(filterArray) && filterArray.length); - } -} diff --git a/src/app/features/collections/services/index.ts b/src/app/features/collections/services/index.ts index 66b8b9238..a0b37eb1f 100644 --- a/src/app/features/collections/services/index.ts +++ b/src/app/features/collections/services/index.ts @@ -1,3 +1,2 @@ export * from './add-to-collection.service'; -export * from './collections-query-sync.service'; export * from './project-metadata-form.service'; diff --git a/src/app/features/collections/store/add-to-collection/add-to-collection.actions.ts b/src/app/features/collections/store/add-to-collection/add-to-collection.actions.ts index 8d0531014..8b68c33b5 100644 --- a/src/app/features/collections/store/add-to-collection/add-to-collection.actions.ts +++ b/src/app/features/collections/store/add-to-collection/add-to-collection.actions.ts @@ -23,12 +23,6 @@ export class CreateCollectionSubmission { constructor(public metadata: CollectionSubmissionPayload) {} } -export class UpdateCollectionSubmission { - static readonly type = '[Add To Collection] Update Collection Submission'; - - constructor(public metadata: CollectionSubmissionPayload) {} -} - export class RemoveCollectionSubmission { static readonly type = '[Add To Collection] Delete Collection Submission'; diff --git a/src/app/features/collections/store/add-to-collection/add-to-collection.state.ts b/src/app/features/collections/store/add-to-collection/add-to-collection.state.ts index 04a1848c0..1e1f230f0 100644 --- a/src/app/features/collections/store/add-to-collection/add-to-collection.state.ts +++ b/src/app/features/collections/store/add-to-collection/add-to-collection.state.ts @@ -15,7 +15,6 @@ import { GetCollectionLicenses, GetCurrentCollectionSubmission, RemoveCollectionSubmission, - UpdateCollectionSubmission, } from './add-to-collection.actions'; import { ADD_TO_COLLECTION_DEFAULTS, AddToCollectionStateModel } from './add-to-collection.model'; @@ -56,8 +55,8 @@ export class AddToCollectionState { getCurrentCollectionSubmission(ctx: StateContext, action: GetCurrentCollectionSubmission) { const state = ctx.getState(); ctx.patchState({ - collectionLicenses: { - ...state.collectionLicenses, + currentProjectSubmission: { + ...state.currentProjectSubmission, isLoading: true, }, }); @@ -81,11 +80,6 @@ export class AddToCollectionState { return this.addToCollectionService.createCollectionSubmission(action.metadata); } - @Action(UpdateCollectionSubmission) - updateCollectionSubmission(ctx: StateContext, action: UpdateCollectionSubmission) { - return this.addToCollectionService.updateCollectionSubmission(action.metadata); - } - @Action(RemoveCollectionSubmission) removeCollectionSubmission(ctx: StateContext, action: RemoveCollectionSubmission) { return this.addToCollectionService.removeCollectionSubmission(action.payload); diff --git a/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.html b/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.html index d7a384a20..67e98e8f0 100644 --- a/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.html +++ b/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.html @@ -31,13 +31,3 @@ > } - -@if (showAttributes()) { -
- @for (attribute of attributes(); track attribute.key) { -

- {{ attribute.label }}: {{ attribute.value }} -

- } -
-} diff --git a/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.spec.ts b/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.spec.ts index 1ed5237ae..7f0606a4a 100644 --- a/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.spec.ts +++ b/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.spec.ts @@ -37,30 +37,6 @@ describe('MetadataCollectionItemComponent', () => { expect(component.submission()).toEqual(mockSubmission); }); - it('should compute attributes from submission', () => { - const attributes = component.attributes(); - expect(attributes.length).toBeGreaterThan(0); - expect(attributes.some((attr) => attr.key === 'programArea' && attr.value === 'Science')).toBe(true); - expect(attributes.some((attr) => attr.key === 'collectedType' && attr.value === 'preprint')).toBe(true); - expect(attributes.some((attr) => attr.key === 'dataType' && attr.value === 'Quantitative')).toBe(true); - }); - - it('should filter out empty attributes', () => { - const submissionWithEmptyFields: CollectionSubmission = { - ...mockSubmission, - programArea: '', - disease: '', - gradeLevels: '', - }; - fixture.componentRef.setInput('submission', submissionWithEmptyFields); - fixture.detectChanges(); - - const attributes = component.attributes(); - expect(attributes.some((attr) => attr.key === 'programArea')).toBe(false); - expect(attributes.some((attr) => attr.key === 'disease')).toBe(false); - expect(attributes.some((attr) => attr.key === 'gradeLevels')).toBe(false); - }); - it('should toggle submission button visibility based on reviews state', () => { fixture.componentRef.setInput('submission', { ...mockSubmission, @@ -68,8 +44,7 @@ describe('MetadataCollectionItemComponent', () => { }); fixture.detectChanges(); - const submissionButtonVisible = fixture.nativeElement.querySelector('p-button[severity="secondary"]'); - expect(submissionButtonVisible).toBeTruthy(); + expect(component.showSubmissionButton()).toBe(true); fixture.componentRef.setInput('submission', { ...mockSubmission, @@ -77,15 +52,13 @@ describe('MetadataCollectionItemComponent', () => { }); fixture.detectChanges(); - const submissionButtonHidden = fixture.nativeElement.querySelector('p-button[severity="secondary"]'); - expect(submissionButtonHidden).toBeFalsy(); + expect(component.showSubmissionButton()).toBe(false); }); it('should switch submission button label for removed status', () => { fixture.componentRef.setInput('submission', { ...mockSubmission, - reviewsState: CollectionSubmissionReviewState.Accepted, - status: CollectionSubmissionReviewState.Removed, + reviewsState: CollectionSubmissionReviewState.Removed, }); fixture.detectChanges(); @@ -94,65 +67,14 @@ describe('MetadataCollectionItemComponent', () => { fixture.componentRef.setInput('submission', { ...mockSubmission, reviewsState: CollectionSubmissionReviewState.Accepted, - status: CollectionSubmissionReviewState.Accepted, }); fixture.detectChanges(); expect(component.submissionButtonLabel()).toBe('common.buttons.edit'); }); - it('should not display attributes section when all fields are empty', () => { - const submissionWithNoAttributes: CollectionSubmission = { - id: '1', - type: 'collection-submission', - collectionTitle: 'Test Collection', - collectionId: 'collection-123', - reviewsState: CollectionSubmissionReviewState.Pending, - collectedType: '', - status: '', - volume: '', - issue: '', - programArea: '', - schoolType: '', - studyDesign: '', - dataType: '', - disease: '', - gradeLevels: '', - }; - fixture.componentRef.setInput('submission', submissionWithNoAttributes); - fixture.detectChanges(); - - const attributes = component.attributes(); - expect(attributes.length).toBe(0); - - const attributesSection = fixture.nativeElement.querySelector('.flex.flex-column.gap-2.mt-2'); - expect(attributesSection).toBeFalsy(); - }); - - it('should hide attributes when reviews state is Removed even with data', () => { - fixture.componentRef.setInput('submission', { - ...mockSubmission, - reviewsState: CollectionSubmissionReviewState.Removed, - }); - fixture.detectChanges(); - - expect(component.attributes().length).toBeGreaterThan(0); - const attributesSection = fixture.nativeElement.querySelector('.flex.flex-column.gap-2.mt-2'); - expect(attributesSection).toBeFalsy(); - }); - describe('CEDAR mode', () => { - it('should not show cedar viewer when isCedarMode is false', () => { - fixture.componentRef.setInput('isCedarMode', false); - fixture.componentRef.setInput('cedarRecord', mockCedarRecord); - fixture.componentRef.setInput('cedarTemplate', mockCedarTemplate); - fixture.detectChanges(); - - expect(component.showCedarViewer()).toBe(false); - }); - it('should not show cedar viewer when cedarRecord is null', () => { - fixture.componentRef.setInput('isCedarMode', true); fixture.componentRef.setInput('cedarRecord', null); fixture.componentRef.setInput('cedarTemplate', mockCedarTemplate); fixture.detectChanges(); @@ -161,7 +83,6 @@ describe('MetadataCollectionItemComponent', () => { }); it('should not show cedar viewer when cedarTemplate is null', () => { - fixture.componentRef.setInput('isCedarMode', true); fixture.componentRef.setInput('cedarRecord', mockCedarRecord); fixture.componentRef.setInput('cedarTemplate', null); fixture.detectChanges(); @@ -169,8 +90,7 @@ describe('MetadataCollectionItemComponent', () => { expect(component.showCedarViewer()).toBe(false); }); - it('should show cedar viewer when isCedarMode, record, and template are provided', () => { - fixture.componentRef.setInput('isCedarMode', true); + it('should show cedar viewer when record and template are provided', () => { fixture.componentRef.setInput('cedarRecord', mockCedarRecord); fixture.componentRef.setInput('cedarTemplate', mockCedarTemplate); fixture.detectChanges(); @@ -179,7 +99,6 @@ describe('MetadataCollectionItemComponent', () => { }); it('should not show cedar viewer when submission is removed', () => { - fixture.componentRef.setInput('isCedarMode', true); fixture.componentRef.setInput('cedarRecord', mockCedarRecord); fixture.componentRef.setInput('cedarTemplate', mockCedarTemplate); fixture.componentRef.setInput('submission', { @@ -191,13 +110,6 @@ describe('MetadataCollectionItemComponent', () => { expect(component.showCedarViewer()).toBe(false); }); - it('should not show attributes in cedar mode', () => { - fixture.componentRef.setInput('isCedarMode', true); - fixture.detectChanges(); - - expect(component.showAttributes()).toBe(false); - }); - it('should compute cedarMetadata from record', () => { fixture.componentRef.setInput('cedarRecord', mockCedarRecord); fixture.detectChanges(); diff --git a/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.ts b/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.ts index c9d700248..d1d5d0967 100644 --- a/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.ts +++ b/src/app/features/metadata/components/metadata-collection-item/metadata-collection-item.component.ts @@ -13,12 +13,10 @@ import { } from '@angular/core'; import { RouterLink } from '@angular/router'; -import { collectionFilterNames } from '@osf/features/collections/constants'; import { CEDAR_VIEWER_CONFIG } from '@osf/features/metadata/constants'; import { CedarMetadataDataTemplateJsonApi, CedarMetadataRecordData } from '@osf/features/metadata/models'; import { CollectionSubmissionReviewState } from '@osf/shared/enums/collection-submission-review-state.enum'; import { CollectionSubmission } from '@osf/shared/models/collections/collections.model'; -import { KeyValueModel } from '@osf/shared/models/common/key-value.model'; import { CollectionStatusSeverityPipe } from '@osf/shared/pipes/collection-status-severity.pipe'; @Component({ @@ -34,7 +32,6 @@ export class MetadataCollectionItemComponent { readonly CollectionSubmissionReviewState = CollectionSubmissionReviewState; submission = input.required(); - isCedarMode = input(false); cedarRecord = input(null); cedarTemplate = input(null); @@ -42,21 +39,14 @@ export class MetadataCollectionItemComponent { showSubmissionButton = computed(() => this.submission().reviewsState === CollectionSubmissionReviewState.Accepted); - submissionButtonLabel = computed(() => { - const status = this.submission().status; - return status === CollectionSubmissionReviewState.Removed ? 'common.buttons.resubmit' : 'common.buttons.edit'; - }); - - showAttributes = computed( - () => - !this.isCedarMode() && - this.submission().reviewsState !== CollectionSubmissionReviewState.Removed && - !!this.attributes().length + submissionButtonLabel = computed(() => + this.submission().reviewsState === CollectionSubmissionReviewState.Removed + ? 'common.buttons.resubmit' + : 'common.buttons.edit' ); showCedarViewer = computed( () => - this.isCedarMode() && !!this.cedarRecord() && !!this.cedarTemplate()?.attributes?.template && this.submission().reviewsState !== CollectionSubmissionReviewState.Removed @@ -66,23 +56,4 @@ export class MetadataCollectionItemComponent { const record = this.cedarRecord(); return record?.attributes?.metadata ? (record.attributes.metadata as Record) : {}; }); - - attributes = computed(() => { - const submission = this.submission(); - const attributes: KeyValueModel[] = []; - - for (const filter of collectionFilterNames) { - const value = submission[filter.key as keyof CollectionSubmission]; - - if (value) { - attributes.push({ - key: filter.key, - label: filter.label, - value: String(value), - }); - } - } - - return attributes; - }); } diff --git a/src/app/features/metadata/components/metadata-collections/metadata-collections.component.html b/src/app/features/metadata/components/metadata-collections/metadata-collections.component.html index d9d0a0815..1707f59e9 100644 --- a/src/app/features/metadata/components/metadata-collections/metadata-collections.component.html +++ b/src/app/features/metadata/components/metadata-collections/metadata-collections.component.html @@ -11,7 +11,6 @@

{{ 'project.overview.metadata.collection' | translate }}

@for (submission of submissions; track submission.id) { diff --git a/src/app/features/metadata/components/metadata-collections/metadata-collections.component.spec.ts b/src/app/features/metadata/components/metadata-collections/metadata-collections.component.spec.ts index 9d446b991..e265cf615 100644 --- a/src/app/features/metadata/components/metadata-collections/metadata-collections.component.spec.ts +++ b/src/app/features/metadata/components/metadata-collections/metadata-collections.component.spec.ts @@ -64,10 +64,6 @@ describe('MetadataCollectionsComponent', () => { expect(content).toContain('project.overview.metadata.noCollections'); }); - it('should default isCedarMode to false', () => { - expect(component.isCedarMode()).toBe(false); - }); - it('should build cedarRecordByTemplateId map from records', () => { fixture.componentRef.setInput('cedarRecords', [mockCedarRecord]); fixture.detectChanges(); @@ -98,8 +94,7 @@ describe('MetadataCollectionsComponent', () => { expect(component.cedarTemplateById().size).toBe(0); }); - it('should pass matching cedarRecord to items in cedar mode', () => { - fixture.componentRef.setInput('isCedarMode', true); + it('should pass matching cedarRecord to items', () => { fixture.componentRef.setInput('projectSubmissions', mockSubmissionsWithTemplate); fixture.componentRef.setInput('cedarRecords', [mockCedarRecord]); fixture.componentRef.setInput('cedarTemplates', [mockCedarTemplate]); diff --git a/src/app/features/metadata/components/metadata-collections/metadata-collections.component.ts b/src/app/features/metadata/components/metadata-collections/metadata-collections.component.ts index 950d7e2ac..eb46f0dda 100644 --- a/src/app/features/metadata/components/metadata-collections/metadata-collections.component.ts +++ b/src/app/features/metadata/components/metadata-collections/metadata-collections.component.ts @@ -22,7 +22,6 @@ export class MetadataCollectionsComponent { isProjectSubmissionsLoading = input(false); cedarRecords = input(null); cedarTemplates = input(null); - isCedarMode = input(false); cedarRecordByTemplateId = computed(() => { const records = this.cedarRecords(); diff --git a/src/app/features/metadata/metadata.component.html b/src/app/features/metadata/metadata.component.html index e49c5490b..2605fc574 100644 --- a/src/app/features/metadata/metadata.component.html +++ b/src/app/features/metadata/metadata.component.html @@ -73,7 +73,6 @@ [isProjectSubmissionsLoading]="isProjectSubmissionsLoading()" [cedarRecords]="cedarRecords()" [cedarTemplates]="cedarTemplates()?.data ?? null" - [isCedarMode]="collectionSubmissionWithCedar" /> } diff --git a/src/app/features/metadata/metadata.component.ts b/src/app/features/metadata/metadata.component.ts index ef00699e8..ad6f68623 100644 --- a/src/app/features/metadata/metadata.component.ts +++ b/src/app/features/metadata/metadata.component.ts @@ -128,8 +128,6 @@ export class MetadataComponent implements OnInit, OnDestroy { private readonly environment = inject(ENVIRONMENT); private readonly signpostingService = inject(SignpostingService); - readonly collectionSubmissionWithCedar = this.environment.collectionSubmissionWithCedar; - private resourceId = ''; tabs = signal([]); diff --git a/src/app/features/moderation/components/collection-moderation-submissions/collection-moderation-submissions.component.ts b/src/app/features/moderation/components/collection-moderation-submissions/collection-moderation-submissions.component.ts index 8c86b6814..80da80c4b 100644 --- a/src/app/features/moderation/components/collection-moderation-submissions/collection-moderation-submissions.component.ts +++ b/src/app/features/moderation/components/collection-moderation-submissions/collection-moderation-submissions.component.ts @@ -15,14 +15,7 @@ import { LoadingSpinnerComponent } from '@osf/shared/components/loading-spinner/ import { SelectComponent } from '@osf/shared/components/select/select.component'; import { COLLECTION_SUBMISSIONS_SORT_OPTIONS } from '@osf/shared/constants/sort-options.const'; import { Primitive } from '@osf/shared/helpers/types.helper'; -import { - ClearCollections, - ClearCollectionSubmissions, - CollectionsSelectors, - GetCollectionDetails, - SearchCollectionSubmissions, - SetPageNumber, -} from '@osf/shared/stores/collections'; +import { CollectionsSelectors } from '@osf/shared/stores/collections'; import { COLLECTIONS_SUBMISSIONS_REVIEW_OPTIONS } from '../../constants'; import { SubmissionReviewStatus } from '../../enums'; @@ -72,23 +65,11 @@ export class CollectionModerationSubmissionsComponent { firstIndex = computed(() => (parseInt(this.currentPage()) - 1) * 10); actions = createDispatchMap({ - getCollectionDetails: GetCollectionDetails, - searchCollectionSubmissions: SearchCollectionSubmissions, getCollectionSubmissions: GetCollectionSubmissions, - setPageNumber: SetPageNumber, - clearCollections: ClearCollections, - clearCollectionsSubmissions: ClearCollectionSubmissions, getSubmissionsReviewActions: GetSubmissionsReviewActions, }); private setupEffects(): void { - effect(() => { - const collectionId = this.primaryCollectionId(); - if (collectionId) { - this.actions.getCollectionDetails(collectionId); - } - }); - effect(() => { const provider = this.collectionProvider(); const status = this.reviewStatus(); diff --git a/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.html b/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.html index e411a6cc2..f6b83afb9 100644 --- a/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.html +++ b/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.html @@ -1,7 +1,6 @@ @let action = currentReviewAction(); -@let attributes = currentSubmissionAttributes(); -@if (action && attributes) { +@if (action) {
@@ -46,17 +45,6 @@ {{ action.createdBy }}

-
- @for (attribute of attributes; track attribute.key) { - @if (!$first) { - | - } -

- {{ attribute.label }}: {{ attribute.value }} -

- } -
- @if (action.comment) { } diff --git a/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.spec.ts b/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.spec.ts index 612a93311..9d6f23010 100644 --- a/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.spec.ts +++ b/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.spec.ts @@ -90,39 +90,6 @@ describe('CollectionSubmissionItemComponent', () => { expect(currentAction).toBeNull(); }); - it('should compute current submission attributes correctly', () => { - fixture.componentRef.setInput('submission', mockSubmission); - fixture.detectChanges(); - - const attributes = component.currentSubmissionAttributes(); - expect(attributes).toBeDefined(); - expect(Array.isArray(attributes)).toBe(true); - }); - - it('should return attributes even when submission has no actions', () => { - const submissionWithoutActions = { ...mockSubmission, actions: [] }; - fixture.componentRef.setInput('submission', submissionWithoutActions); - fixture.detectChanges(); - - const attributes = component.currentSubmissionAttributes(); - expect(attributes).toBeDefined(); - expect(attributes).not.toBeNull(); - expect(Array.isArray(attributes)).toBe(true); - expect(attributes!.length).toBeGreaterThan(0); - }); - - it('should return attributes with filtered null values', () => { - const submissionWithNullFields = { ...mockSubmission, programArea: null, collectedType: null, dataType: null }; - fixture.componentRef.setInput('submission', submissionWithNullFields); - fixture.detectChanges(); - - const attributes = component.currentSubmissionAttributes(); - expect(attributes).toBeDefined(); - expect(attributes).not.toBeNull(); - expect(Array.isArray(attributes)).toBe(true); - expect(attributes!.length).toBeGreaterThan(0); - }); - it('should have SubmissionReviewStatus enum available', () => { expect(component.SubmissionReviewStatus).toBe(SubmissionReviewStatus); }); diff --git a/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.ts b/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.ts index a1d475ac1..013686142 100644 --- a/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.ts +++ b/src/app/features/moderation/components/collection-submission-item/collection-submission-item.component.ts @@ -8,7 +8,6 @@ import { Button } from 'primeng/button'; import { ChangeDetectionStrategy, Component, computed, inject, input, output } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { collectionFilterNames } from '@osf/features/collections/constants'; import { ContributorsListComponent } from '@osf/shared/components/contributors-list/contributors-list.component'; import { IconComponent } from '@osf/shared/components/icon/icon.component'; import { TruncatedTextComponent } from '@osf/shared/components/truncated-text/truncated-text.component'; @@ -57,18 +56,6 @@ export class CollectionSubmissionItemComponent { return actions[0]; }); - currentSubmissionAttributes = computed(() => { - const item = this.submission(); - if (!item) return null; - - return collectionFilterNames - .map((attribute) => ({ - ...attribute, - value: item[attribute.key as keyof CollectionSubmissionWithGuid] as string, - })) - .filter((attribute) => attribute.value); - }); - hasMoreContributors = computed(() => { const submission = this.submission(); if (submission.contributors && submission.totalContributors) { diff --git a/src/app/features/project/overview/components/overview-collections/overview-collections.component.html b/src/app/features/project/overview/components/overview-collections/overview-collections.component.html index 5a18e2d72..026620fe9 100644 --- a/src/app/features/project/overview/components/overview-collections/overview-collections.component.html +++ b/src/app/features/project/overview/components/overview-collections/overview-collections.component.html @@ -8,41 +8,18 @@

{{ 'project.overview.metadata.collection' | translate }}

@if (submissions?.length) { @for (submission of submissions; track submission.id) { -