Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
6d97d38
feat(ENG-9817): collection-specific metadata with cedar
Vlad0n20 Apr 21, 2026
ad9ed4a
feat(ENG-9817): fix comments
Vlad0n20 Apr 23, 2026
7029905
feat(ENG-9817): fix comment
Vlad0n20 Apr 23, 2026
29d3897
Merge pull request #963 from Vlad0n20/feat/ENG-9817
adlius Apr 28, 2026
874450f
feat(ENG-9818): collection search with shtrove and cedar filters
Vlad0n20 Apr 28, 2026
d45a69a
feat(ENG-9818): fix comments
Vlad0n20 Apr 29, 2026
3eef635
Merge pull request #970 from Vlad0n20/feat/ENG-9818
adlius Apr 29, 2026
3c8de43
chore(merge): merge develop into feature/es2-consolidation, resolve c…
Vlad0n20 May 13, 2026
3ebca0f
feat(ENG-9827): fix tests
Vlad0n20 May 13, 2026
d67e972
Merge pull request #991 from Vlad0n20/merge/es2-consolidation-with-de…
adlius May 13, 2026
bec9447
fix(ENG-9821): fix
Vlad0n20 Apr 30, 2026
694534e
feat(ENG-9827): remove frontend cedar pre-save from collection submis…
Vlad0n20 May 12, 2026
b7ca8c3
feat(ENG-9827): fix comments
Vlad0n20 May 14, 2026
7c3cee1
feat(ENG-9827): fix tests
Vlad0n20 May 14, 2026
d198ac4
Merge pull request #988 from Vlad0n20/feat/ENG-9827
adlius May 18, 2026
ab21476
Merge pull request #997 from CenterForOpenScience/develop
adlius May 27, 2026
b86b57e
Revert "Merge pull request #988 from Vlad0n20/feat/ENG-9827"
adlius May 22, 2026
323a6a1
feat(es2): Add waffle flags; revert changes and use cedar editor
adlius May 27, 2026
4655dae
feat(ENG-9827): fix conflicts
Vlad0n20 May 29, 2026
7a6dad9
feat(ENG-9827): fix comments
Vlad0n20 May 29, 2026
07759e1
Merge pull request #1000 from Vlad0n20/feat/ENG-9827
adlius Jun 2, 2026
c3ed5b8
feat(es2): Fix licenses
adlius Jun 2, 2026
527c175
Merge pull request #1002 from adlius/fix-licenses
adlius Jun 2, 2026
876ee5f
feat(es2): Fix search
adlius Jun 3, 2026
a408a54
Merge pull request #1003 from adlius/fix-search
adlius Jun 3, 2026
42eb015
feat(es2): fix search page again
adlius Jun 3, 2026
50c5984
feat(es2): Fix tests
adlius Jun 3, 2026
af7caca
Merge pull request #1004 from adlius/fix-search
adlius Jun 4, 2026
70a3871
feat(es2): Fix collection discover page facet
adlius Jun 4, 2026
fc98d72
feat(es2): CR followup
adlius Jun 5, 2026
c9fb260
Merge pull request #1006 from adlius/fix-discover-page-facet
adlius Jun 5, 2026
c38c894
feat(es2): Only show non-cedar templates when adding metadata
adlius Jun 8, 2026
e34005e
feat(es2): Fix tests
adlius Jun 8, 2026
42df5f5
feat(es2): revert query param
adlius Jun 9, 2026
bed1c91
feat(es2): Add filter and tests
adlius Jun 9, 2026
e751ae8
Merge pull request #1007 from adlius/fix-add-metadata-page
adlius Jun 11, 2026
23b9cae
Merge pull request #1008 from adlius/fix-only-public-project-collection
adlius Jun 11, 2026
cff3b4e
feat(ENG-11333): fix selected filters from overriding default filters
Vlad0n20 Jun 12, 2026
dc90c66
fix(ENG-11358): show cedar metadata in collection accordion on projec…
Vlad0n20 Jun 12, 2026
95830e5
fix(ENG-11346): show placeholder in cedar-derived filter dropdowns
Vlad0n20 Jun 15, 2026
f0167e6
fix(ENG-11346): use nullish coalescing operator
Vlad0n20 Jun 15, 2026
5905b79
Merge pull request #1010 from Vlad0n20/fix/ENG-11333
adlius Jun 16, 2026
bfd5bc9
Merge pull request #1011 from Vlad0n20/fix/ENG-11358
adlius Jun 16, 2026
0baaaba
Merge pull request #1013 from Vlad0n20/fix/ENG-11346
adlius Jun 16, 2026
2a23aec
feat(es2): Fix overview page dropdown
adlius Jun 17, 2026
1213c90
fix(ENG-11333): fix single value filtering
Vlad0n20 Jun 17, 2026
d5315bf
feat(es2): Get rid of artifact viewer
adlius Jun 17, 2026
c2b7237
feat(es2): update tests
adlius Jun 17, 2026
3930350
Merge pull request #1017 from Vlad0n20/fix/ENG-11333
adlius Jun 17, 2026
83db19d
Merge pull request #1016 from adlius/fix-overview-collection-dropdown
adlius Jun 17, 2026
c5e6606
Merge remote-tracking branch 'upstream/develop' into feature/es2-cons…
adlius Jun 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import { of, throwError } from 'rxjs';
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { CreateCollectionSubmission } from '@osf/features/collections/store/add-to-collection/add-to-collection.actions';
import { CedarMetadataAttributes, CedarRecordDataBinding } from '@osf/features/metadata/models';
import { CreateCedarMetadataRecord } from '@osf/features/metadata/store';
import { UpdateProjectPublicStatus } from '@osf/features/project/overview/store';
import { ResourceType } from '@osf/shared/enums/resource-type.enum';
import { CollectionSubmissionPayload } from '@osf/shared/models/collections/collection-submission-payload.model';
import { ToastService } from '@osf/shared/services/toast.service';

import { provideOSFCore } from '@testing/osf.testing.provider';
Expand All @@ -19,20 +23,39 @@ import { ToastServiceMock, ToastServiceMockType } from '@testing/providers/toast

import { AddToCollectionConfirmationDialogComponent } from './add-to-collection-confirmation-dialog.component';

const MOCK_CEDAR_DATA: CedarRecordDataBinding = {
data: { '@context': {} } as CedarMetadataAttributes,
id: 'template-1',
isPublished: true,
};

describe('AddToCollectionConfirmationDialogComponent', () => {
let component: AddToCollectionConfirmationDialogComponent;
let fixture: ComponentFixture<AddToCollectionConfirmationDialogComponent>;
let store: Store;
let dialogRef: DynamicDialogRef;
let toastService: ToastServiceMockType;
let dialogConfig: { data: { payload?: unknown; project?: { id: string; isPublic: boolean } } };
let dialogConfig: {
data: {
payload?: CollectionSubmissionPayload;
project?: { id: string; isPublic: boolean };
cedarData?: CedarRecordDataBinding | null;
};
};

const MOCK_PAYLOAD: CollectionSubmissionPayload = {
collectionId: 'collection-1',
projectId: 'project-1',
userId: 'user-1',
};

beforeEach(() => {
toastService = ToastServiceMock.simple();
dialogConfig = {
data: {
payload: { title: 'Submission' },
payload: MOCK_PAYLOAD,
project: { id: 'project-1', isPublic: false },
cedarData: null,
},
};

Expand Down Expand Up @@ -69,13 +92,14 @@ describe('AddToCollectionConfirmationDialogComponent', () => {
expect(toastService.showSuccess).not.toHaveBeenCalled();
});

it('should update project public status and create submission when project is private', () => {
it('should update project public status then create submission when project is private and no Cedar data', () => {
vi.spyOn(store, 'dispatch').mockReturnValue(of(void 0));

component.handleAddToCollectionConfirm();

expect(store.dispatch).toHaveBeenCalledWith(new UpdateProjectPublicStatus([{ id: 'project-1', public: true }]));
expect(store.dispatch).toHaveBeenCalledWith(new CreateCollectionSubmission({ title: 'Submission' } as any));
expect(store.dispatch).toHaveBeenCalledWith(new CreateCollectionSubmission(MOCK_PAYLOAD));
expect(store.dispatch).not.toHaveBeenCalledWith(expect.any(CreateCedarMetadataRecord));
expect(dialogRef.close).toHaveBeenCalledWith(true);
expect(toastService.showSuccess).toHaveBeenCalledWith('collections.addToCollection.confirmationDialogToastMessage');
expect(component.isSubmitting()).toBe(false);
Expand All @@ -87,11 +111,34 @@ describe('AddToCollectionConfirmationDialogComponent', () => {

component.handleAddToCollectionConfirm();

expect(store.dispatch).toHaveBeenCalledWith(new CreateCollectionSubmission({ title: 'Submission' } as any));
expect(store.dispatch).toHaveBeenCalledWith(new CreateCollectionSubmission(MOCK_PAYLOAD));
expect(store.dispatch).not.toHaveBeenCalledWith(expect.any(UpdateProjectPublicStatus));
expect(dialogRef.close).toHaveBeenCalledWith(true);
});

it('should create Cedar record before submission when cedarData is present', () => {
dialogConfig.data.cedarData = MOCK_CEDAR_DATA;
vi.spyOn(store, 'dispatch').mockReturnValue(of(void 0));

component.handleAddToCollectionConfirm();

expect(store.dispatch).toHaveBeenCalledWith(
new CreateCedarMetadataRecord(MOCK_CEDAR_DATA, 'project-1', ResourceType.Project)
);
expect(store.dispatch).toHaveBeenCalledWith(new CreateCollectionSubmission(MOCK_PAYLOAD));
expect(dialogRef.close).toHaveBeenCalledWith(true);
});

it('should not create Cedar record when cedarData is null', () => {
dialogConfig.data.cedarData = null;
vi.spyOn(store, 'dispatch').mockReturnValue(of(void 0));

component.handleAddToCollectionConfirm();

expect(store.dispatch).not.toHaveBeenCalledWith(expect.any(CreateCedarMetadataRecord));
expect(store.dispatch).toHaveBeenCalledWith(new CreateCollectionSubmission(MOCK_PAYLOAD));
});

it('should reset submitting state on error', () => {
vi.spyOn(store, 'dispatch').mockImplementation((action) => {
if (action instanceof CreateCollectionSubmission) {
Expand All @@ -106,4 +153,20 @@ describe('AddToCollectionConfirmationDialogComponent', () => {
expect(dialogRef.close).not.toHaveBeenCalled();
expect(toastService.showSuccess).not.toHaveBeenCalled();
});

it('should reset submitting state on Cedar record creation error', () => {
dialogConfig.data.cedarData = MOCK_CEDAR_DATA;
vi.spyOn(store, 'dispatch').mockImplementation((action) => {
if (action instanceof CreateCedarMetadataRecord) {
return throwError(() => new Error('cedar fail'));
}
return of(void 0);
});

component.handleAddToCollectionConfirm();

expect(component.isSubmitting()).toBe(false);
expect(dialogRef.close).not.toHaveBeenCalled();
expect(toastService.showSuccess).not.toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ import { TranslatePipe } from '@ngx-translate/core';
import { Button } from 'primeng/button';
import { DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';

import { forkJoin, of } from 'rxjs';
import { Observable, of, switchMap } from 'rxjs';

import { ChangeDetectionStrategy, Component, DestroyRef, inject, signal } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';

import { CreateCollectionSubmission } from '@osf/features/collections/store/add-to-collection/add-to-collection.actions';
import { CedarRecordDataBinding } from '@osf/features/metadata/models';
import { CreateCedarMetadataRecord } from '@osf/features/metadata/store';
import { UpdateProjectPublicStatus } from '@osf/features/project/overview/store';
import { ResourceType } from '@osf/shared/enums/resource-type.enum';
import { ToastService } from '@osf/shared/services/toast.service';

@Component({
Expand All @@ -30,26 +33,33 @@ export class AddToCollectionConfirmationDialogComponent {
actions = createDispatchMap({
createCollectionSubmission: CreateCollectionSubmission,
updateProjectPublicStatus: UpdateProjectPublicStatus,
createCedarRecord: CreateCedarMetadataRecord,
});

handleAddToCollectionConfirm(): void {
const payload = this.config.data.payload;
const project = this.config.data.project;
const cedarData = this.config.data.cedarData as CedarRecordDataBinding | null | undefined;

if (!payload || !project) return;

this.isSubmitting.set(true);
const projectPayload = [{ id: project.id as string, public: true }];

const updatePublicStatus$ = project.isPublic ? of(null) : this.actions.updateProjectPublicStatus(projectPayload);
const updatePublicStatus$: Observable<unknown> = project.isPublic
? of(null)
: this.actions.updateProjectPublicStatus(projectPayload);

const createSubmission$ = this.actions.createCollectionSubmission(payload);
const createCedar$: Observable<unknown> = cedarData
? this.actions.createCedarRecord(cedarData, project.id as string, ResourceType.Project)
: of(null);

forkJoin({
publicStatusUpdate: updatePublicStatus$,
collectionSubmission: createSubmission$,
})
.pipe(takeUntilDestroyed(this.destroyRef))
updatePublicStatus$
.pipe(
switchMap(() => createCedar$),
switchMap(() => this.actions.createCollectionSubmission(payload)),
takeUntilDestroyed(this.destroyRef)
)
.subscribe({
next: () => {
this.isSubmitting.set(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ <h1 class="collections-heading flex align-items-center">{{ collectionProvider()?
[targetStepValue]="AddToCollectionSteps.CollectionMetadata"
[isDisabled]="isCollectionMetadataDisabled()"
[primaryCollectionId]="primaryCollectionId()"
[isCedarMode]="isCedarMode()"
[cedarTemplate]="requiredMetadataTemplate()"
[existingCedarRecord]="existingCedarRecord()"
(metadataSaved)="handleCollectionMetadataSaved($event)"
(cedarDataSaved)="handleCedarDataSaved($event)"
(stepChange)="handleChangeStep($event)"
/>
</p-stepper>
Expand Down
Loading
Loading