Skip to content

Commit bfd5bc9

Browse files
authored
Merge pull request #1011 from Vlad0n20/fix/ENG-11358
fix(ENG-11358): show cedar metadata in collection accordion on projec…
2 parents 5905b79 + dc90c66 commit bfd5bc9

6 files changed

Lines changed: 150 additions & 10 deletions

File tree

src/app/features/project/overview/components/overview-collections/overview-collections.component.html

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,30 @@ <h3 class="mb-2">{{ 'project.overview.metadata.collection' | translate }}</h3>
2929
</p-accordion-header>
3030

3131
<p-accordion-content>
32-
@let attributes = getSubmissionAttributes(submission);
32+
@let templateId = submission.requiredMetadataTemplateId ?? '';
33+
@let cedarRecord = cedarRecordByTemplateId().get(templateId) ?? null;
34+
@let cedarTemplate = cedarTemplateById().get(templateId) ?? null;
3335

34-
@if (attributes.length) {
35-
<div class="flex flex-column gap-2 mt-2">
36-
@for (attribute of attributes; track attribute.key) {
37-
<p class="font-normal">
38-
<span class="font-bold">{{ attribute.label }}:</span> {{ attribute.value }}
39-
</p>
40-
}
36+
@if (isCedarMode() && cedarRecord && cedarTemplate?.attributes?.template) {
37+
<div class="mt-2">
38+
<cedar-artifact-viewer
39+
[config]="cedarViewerConfig"
40+
[templateObject]="cedarTemplate!.attributes.template"
41+
[instanceObject]="cedarRecord.attributes.metadata"
42+
></cedar-artifact-viewer>
4143
</div>
44+
} @else {
45+
@let attributes = getSubmissionAttributes(submission);
46+
47+
@if (attributes.length) {
48+
<div class="flex flex-column gap-2 mt-2">
49+
@for (attribute of attributes; track attribute.key) {
50+
<p class="font-normal">
51+
<span class="font-bold">{{ attribute.label }}:</span> {{ attribute.value }}
52+
</p>
53+
}
54+
</div>
55+
}
4256
}
4357
</p-accordion-content>
4458
</p-accordion-panel>

src/app/features/project/overview/components/overview-collections/overview-collections.component.spec.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
22
import { provideRouter } from '@angular/router';
33

44
import { collectionFilterNames } from '@osf/features/collections/constants';
5+
import { CedarMetadataDataTemplateJsonApi, CedarMetadataRecordData } from '@osf/features/metadata/models';
56
import { CollectionSubmission } from '@osf/shared/models/collections/collections.model';
67

8+
import { CEDAR_METADATA_DATA_TEMPLATE_JSON_API_MOCK } from '@testing/mocks/cedar-metadata-data-template-json-api.mock';
9+
import { MOCK_CEDAR_METADATA_RECORD_DATA } from '@testing/mocks/cedar-metadata-record.mock';
710
import {
811
MOCK_COLLECTION_SUBMISSION_EMPTY_FILTERS,
912
MOCK_COLLECTION_SUBMISSION_SINGLE_FILTER,
@@ -92,4 +95,74 @@ describe('OverviewCollectionsComponent', () => {
9295
expect(statusAttr?.value).toBe('1');
9396
expect(typeof statusAttr?.value).toBe('string');
9497
});
98+
99+
it('should render cedar-artifact-viewer when isCedarMode is true with matching record and template', async () => {
100+
const cedarSubmission: CollectionSubmission = {
101+
...MOCK_COLLECTION_SUBMISSION_EMPTY_FILTERS,
102+
requiredMetadataTemplateId: 'template-1',
103+
};
104+
const cedarRecord: CedarMetadataRecordData = MOCK_CEDAR_METADATA_RECORD_DATA;
105+
const cedarTemplate: CedarMetadataDataTemplateJsonApi =
106+
CEDAR_METADATA_DATA_TEMPLATE_JSON_API_MOCK as CedarMetadataDataTemplateJsonApi;
107+
108+
fixture.componentRef.setInput('projectSubmissions', [cedarSubmission]);
109+
fixture.componentRef.setInput('isCedarMode', true);
110+
fixture.componentRef.setInput('cedarRecords', [cedarRecord]);
111+
fixture.componentRef.setInput('cedarTemplates', [cedarTemplate]);
112+
fixture.detectChanges();
113+
await fixture.whenStable();
114+
115+
const viewer = fixture.nativeElement.querySelector('cedar-artifact-viewer');
116+
expect(viewer).toBeTruthy();
117+
});
118+
119+
it('should not render cedar-artifact-viewer when isCedarMode is false', async () => {
120+
const cedarSubmission: CollectionSubmission = {
121+
...MOCK_COLLECTION_SUBMISSION_WITH_FILTERS,
122+
requiredMetadataTemplateId: 'template-1',
123+
};
124+
const cedarRecord: CedarMetadataRecordData = MOCK_CEDAR_METADATA_RECORD_DATA;
125+
const cedarTemplate: CedarMetadataDataTemplateJsonApi =
126+
CEDAR_METADATA_DATA_TEMPLATE_JSON_API_MOCK as CedarMetadataDataTemplateJsonApi;
127+
128+
fixture.componentRef.setInput('projectSubmissions', [cedarSubmission]);
129+
fixture.componentRef.setInput('isCedarMode', false);
130+
fixture.componentRef.setInput('cedarRecords', [cedarRecord]);
131+
fixture.componentRef.setInput('cedarTemplates', [cedarTemplate]);
132+
fixture.detectChanges();
133+
await fixture.whenStable();
134+
135+
const viewer = fixture.nativeElement.querySelector('cedar-artifact-viewer');
136+
expect(viewer).toBeNull();
137+
});
138+
139+
it('should show traditional attributes when isCedarMode is true but no matching record', async () => {
140+
const cedarSubmission: CollectionSubmission = {
141+
...MOCK_COLLECTION_SUBMISSION_WITH_FILTERS,
142+
requiredMetadataTemplateId: 'non-existent-template',
143+
};
144+
145+
fixture.componentRef.setInput('projectSubmissions', [cedarSubmission]);
146+
fixture.componentRef.setInput('isCedarMode', true);
147+
fixture.componentRef.setInput('cedarRecords', []);
148+
fixture.componentRef.setInput('cedarTemplates', []);
149+
fixture.detectChanges();
150+
await fixture.whenStable();
151+
152+
const viewer = fixture.nativeElement.querySelector('cedar-artifact-viewer');
153+
expect(viewer).toBeNull();
154+
expect(component.getSubmissionAttributes(cedarSubmission).length).toBeGreaterThan(0);
155+
});
156+
157+
it('should compute empty cedarRecordByTemplateId map when cedarRecords is null', () => {
158+
fixture.componentRef.setInput('cedarRecords', null);
159+
fixture.detectChanges();
160+
expect(component.cedarRecordByTemplateId().size).toBe(0);
161+
});
162+
163+
it('should compute empty cedarTemplateById map when cedarTemplates is null', () => {
164+
fixture.componentRef.setInput('cedarTemplates', null);
165+
fixture.detectChanges();
166+
expect(component.cedarTemplateById().size).toBe(0);
167+
});
95168
});

src/app/features/project/overview/components/overview-collections/overview-collections.component.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,19 @@ import { Button } from 'primeng/button';
55
import { Skeleton } from 'primeng/skeleton';
66
import { Tag } from 'primeng/tag';
77

8-
import { ChangeDetectionStrategy, Component, input } from '@angular/core';
8+
import {
9+
ChangeDetectionStrategy,
10+
Component,
11+
computed,
12+
CUSTOM_ELEMENTS_SCHEMA,
13+
input,
14+
ViewEncapsulation,
15+
} from '@angular/core';
916
import { RouterLink } from '@angular/router';
1017

1118
import { collectionFilterNames } from '@osf/features/collections/constants';
19+
import { CEDAR_VIEWER_CONFIG } from '@osf/features/metadata/constants';
20+
import { CedarMetadataDataTemplateJsonApi, CedarMetadataRecordData } from '@osf/features/metadata/models';
1221
import { StopPropagationDirective } from '@osf/shared/directives/stop-propagation.directive';
1322
import { CollectionSubmission } from '@osf/shared/models/collections/collections.model';
1423
import { KeyValueModel } from '@osf/shared/models/common/key-value.model';
@@ -32,10 +41,32 @@ import { CollectionStatusSeverityPipe } from '@osf/shared/pipes/collection-statu
3241
templateUrl: './overview-collections.component.html',
3342
styleUrl: './overview-collections.component.scss',
3443
changeDetection: ChangeDetectionStrategy.OnPush,
44+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
45+
encapsulation: ViewEncapsulation.None,
3546
})
3647
export class OverviewCollectionsComponent {
3748
projectSubmissions = input<CollectionSubmission[] | null>(null);
3849
isProjectSubmissionsLoading = input<boolean>(false);
50+
isCedarMode = input<boolean>(false);
51+
cedarRecords = input<CedarMetadataRecordData[] | null>(null);
52+
cedarTemplates = input<CedarMetadataDataTemplateJsonApi[] | null>(null);
53+
54+
cedarViewerConfig = CEDAR_VIEWER_CONFIG;
55+
56+
cedarRecordByTemplateId = computed(() => {
57+
const records = this.cedarRecords();
58+
return new Map(
59+
records?.flatMap((record) => {
60+
const templateId = record.relationships?.template?.data?.id;
61+
return templateId ? [[templateId, record] as const] : [];
62+
}) ?? []
63+
);
64+
});
65+
66+
cedarTemplateById = computed(() => {
67+
const templates = this.cedarTemplates();
68+
return new Map(templates?.map((t) => [t.id, t] as const) ?? []);
69+
});
3970

4071
getSubmissionAttributes(submission: CollectionSubmission): KeyValueModel[] {
4172
const attributes: KeyValueModel[] = [];

src/app/features/project/overview/components/project-overview-metadata/project-overview-metadata.component.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ <h3>{{ 'common.labels.affiliatedInstitutions' | translate }}</h3>
8383
<osf-overview-collections
8484
[projectSubmissions]="projectSubmissions()"
8585
[isProjectSubmissionsLoading]="isProjectSubmissionsLoading()"
86+
[isCedarMode]="isCedarMode()"
87+
[cedarRecords]="cedarRecords()"
88+
[cedarTemplates]="cedarTemplates()"
8689
></osf-overview-collections>
8790

8891
<div class="flex flex-column gap-2">

src/app/features/project/overview/components/project-overview-metadata/project-overview-metadata.component.spec.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { Mock } from 'vitest';
77
import { ComponentFixture, TestBed } from '@angular/core/testing';
88
import { Router } from '@angular/router';
99

10+
import { UserSelectors } from '@core/store/user';
11+
import { GetCedarMetadataRecords, GetCedarMetadataTemplates, MetadataSelectors } from '@osf/features/metadata/store';
1012
import { AffiliatedInstitutionsViewComponent } from '@osf/shared/components/affiliated-institutions-view/affiliated-institutions-view.component';
1113
import { ContributorsListComponent } from '@osf/shared/components/contributors-list/contributors-list.component';
1214
import { ResourceCitationsComponent } from '@osf/shared/components/resource-citations/resource-citations.component';
@@ -94,6 +96,9 @@ describe('ProjectOverviewMetadataComponent', () => {
9496
{ selector: ContributorsSelectors.hasMoreBibliographicContributors, value: false },
9597
{ selector: CollectionsSelectors.getCurrentProjectSubmissions, value: [] },
9698
{ selector: CollectionsSelectors.getCurrentProjectSubmissionsLoading, value: false },
99+
{ selector: UserSelectors.getActiveFlags, value: [] },
100+
{ selector: MetadataSelectors.getCedarRecords, value: [] },
101+
{ selector: MetadataSelectors.getCedarTemplates, value: null },
97102
],
98103
}),
99104
],
@@ -122,6 +127,8 @@ describe('ProjectOverviewMetadataComponent', () => {
122127
expect(dispatchMock).toHaveBeenCalledWith(new FetchSelectedSubjects('project-1', ResourceType.Project));
123128
expect(dispatchMock).toHaveBeenCalledWith(new GetProjectSubmissions('project-1'));
124129
expect(dispatchMock).toHaveBeenCalledWith(new GetProjectLicense(MOCK_PROJECT_OVERVIEW.licenseId));
130+
expect(dispatchMock).toHaveBeenCalledWith(new GetCedarMetadataRecords('project-1', ResourceType.Project));
131+
expect(dispatchMock).toHaveBeenCalledWith(new GetCedarMetadataTemplates());
125132
});
126133

127134
it('should not dispatch init actions when project is null', () => {

src/app/features/project/overview/components/project-overview-metadata/project-overview-metadata.component.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import { TranslatePipe } from '@ngx-translate/core';
55
import { Button } from 'primeng/button';
66

77
import { DatePipe } from '@angular/common';
8-
import { ChangeDetectionStrategy, Component, effect, inject } from '@angular/core';
8+
import { ChangeDetectionStrategy, Component, computed, effect, inject } from '@angular/core';
99
import { Router, RouterLink } from '@angular/router';
1010

11+
import { UserSelectors } from '@core/store/user';
12+
import { GetCedarMetadataRecords, GetCedarMetadataTemplates, MetadataSelectors } from '@osf/features/metadata/store';
1113
import { AffiliatedInstitutionsViewComponent } from '@osf/shared/components/affiliated-institutions-view/affiliated-institutions-view.component';
1214
import { ContributorsListComponent } from '@osf/shared/components/contributors-list/contributors-list.component';
1315
import { ResourceCitationsComponent } from '@osf/shared/components/resource-citations/resource-citations.component';
@@ -24,6 +26,7 @@ import {
2426
LoadMoreBibliographicContributors,
2527
} from '@osf/shared/stores/contributors';
2628
import { FetchSelectedSubjects, SubjectsSelectors } from '@osf/shared/stores/subjects';
29+
import { COLLECTION_SUBMISSION_WITH_CEDAR } from '@shared/constants/feature-flags.const';
2730

2831
import {
2932
GetProjectIdentifiers,
@@ -79,6 +82,11 @@ export class ProjectOverviewMetadataComponent {
7982
readonly hasMoreBibliographicContributors = select(ContributorsSelectors.hasMoreBibliographicContributors);
8083
readonly projectSubmissions = select(CollectionsSelectors.getCurrentProjectSubmissions);
8184
readonly isProjectSubmissionsLoading = select(CollectionsSelectors.getCurrentProjectSubmissionsLoading);
85+
readonly activeFlags = select(UserSelectors.getActiveFlags);
86+
readonly cedarRecords = select(MetadataSelectors.getCedarRecords);
87+
private readonly cedarTemplatesResponse = select(MetadataSelectors.getCedarTemplates);
88+
readonly cedarTemplates = computed(() => this.cedarTemplatesResponse()?.data ?? null);
89+
readonly isCedarMode = computed(() => this.activeFlags().includes(COLLECTION_SUBMISSION_WITH_CEDAR));
8290

8391
readonly resourceType = CurrentResourceType.Projects;
8492
readonly dateFormat = 'MMM d, y, h:mm a';
@@ -93,6 +101,8 @@ export class ProjectOverviewMetadataComponent {
93101
getProjectSubmissions: GetProjectSubmissions,
94102
getBibliographicContributors: GetBibliographicContributors,
95103
loadMoreBibliographicContributors: LoadMoreBibliographicContributors,
104+
getCedarRecords: GetCedarMetadataRecords,
105+
getCedarTemplates: GetCedarMetadataTemplates,
96106
});
97107

98108
constructor() {
@@ -107,6 +117,8 @@ export class ProjectOverviewMetadataComponent {
107117
this.actions.getSubjects(project.id, ResourceType.Project);
108118
this.actions.getProjectSubmissions(project.id);
109119
this.actions.getLicense(project.licenseId);
120+
this.actions.getCedarRecords(project.id, ResourceType.Project);
121+
this.actions.getCedarTemplates();
110122
}
111123
});
112124
}

0 commit comments

Comments
 (0)