diff --git a/src/app/core/constants/ngxs-states.constant.ts b/src/app/core/constants/ngxs-states.constant.ts
index c16df5cb4..1454fd718 100644
--- a/src/app/core/constants/ngxs-states.constant.ts
+++ b/src/app/core/constants/ngxs-states.constant.ts
@@ -8,7 +8,8 @@ import { RegistrationsState } from '@osf/features/project/registrations/store';
import { AccountSettingsState } from '@osf/features/settings/account-settings/store/account-settings.state';
import { DeveloperAppsState } from '@osf/features/settings/developer-apps/store';
import { NotificationSubscriptionState } from '@osf/features/settings/notifications/store';
-import { AddonsState, InstitutionsState, WikiState } from '@osf/shared/stores';
+import { AddonsState, WikiState } from '@osf/shared/stores';
+import { InstitutionsState } from '@shared/stores/institutions';
import { LicensesState } from '@shared/stores/licenses';
import { MyResourcesState } from '@shared/stores/my-resources';
import { RegionsState } from '@shared/stores/regions';
diff --git a/src/app/features/home/pages/dashboard/dashboard.component.ts b/src/app/features/home/pages/dashboard/dashboard.component.ts
index 66608b15f..a36a91d20 100644
--- a/src/app/features/home/pages/dashboard/dashboard.component.ts
+++ b/src/app/features/home/pages/dashboard/dashboard.component.ts
@@ -21,7 +21,7 @@ import { MY_PROJECTS_TABLE_PARAMS } from '@osf/shared/constants';
import { SortOrder } from '@osf/shared/enums';
import { IS_MEDIUM } from '@osf/shared/helpers';
import { MyResourcesItem, MyResourcesSearchFilters, TableParameters } from '@osf/shared/models';
-import { ClearMyResources, FetchUserInstitutions, GetMyProjects, MyResourcesSelectors } from '@shared/stores';
+import { ClearMyResources, GetMyProjects, MyResourcesSelectors } from '@shared/stores';
import { ConfirmEmailComponent } from '../../components';
@@ -73,7 +73,6 @@ export class DashboardComponent implements OnInit {
ngOnInit() {
this.setupQueryParamsSubscription();
- this.store.dispatch(new FetchUserInstitutions());
this.route.params.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((params) => {
const userId = params['userId'];
diff --git a/src/app/features/institutions/pages/institutions-list/institutions-list.component.ts b/src/app/features/institutions/pages/institutions-list/institutions-list.component.ts
index b0adeb8e9..07ea9fbc9 100644
--- a/src/app/features/institutions/pages/institutions-list/institutions-list.component.ts
+++ b/src/app/features/institutions/pages/institutions-list/institutions-list.component.ts
@@ -30,7 +30,7 @@ import {
import { TABLE_PARAMS } from '@shared/constants';
import { parseQueryFilterParams } from '@shared/helpers';
import { QueryParams } from '@shared/models';
-import { FetchInstitutions, InstitutionsSelectors } from '@shared/stores';
+import { FetchInstitutions, InstitutionsSelectors } from '@shared/stores/institutions';
@Component({
selector: 'osf-institutions-list',
diff --git a/src/app/features/preprints/components/preprint-details/general-information/general-information.component.html b/src/app/features/preprints/components/preprint-details/general-information/general-information.component.html
index 5b4ea4c1e..acc12f774 100644
--- a/src/app/features/preprints/components/preprint-details/general-information/general-information.component.html
+++ b/src/app/features/preprints/components/preprint-details/general-information/general-information.component.html
@@ -8,15 +8,7 @@
{{ 'preprints.preprintStepper.common.labels.abstract' | translate }}
@if (affiliatedInstitutions().length) {
-
- {{ 'preprints.preprintStepper.review.sections.metadata.affiliatedInstitutions' | translate }}
-
-
- @for (institution of affiliatedInstitutions(); track institution.id) {
-
![Institution logo]()
- }
-
-
+
}
@if (preprintValue.nodeId) {
diff --git a/src/app/features/preprints/components/preprint-details/general-information/general-information.component.ts b/src/app/features/preprints/components/preprint-details/general-information/general-information.component.ts
index 757e4d53e..a4a2a176c 100644
--- a/src/app/features/preprints/components/preprint-details/general-information/general-information.component.ts
+++ b/src/app/features/preprints/components/preprint-details/general-information/general-information.component.ts
@@ -5,7 +5,7 @@ import { TranslatePipe } from '@ngx-translate/core';
import { Card } from 'primeng/card';
import { Skeleton } from 'primeng/skeleton';
-import { ChangeDetectionStrategy, Component, computed, effect, input, OnDestroy, output, signal } from '@angular/core';
+import { ChangeDetectionStrategy, Component, computed, effect, input, OnDestroy, output } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RouterLink } from '@angular/router';
@@ -13,10 +13,10 @@ import { PreprintDoiSectionComponent } from '@osf/features/preprints/components/
import { ApplicabilityStatus, PreregLinkInfo } from '@osf/features/preprints/enums';
import { PreprintProviderDetails } from '@osf/features/preprints/models';
import { FetchPreprintById, PreprintSelectors } from '@osf/features/preprints/store/preprint';
-import { IconComponent, TruncatedTextComponent } from '@shared/components';
+import { AffiliatedInstitutionsViewComponent, IconComponent, TruncatedTextComponent } from '@shared/components';
import { ResourceType } from '@shared/enums';
-import { Institution } from '@shared/models';
import { ContributorsSelectors, GetAllContributors, ResetContributorsState } from '@shared/stores';
+import { FetchResourceInstitutions, InstitutionsSelectors } from '@shared/stores/institutions';
import { environment } from 'src/environments/environment';
@@ -31,6 +31,7 @@ import { environment } from 'src/environments/environment';
PreprintDoiSectionComponent,
RouterLink,
IconComponent,
+ AffiliatedInstitutionsViewComponent,
],
templateUrl: './general-information.component.html',
styleUrl: './general-information.component.scss',
@@ -44,6 +45,7 @@ export class GeneralInformationComponent implements OnDestroy {
getContributors: GetAllContributors,
resetContributorsState: ResetContributorsState,
fetchPreprintById: FetchPreprintById,
+ fetchResourceInstitutions: FetchResourceInstitutions,
});
protected readonly environment = environment;
@@ -53,8 +55,7 @@ export class GeneralInformationComponent implements OnDestroy {
preprint = select(PreprintSelectors.getPreprint);
isPreprintLoading = select(PreprintSelectors.isPreprintLoading);
- //[RNi] TODO: Implement when institutions available
- affiliatedInstitutions = signal([]);
+ affiliatedInstitutions = select(InstitutionsSelectors.getResourceInstitutions);
contributors = select(ContributorsSelectors.getContributors);
areContributorsLoading = select(ContributorsSelectors.isContributorsLoading);
@@ -74,6 +75,7 @@ export class GeneralInformationComponent implements OnDestroy {
if (!preprint) return;
this.actions.getContributors(this.preprint()!.id, ResourceType.Preprint);
+ this.actions.fetchResourceInstitutions(this.preprint()!.id, ResourceType.Preprint);
});
}
diff --git a/src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.html b/src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.html
index a7538e5eb..e5a5af081 100644
--- a/src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.html
+++ b/src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.html
@@ -41,6 +41,10 @@ {{ 'preprints.preprintStepper.metadata.publicationDoi.title' | translate }}<
+
+
+
+
diff --git a/src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.ts b/src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.ts
index bb3372240..be4dc02d2 100644
--- a/src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.ts
+++ b/src/app/features/preprints/components/stepper/metadata-step/metadata-step.component.ts
@@ -9,12 +9,11 @@ import { InputText } from 'primeng/inputtext';
import { Message } from 'primeng/message';
import { Tooltip } from 'primeng/tooltip';
-import { ChangeDetectionStrategy, Component, inject, OnInit, output } from '@angular/core';
+import { ChangeDetectionStrategy, Component, inject, input, OnInit, output } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
-import { PreprintsSubjectsComponent } from '@osf/features/preprints/components/stepper/metadata-step/preprints-subjects/preprints-subjects.component';
import { formInputLimits } from '@osf/features/preprints/constants';
-import { MetadataForm, Preprint } from '@osf/features/preprints/models';
+import { MetadataForm, Preprint, PreprintProviderDetails } from '@osf/features/preprints/models';
import {
CreatePreprint,
FetchLicenses,
@@ -29,6 +28,8 @@ import { License, LicenseOptions } from '@shared/models';
import { CustomConfirmationService, ToastService } from '@shared/services';
import { ContributorsComponent } from './contributors/contributors.component';
+import { PreprintsAffiliatedInstitutionsComponent } from './preprints-affiliated-institutions/preprints-affiliated-institutions.component';
+import { PreprintsSubjectsComponent } from './preprints-subjects/preprints-subjects.component';
@Component({
selector: 'osf-preprint-metadata',
@@ -47,6 +48,7 @@ import { ContributorsComponent } from './contributors/contributors.component';
LicenseComponent,
TagsInputComponent,
PreprintsSubjectsComponent,
+ PreprintsAffiliatedInstitutionsComponent,
],
templateUrl: './metadata-step.component.html',
styleUrl: './metadata-step.component.scss',
@@ -71,6 +73,7 @@ export class MetadataStepComponent implements OnInit {
createdPreprint = select(PreprintStepperSelectors.getPreprint);
isUpdatingPreprint = select(PreprintStepperSelectors.isPreprintSubmitting);
+ provider = input.required();
nextClicked = output();
backClicked = output();
diff --git a/src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.html b/src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.html
new file mode 100644
index 000000000..513d64186
--- /dev/null
+++ b/src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.html
@@ -0,0 +1,18 @@
+
+
+
{{ 'preprints.preprintStepper.metadata.affiliatedInstitutionsTitle' | translate }}
+
+ {{
+ 'preprints.preprintStepper.metadata.affiliatedInstitutionsDescription'
+ | translate: { preprintWord: provider()?.preprintWord }
+ }}
+
+
+
+
+
+
+
diff --git a/src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.scss b/src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.spec.ts b/src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.spec.ts
new file mode 100644
index 000000000..031eda263
--- /dev/null
+++ b/src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.spec.ts
@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PreprintsAffiliatedInstitutionsComponent } from './preprints-affiliated-institutions.component';
+
+describe.skip('PreprintsAffiliatedInstitutionsComponent', () => {
+ let component: PreprintsAffiliatedInstitutionsComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [PreprintsAffiliatedInstitutionsComponent],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(PreprintsAffiliatedInstitutionsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.ts b/src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.ts
new file mode 100644
index 000000000..bf64dbebb
--- /dev/null
+++ b/src/app/features/preprints/components/stepper/metadata-step/preprints-affiliated-institutions/preprints-affiliated-institutions.component.ts
@@ -0,0 +1,38 @@
+import { createDispatchMap } from '@ngxs/store';
+
+import { TranslatePipe } from '@ngx-translate/core';
+
+import { Card } from 'primeng/card';
+
+import { ChangeDetectionStrategy, Component, input, OnInit } from '@angular/core';
+
+import { PreprintProviderDetails } from '@osf/features/preprints/models';
+import { AffiliatedInstitutionSelectComponent } from '@shared/components';
+import { ResourceType } from '@shared/enums';
+import { Institution } from '@shared/models';
+import { FetchResourceInstitutions, UpdateResourceInstitutions } from '@shared/stores/institutions';
+
+@Component({
+ selector: 'osf-preprints-affiliated-institutions',
+ imports: [AffiliatedInstitutionSelectComponent, Card, TranslatePipe],
+ templateUrl: './preprints-affiliated-institutions.component.html',
+ styleUrl: './preprints-affiliated-institutions.component.scss',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class PreprintsAffiliatedInstitutionsComponent implements OnInit {
+ preprintId = input();
+ provider = input.required();
+
+ private actions = createDispatchMap({
+ fetchResourceInstitutions: FetchResourceInstitutions,
+ updateResourceInstitutions: UpdateResourceInstitutions,
+ });
+
+ ngOnInit() {
+ this.actions.fetchResourceInstitutions(this.preprintId()!, ResourceType.Preprint);
+ }
+
+ institutionsSelected(institutions: Institution[]) {
+ this.actions.updateResourceInstitutions(this.preprintId()!, ResourceType.Preprint, institutions);
+ }
+}
diff --git a/src/app/features/preprints/components/stepper/review-step/review-step.component.html b/src/app/features/preprints/components/stepper/review-step/review-step.component.html
index a1448ae20..42b38be03 100644
--- a/src/app/features/preprints/components/stepper/review-step/review-step.component.html
+++ b/src/app/features/preprints/components/stepper/review-step/review-step.component.html
@@ -63,15 +63,7 @@ {{ 'preprints.preprintStepper.review.sections.metadata.contributors' | trans
@if (affiliatedInstitutions().length) {
-
- {{ 'preprints.preprintStepper.review.sections.metadata.affiliatedInstitutions' | translate }}
-
-
- @for (institution of affiliatedInstitutions(); track institution.id) {
-
![Institution logo]()
- }
-
-
+
}
diff --git a/src/app/features/preprints/components/stepper/review-step/review-step.component.ts b/src/app/features/preprints/components/stepper/review-step/review-step.component.ts
index e4a131298..bb01c7d70 100644
--- a/src/app/features/preprints/components/stepper/review-step/review-step.component.ts
+++ b/src/app/features/preprints/components/stepper/review-step/review-step.component.ts
@@ -8,7 +8,7 @@ import { Card } from 'primeng/card';
import { Tag } from 'primeng/tag';
import { DatePipe, TitleCasePipe } from '@angular/common';
-import { ChangeDetectionStrategy, Component, computed, inject, input, OnInit, signal } from '@angular/core';
+import { ChangeDetectionStrategy, Component, computed, inject, input, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { ApplicabilityStatus, PreregLinkInfo, ReviewsState } from '@osf/features/preprints/enums';
@@ -19,12 +19,12 @@ import {
PreprintStepperSelectors,
SubmitPreprint,
} from '@osf/features/preprints/store/preprint-stepper';
-import { TruncatedTextComponent } from '@shared/components';
+import { AffiliatedInstitutionsViewComponent, TruncatedTextComponent } from '@shared/components';
import { ResourceType } from '@shared/enums';
-import { Institution } from '@shared/models';
import { InterpolatePipe } from '@shared/pipes';
import { ToastService } from '@shared/services';
import { ContributorsSelectors, FetchSelectedSubjects, GetAllContributors, SubjectsSelectors } from '@shared/stores';
+import { FetchResourceInstitutions, InstitutionsSelectors } from '@shared/stores/institutions';
@Component({
selector: 'osf-review-step',
@@ -41,6 +41,7 @@ import { ContributorsSelectors, FetchSelectedSubjects, GetAllContributors, Subje
AccordionHeader,
AccordionPanel,
InterpolatePipe,
+ AffiliatedInstitutionsViewComponent,
],
templateUrl: './review-step.component.html',
styleUrl: './review-step.component.scss',
@@ -55,6 +56,7 @@ export class ReviewStepComponent implements OnInit {
fetchLicenses: FetchLicenses,
fetchPreprintProject: FetchPreprintProject,
submitPreprint: SubmitPreprint,
+ fetchResourceInstitutions: FetchResourceInstitutions,
});
provider = input.required();
preprint = select(PreprintStepperSelectors.getPreprint);
@@ -65,7 +67,7 @@ export class ReviewStepComponent implements OnInit {
return this.contributors().filter((contributor) => contributor.isBibliographic);
});
subjects = select(SubjectsSelectors.getSelectedSubjects);
- affiliatedInstitutions = signal([]);
+ affiliatedInstitutions = select(InstitutionsSelectors.getResourceInstitutions);
license = select(PreprintStepperSelectors.getPreprintLicense);
preprintProject = select(PreprintStepperSelectors.getPreprintProject);
licenseOptionsRecord = computed(() => {
@@ -80,6 +82,7 @@ export class ReviewStepComponent implements OnInit {
this.actions.fetchSubjects(this.preprint()!.id, ResourceType.Preprint);
this.actions.fetchLicenses();
this.actions.fetchPreprintProject();
+ this.actions.fetchResourceInstitutions(this.preprint()!.id, ResourceType.Preprint);
}
submitPreprint() {
diff --git a/src/app/features/preprints/pages/submit-preprint-stepper/submit-preprint-stepper.component.html b/src/app/features/preprints/pages/submit-preprint-stepper/submit-preprint-stepper.component.html
index a970fb38c..d700c0810 100644
--- a/src/app/features/preprints/pages/submit-preprint-stepper/submit-preprint-stepper.component.html
+++ b/src/app/features/preprints/pages/submit-preprint-stepper/submit-preprint-stepper.component.html
@@ -43,7 +43,11 @@
/>
}
@case (SubmitStepsEnum.Metadata) {
-
+
}
@case (SubmitStepsEnum.AuthorAssertions) {
diff --git a/src/app/features/preprints/pages/update-preprint-stepper/update-preprint-stepper.component.html b/src/app/features/preprints/pages/update-preprint-stepper/update-preprint-stepper.component.html
index 093754596..7528acfe6 100644
--- a/src/app/features/preprints/pages/update-preprint-stepper/update-preprint-stepper.component.html
+++ b/src/app/features/preprints/pages/update-preprint-stepper/update-preprint-stepper.component.html
@@ -36,7 +36,11 @@
}
@case (PreprintSteps.Metadata) {
-
+
}
@case (PreprintSteps.AuthorAssertions) {
diff --git a/src/app/features/project/metadata/mappers/project-metadata.mapper.ts b/src/app/features/project/metadata/mappers/project-metadata.mapper.ts
index c2ea123b4..4ec6b35bb 100644
--- a/src/app/features/project/metadata/mappers/project-metadata.mapper.ts
+++ b/src/app/features/project/metadata/mappers/project-metadata.mapper.ts
@@ -1,4 +1,6 @@
import { ProjectOverview, ProjectOverviewContributor } from '@osf/features/project/overview/models';
+import { InstitutionsMapper } from '@shared/mappers';
+import { InstitutionsJsonApiResponse } from '@shared/models';
export class ProjectMetadataMapper {
static fromMetadataApiResponse(response: Record): ProjectOverview {
@@ -40,6 +42,9 @@ export class ProjectMetadataMapper {
isCollection: attributes['collection'] as boolean,
accessRequestsEnabled: attributes['access_requests_enabled'] as boolean,
wikiEnabled: attributes['wiki_enabled'] as boolean,
+ affiliatedInstitutions: InstitutionsMapper.fromInstitutionsResponse(
+ embeds['affiliated_institutions'] as InstitutionsJsonApiResponse
+ ),
currentUserCanComment: attributes['current_user_can_comment'] as boolean,
currentUserPermissions: (attributes['current_user_permissions'] as string[]) || [],
currentUserIsContributor: attributes['current_user_is_contributor'] as boolean,
diff --git a/src/app/features/project/metadata/services/metadata.service.ts b/src/app/features/project/metadata/services/metadata.service.ts
index effa0ec31..2905e7d26 100644
--- a/src/app/features/project/metadata/services/metadata.service.ts
+++ b/src/app/features/project/metadata/services/metadata.service.ts
@@ -81,7 +81,6 @@ export class MetadataService {
getProjectForMetadata(projectId: string): Observable {
const params: Record = {
'embed[]': ['contributors', 'affiliated_institutions', 'identifiers', 'license', 'subjects_acceptable'],
- 'fields[institutions]': 'assets,description,name',
'fields[users]': 'family_name,full_name,given_name,middle_name',
'fields[subjects]': 'text,taxonomy',
};
diff --git a/src/app/features/project/overview/components/add-component-dialog/add-component-dialog.component.html b/src/app/features/project/overview/components/add-component-dialog/add-component-dialog.component.html
index 664cd9c6a..28e444a87 100644
--- a/src/app/features/project/overview/components/add-component-dialog/add-component-dialog.component.html
+++ b/src/app/features/project/overview/components/add-component-dialog/add-component-dialog.component.html
@@ -42,7 +42,7 @@
[inputId]="affiliation.id"
[name]="'affiliations'"
/>
-
+
}
diff --git a/src/app/features/project/overview/mappers/project-overview.mapper.ts b/src/app/features/project/overview/mappers/project-overview.mapper.ts
index 5f69d1907..7488be1d0 100644
--- a/src/app/features/project/overview/mappers/project-overview.mapper.ts
+++ b/src/app/features/project/overview/mappers/project-overview.mapper.ts
@@ -1,3 +1,4 @@
+import { InstitutionsMapper } from '@shared/mappers';
import { License } from '@shared/models';
import { ProjectOverview, ProjectOverviewGetResponseJsoApi } from '../models';
@@ -44,13 +45,7 @@ export class ProjectOverviewMapper {
middleName: contributor.embeds.users.data.attributes.middle_name,
type: contributor.embeds.users.data.type,
})),
- affiliatedInstitutions: response.embeds.affiliated_institutions?.data.map((institution) => ({
- id: institution.id,
- type: institution.type,
- logo: institution.attributes.assets.logo,
- description: institution.attributes.description,
- name: institution.attributes.name,
- })),
+ affiliatedInstitutions: InstitutionsMapper.fromInstitutionsResponse(response.embeds.affiliated_institutions),
identifiers: response.embeds.identifiers?.data.map((identifier) => ({
id: identifier.id,
type: identifier.type,
diff --git a/src/app/features/project/overview/models/project-overview.models.ts b/src/app/features/project/overview/models/project-overview.models.ts
index b5f1f3b86..94440b041 100644
--- a/src/app/features/project/overview/models/project-overview.models.ts
+++ b/src/app/features/project/overview/models/project-overview.models.ts
@@ -1,5 +1,5 @@
import { UserPermissions } from '@osf/shared/enums';
-import { JsonApiResponse } from '@osf/shared/models';
+import { Institution, InstitutionsJsonApiResponse, JsonApiResponse } from '@osf/shared/models';
import { License } from '@shared/models';
export interface ProjectOverviewContributor {
@@ -54,7 +54,7 @@ export interface ProjectOverview {
id: string;
type: string;
};
- affiliatedInstitutions?: ProjectAffiliatedInstitutions[];
+ affiliatedInstitutions?: Institution[];
forksCount: number;
viewOnlyLinksCount: number;
links: {
@@ -100,19 +100,7 @@ export interface ProjectOverviewGetResponseJsoApi {
custom_citation: string | null;
};
embeds: {
- affiliated_institutions: {
- data: {
- id: string;
- type: string;
- attributes: {
- assets: {
- logo: string;
- };
- description: string;
- name: string;
- };
- }[];
- };
+ affiliated_institutions: InstitutionsJsonApiResponse;
identifiers: {
data: {
id: string;
@@ -228,14 +216,6 @@ export interface ProjectIdentifiers {
value: string;
}
-export interface ProjectAffiliatedInstitutions {
- id: string;
- type: string;
- name: string;
- description: string;
- logo: string;
-}
-
export interface ProjectSupplements {
id: string;
type: string;
diff --git a/src/app/features/registry/models/get-registry-institutions-json-api.model.ts b/src/app/features/registry/models/get-registry-institutions-json-api.model.ts
deleted file mode 100644
index 7ca64bae5..000000000
--- a/src/app/features/registry/models/get-registry-institutions-json-api.model.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { ApiData, JsonApiResponse } from '@shared/models';
-
-export type GetRegistryInstitutionsJsonApi = JsonApiResponse<
- ApiData[],
- null
->;
-
-export interface RegistryInstitutionsAttributes {
- assets: {
- banner: string;
- logo: string;
- logo_rounded: string;
- };
-}
diff --git a/src/app/features/registry/models/index.ts b/src/app/features/registry/models/index.ts
index 36d0bdff4..cb8464af7 100644
--- a/src/app/features/registry/models/index.ts
+++ b/src/app/features/registry/models/index.ts
@@ -1,5 +1,4 @@
export * from './bibliographic-contributors.models';
-export * from './get-registry-institutions-json-api.model';
export * from './get-registry-overview-json-api.model';
export * from './get-resource-subjects-json-api.model';
export * from './linked-nodes.models';
@@ -9,8 +8,6 @@ export * from './linked-response.models';
export * from './registry-components.models';
export * from './registry-components-json-api.model';
export * from './registry-contributor-json-api.model';
-export * from './registry-institution.model';
-export * from './registry-institutions-json-api.model';
export * from './registry-metadata.models';
export * from './registry-overview.models';
export * from './registry-subject.model';
@@ -22,4 +19,3 @@ export * from './resources/get-registry-resources-json-api.model';
export * from './resources/get-registry-resources-json-api.model';
export * from './resources/registry-resource.model';
export * from './resources/registry-resource.model';
-export * from './view-schema-block.model';
diff --git a/src/app/features/registry/models/registry-institution.model.ts b/src/app/features/registry/models/registry-institution.model.ts
deleted file mode 100644
index 786c3397f..000000000
--- a/src/app/features/registry/models/registry-institution.model.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export interface RegistryInstitution {
- id: string;
- logo: string;
- logoRounded?: string;
-}
diff --git a/src/app/features/registry/models/registry-institutions-json-api.model.ts b/src/app/features/registry/models/registry-institutions-json-api.model.ts
deleted file mode 100644
index e44a7f77a..000000000
--- a/src/app/features/registry/models/registry-institutions-json-api.model.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { MetaJsonApi } from '@osf/shared/models';
-
-export interface RegistryInstitutionJsonApi {
- id: string;
- type: string;
- attributes: {
- name: string;
- };
- links: {
- self: string;
- html: string;
- iri: string;
- };
-}
-
-export interface RegistryInstitutionsJsonApiResponse {
- data: RegistryInstitutionJsonApi[];
- links: {
- first: string | null;
- last: string | null;
- prev: string | null;
- next: string | null;
- };
- meta: MetaJsonApi;
-}
diff --git a/src/app/features/registry/models/view-schema-block.model.ts b/src/app/features/registry/models/view-schema-block.model.ts
deleted file mode 100644
index 432753f5d..000000000
--- a/src/app/features/registry/models/view-schema-block.model.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export interface ViewSchemaBlock {
- value: string;
- values: string[];
- files?: { id: string; name: string }[];
- required: boolean;
- html?: string;
- type: string;
-}
diff --git a/src/app/features/registry/pages/registry-metadata/registry-metadata.component.ts b/src/app/features/registry/pages/registry-metadata/registry-metadata.component.ts
index e0056983f..03ab6a8c2 100644
--- a/src/app/features/registry/pages/registry-metadata/registry-metadata.component.ts
+++ b/src/app/features/registry/pages/registry-metadata/registry-metadata.component.ts
@@ -432,15 +432,9 @@ export class RegistryMetadataComponent implements OnInit {
const registry = this.currentRegistry();
const institutions = this.institutions();
- const institutionsFormatted =
- institutions?.map((inst) => ({
- id: inst.id,
- name: inst.attributes.name,
- })) || [];
-
return {
...registry,
- institutions: institutionsFormatted,
+ institutions,
} as unknown as ProjectOverview;
}
diff --git a/src/app/features/registry/services/registry-metadata.service.ts b/src/app/features/registry/services/registry-metadata.service.ts
index 0ca2e11b1..c472629b7 100644
--- a/src/app/features/registry/services/registry-metadata.service.ts
+++ b/src/app/features/registry/services/registry-metadata.service.ts
@@ -9,7 +9,8 @@ import {
CedarMetadataTemplateJsonApi,
} from '@osf/features/project/metadata/models';
import { JsonApiService } from '@osf/shared/services';
-import { License } from '@shared/models';
+import { InstitutionsMapper } from '@shared/mappers';
+import { Institution, InstitutionsJsonApiResponse, License } from '@shared/models';
import { RegistryMetadataMapper } from '../mappers';
import {
@@ -20,7 +21,6 @@ import {
RegistryContributorAddRequest,
RegistryContributorJsonApiResponse,
RegistryContributorUpdateRequest,
- RegistryInstitutionsJsonApiResponse,
RegistryOverview,
RegistrySubjectsJsonApi,
UserInstitutionsResponse,
@@ -189,18 +189,15 @@ export class RegistryMetadataService {
);
}
- getRegistryInstitutions(
- registryId: string,
- page = 1,
- pageSize = 100
- ): Observable {
+ getRegistryInstitutions(registryId: string, page = 1, pageSize = 100): Observable {
const params: Record = {
- 'fields[institutions]': 'name',
page: page,
'page[size]': pageSize,
};
- return this.jsonApiService.get(`${this.apiUrl}/registrations/${registryId}/institutions/`, params);
+ return this.jsonApiService
+ .get(`${this.apiUrl}/registrations/${registryId}/institutions/`, params)
+ .pipe(map((response) => InstitutionsMapper.fromInstitutionsResponse(response)));
}
updateRegistryContributor(
diff --git a/src/app/features/registry/services/registry-overview.service.ts b/src/app/features/registry/services/registry-overview.service.ts
index 900abd0e7..933c04f65 100644
--- a/src/app/features/registry/services/registry-overview.service.ts
+++ b/src/app/features/registry/services/registry-overview.service.ts
@@ -6,17 +6,15 @@ import { RegistryModerationMapper } from '@osf/features/moderation/mappers';
import { ReviewAction, ReviewActionsResponseJsonApi } from '@osf/features/moderation/models';
import { MapRegistryOverview } from '@osf/features/registry/mappers';
import {
- GetRegistryInstitutionsJsonApi,
GetRegistryOverviewJsonApi,
GetResourceSubjectsJsonApi,
- RegistryInstitution,
RegistryOverview,
RegistryOverviewJsonApiData,
RegistrySubject,
} from '@osf/features/registry/models';
-import { ReviewActionsMapper } from '@osf/shared/mappers';
+import { InstitutionsMapper, ReviewActionsMapper } from '@osf/shared/mappers';
import { PageSchemaMapper } from '@osf/shared/mappers/registration';
-import { PageSchema, SchemaBlocksResponseJsonApi } from '@osf/shared/models';
+import { Institution, InstitutionsJsonApiResponse, PageSchema, SchemaBlocksResponseJsonApi } from '@osf/shared/models';
import { ReviewActionPayload } from '@osf/shared/models/review-action';
import { JsonApiService } from '@shared/services';
@@ -59,22 +57,14 @@ export class RegistryOverviewService {
.pipe(map((response) => response.data.map((subject) => ({ id: subject.id, text: subject.attributes.text }))));
}
- getInstitutions(registryId: string): Observable {
+ getInstitutions(registryId: string): Observable {
const params = {
'page[size]': 100,
};
return this.jsonApiService
- .get(`${environment.apiUrl}/registrations/${registryId}/institutions/`, params)
- .pipe(
- map((response) =>
- response.data.map((institution) => ({
- id: institution.id,
- logo: institution.attributes.assets.logo,
- logoRounded: institution.attributes.assets.logo_rounded,
- }))
- )
- );
+ .get(`${environment.apiUrl}/registrations/${registryId}/institutions/`, params)
+ .pipe(map((response) => InstitutionsMapper.fromInstitutionsResponse(response)));
}
getSchemaBlocks(schemaLink: string): Observable {
@@ -84,7 +74,7 @@ export class RegistryOverviewService {
};
return this.jsonApiService
- .get(`${schemaLink}schema_blocks`, params)
+ .get(`${schemaLink}schema_blocks/`, params)
.pipe(map((response) => PageSchemaMapper.fromSchemaBlocksResponse(response)));
}
diff --git a/src/app/features/registry/store/registry-metadata/registry-metadata.model.ts b/src/app/features/registry/store/registry-metadata/registry-metadata.model.ts
index a55821781..75138ab22 100644
--- a/src/app/features/registry/store/registry-metadata/registry-metadata.model.ts
+++ b/src/app/features/registry/store/registry-metadata/registry-metadata.model.ts
@@ -3,12 +3,11 @@ import {
CedarMetadataRecordData,
CedarMetadataTemplateJsonApi,
} from '@osf/features/project/metadata/models';
-import { AsyncStateModel, License } from '@shared/models';
+import { AsyncStateModel, Institution, License } from '@shared/models';
import {
BibliographicContributor,
CustomItemMetadataRecord,
- RegistryInstitutionJsonApi,
RegistryOverview,
RegistrySubjectData,
UserInstitution,
@@ -19,7 +18,7 @@ export interface RegistryMetadataStateModel {
bibliographicContributors: AsyncStateModel;
customItemMetadata: AsyncStateModel;
userInstitutions: AsyncStateModel;
- institutions: AsyncStateModel;
+ institutions: AsyncStateModel;
subjects: AsyncStateModel;
cedarTemplates: AsyncStateModel;
cedarRecord: AsyncStateModel;
diff --git a/src/app/features/registry/store/registry-metadata/registry-metadata.state.ts b/src/app/features/registry/store/registry-metadata/registry-metadata.state.ts
index b8717ccb9..5fe6151da 100644
--- a/src/app/features/registry/store/registry-metadata/registry-metadata.state.ts
+++ b/src/app/features/registry/store/registry-metadata/registry-metadata.state.ts
@@ -144,10 +144,10 @@ export class RegistryMetadataState {
});
return this.registryMetadataService.getRegistryInstitutions(action.registryId, action.page, action.pageSize).pipe(
- tap((response) => {
+ tap((institutions) => {
ctx.patchState({
institutions: {
- data: response.data,
+ data: institutions,
isLoading: false,
error: null,
},
diff --git a/src/app/features/registry/store/registry-overview/registry-overview.model.ts b/src/app/features/registry/store/registry-overview/registry-overview.model.ts
index 6d25c5715..64b23328e 100644
--- a/src/app/features/registry/store/registry-overview/registry-overview.model.ts
+++ b/src/app/features/registry/store/registry-overview/registry-overview.model.ts
@@ -1,12 +1,12 @@
import { ReviewAction } from '@osf/features/moderation/models';
-import { RegistryInstitution, RegistryOverview, RegistrySubject } from '@osf/features/registry/models';
-import { PageSchema } from '@osf/shared/models';
+import { RegistryOverview, RegistrySubject } from '@osf/features/registry/models';
+import { Institution, PageSchema } from '@osf/shared/models';
import { AsyncStateModel } from '@shared/models';
export interface RegistryOverviewStateModel {
registry: AsyncStateModel;
subjects: AsyncStateModel;
- institutions: AsyncStateModel;
+ institutions: AsyncStateModel;
schemaBlocks: AsyncStateModel;
moderationActions: AsyncStateModel;
}
diff --git a/src/app/features/registry/store/registry-overview/registry-overview.selectors.ts b/src/app/features/registry/store/registry-overview/registry-overview.selectors.ts
index 3b3913f95..05c6b4bc7 100644
--- a/src/app/features/registry/store/registry-overview/registry-overview.selectors.ts
+++ b/src/app/features/registry/store/registry-overview/registry-overview.selectors.ts
@@ -1,8 +1,8 @@
import { Selector } from '@ngxs/store';
import { ReviewAction } from '@osf/features/moderation/models';
-import { RegistryInstitution, RegistryOverview, RegistrySubject } from '@osf/features/registry/models';
-import { PageSchema } from '@osf/shared/models';
+import { RegistryOverview, RegistrySubject } from '@osf/features/registry/models';
+import { Institution, PageSchema } from '@osf/shared/models';
import { RegistryOverviewStateModel } from './registry-overview.model';
import { RegistryOverviewState } from './registry-overview.state';
@@ -29,7 +29,7 @@ export class RegistryOverviewSelectors {
}
@Selector([RegistryOverviewState])
- static getInstitutions(state: RegistryOverviewStateModel): RegistryInstitution[] | null {
+ static getInstitutions(state: RegistryOverviewStateModel): Institution[] | null {
return state.institutions.data;
}
diff --git a/src/app/shared/components/add-project-form/add-project-form.component.html b/src/app/shared/components/add-project-form/add-project-form.component.html
index 45df6704c..ee76fb2c5 100644
--- a/src/app/shared/components/add-project-form/add-project-form.component.html
+++ b/src/app/shared/components/add-project-form/add-project-form.component.html
@@ -20,43 +20,15 @@
/>
- @if (affiliations().length) {
-
-
-
- {{ 'myProjects.createProject.affiliation.title' | translate }}
-
-
-
-
-
- @for (affiliation of affiliations(); track affiliation.id) {
-
-
-
![OSF Logo]()
-
- }
-
-
- }
+
+
+ {{ 'myProjects.createProject.affiliation.title' | translate }}
+
+
+
-
-
{{ 'project.overview.metadata.affiliatedInstitutions' | translate }}
-
-
- @if (resource.affiliatedInstitutions?.length) {
- @for (institution of resource.affiliatedInstitutions; track institution.id) {
-
![institution logo]()
- }
- } @else {
-
{{ 'project.overview.metadata.noAffiliatedInstitutions' | translate }}
- }
-
-
+
@if (resource.type === resourceTypes.Projects) {
diff --git a/src/app/shared/components/resource-metadata/resource-metadata.component.ts b/src/app/shared/components/resource-metadata/resource-metadata.component.ts
index e02b71111..e4dce6506 100644
--- a/src/app/shared/components/resource-metadata/resource-metadata.component.ts
+++ b/src/app/shared/components/resource-metadata/resource-metadata.component.ts
@@ -8,11 +8,12 @@ import { ChangeDetectionStrategy, Component, input, output } from '@angular/core
import { RouterLink } from '@angular/router';
import { OverviewCollectionsComponent } from '@osf/features/project/overview/components/overview-collections/overview-collections.component';
-import { ResourceCitationsComponent } from '@shared/components/resource-citations/resource-citations.component';
-import { TruncatedTextComponent } from '@shared/components/truncated-text/truncated-text.component';
+import { AffiliatedInstitutionsViewComponent, TruncatedTextComponent } from '@shared/components';
import { OsfResourceTypes } from '@shared/constants';
import { ResourceOverview } from '@shared/models';
+import { ResourceCitationsComponent } from '../resource-citations/resource-citations.component';
+
@Component({
selector: 'osf-resource-metadata',
imports: [
@@ -24,6 +25,7 @@ import { ResourceOverview } from '@shared/models';
DatePipe,
ResourceCitationsComponent,
OverviewCollectionsComponent,
+ AffiliatedInstitutionsViewComponent,
],
templateUrl: './resource-metadata.component.html',
styleUrl: './resource-metadata.component.scss',
diff --git a/src/app/shared/components/shared-metadata/components/project-metadata-affiliated-institutions/project-metadata-affiliated-institutions.component.html b/src/app/shared/components/shared-metadata/components/project-metadata-affiliated-institutions/project-metadata-affiliated-institutions.component.html
index af6b5d311..4a994d1a5 100644
--- a/src/app/shared/components/shared-metadata/components/project-metadata-affiliated-institutions/project-metadata-affiliated-institutions.component.html
+++ b/src/app/shared/components/shared-metadata/components/project-metadata-affiliated-institutions/project-metadata-affiliated-institutions.component.html
@@ -11,25 +11,5 @@ {{ 'project.overview.metadata.affiliatedInstitutions' | translate }}
}
- @if (affiliatedInstitutions()) {
-
- @for (institution of affiliatedInstitutions(); track institution.id) {
-
- @if (institution.logo) {
-
![]()
- }
-
-
{{ institution.name }}
- @if (institution.description) {
-
{{ institution.description }}
- }
-
-
- }
-
- } @else {
-
-
{{ 'project.overview.metadata.noAffiliatedInstitutions' | translate }}
-
- }
+
diff --git a/src/app/shared/components/shared-metadata/components/project-metadata-affiliated-institutions/project-metadata-affiliated-institutions.component.ts b/src/app/shared/components/shared-metadata/components/project-metadata-affiliated-institutions/project-metadata-affiliated-institutions.component.ts
index fe0c2fa0d..d11c5c11c 100644
--- a/src/app/shared/components/shared-metadata/components/project-metadata-affiliated-institutions/project-metadata-affiliated-institutions.component.ts
+++ b/src/app/shared/components/shared-metadata/components/project-metadata-affiliated-institutions/project-metadata-affiliated-institutions.component.ts
@@ -5,17 +5,18 @@ import { Card } from 'primeng/card';
import { ChangeDetectionStrategy, Component, input, output } from '@angular/core';
-import { ProjectAffiliatedInstitutions } from '@osf/features/project/overview/models';
+import { AffiliatedInstitutionsViewComponent } from '@shared/components';
+import { Institution } from '@shared/models';
@Component({
selector: 'osf-project-metadata-affiliated-institutions',
- imports: [Button, Card, TranslatePipe],
+ imports: [Button, Card, TranslatePipe, AffiliatedInstitutionsViewComponent],
templateUrl: './project-metadata-affiliated-institutions.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ProjectMetadataAffiliatedInstitutionsComponent {
openEditAffiliatedInstitutionsDialog = output();
- affiliatedInstitutions = input([]);
+ affiliatedInstitutions = input([]);
readonly = input(false);
}
diff --git a/src/app/shared/mappers/institutions/general-institution.mapper.ts b/src/app/shared/mappers/institutions/general-institution.mapper.ts
deleted file mode 100644
index 065edc5b0..000000000
--- a/src/app/shared/mappers/institutions/general-institution.mapper.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import { FetchInstitutionsJsonApi, GetGeneralInstitutionsResponse, Institution, InstitutionData } from '@shared/models';
-
-export class GeneralInstitutionMapper {
- static adaptInstitution(data: InstitutionData): Institution {
- return {
- id: data.id,
- type: data.type,
- name: data.attributes.name,
- description: data.attributes.description,
- iri: data.attributes.iri,
- rorIri: data.attributes.ror_iri,
- iris: data.attributes.iris,
- assets: data.attributes.assets,
- institutionalRequestAccessEnabled: data.attributes.institutional_request_access_enabled,
- logoPath: data.attributes.logo_path,
- userMetricsUrl: data.relationships.user_metrics.links.related.href,
- linkToExternalReportsArchive: data.attributes.link_to_external_reports_archive,
- };
- }
-
- static adaptInstitutions(response: FetchInstitutionsJsonApi): GetGeneralInstitutionsResponse {
- return {
- data: response.data.map((institution) => this.adaptInstitution(institution)),
- total: response.meta.total,
- };
- }
-}
diff --git a/src/app/shared/mappers/institutions/index.ts b/src/app/shared/mappers/institutions/index.ts
index 7931a9fad..d43e7a986 100644
--- a/src/app/shared/mappers/institutions/index.ts
+++ b/src/app/shared/mappers/institutions/index.ts
@@ -1,2 +1 @@
-export * from './general-institution.mapper';
-export * from './user-institutions.mapper';
+export * from './institutions.mapper';
diff --git a/src/app/shared/mappers/institutions/institutions.mapper.ts b/src/app/shared/mappers/institutions/institutions.mapper.ts
new file mode 100644
index 000000000..1c5ddb58e
--- /dev/null
+++ b/src/app/shared/mappers/institutions/institutions.mapper.ts
@@ -0,0 +1,37 @@
+import {
+ Institution,
+ InstitutionDataJsonApi,
+ InstitutionsJsonApiResponse,
+ InstitutionsWithMetaJsonApiResponse,
+ InstitutionsWithTotalCount,
+} from '@shared/models';
+
+export class InstitutionsMapper {
+ static fromInstitutionsResponse(response: InstitutionsJsonApiResponse): Institution[] {
+ return response.data.map((data) => this.fromInstitutionData(data));
+ }
+
+ static fromInstitutionData(data: InstitutionDataJsonApi): Institution {
+ return {
+ id: data.id,
+ type: data.type,
+ name: data.attributes.name,
+ description: data.attributes.description,
+ iri: data.attributes.iri,
+ rorIri: data.attributes.ror_iri,
+ iris: data.attributes.iris,
+ assets: data.attributes.assets,
+ institutionalRequestAccessEnabled: data.attributes.institutional_request_access_enabled,
+ logoPath: data.attributes.logo_path,
+ userMetricsUrl: data.relationships?.user_metrics?.links?.related?.href,
+ linkToExternalReportsArchive: data.attributes.link_to_external_reports_archive,
+ };
+ }
+
+ static fromResponseWithMeta(response: InstitutionsWithMetaJsonApiResponse): InstitutionsWithTotalCount {
+ return {
+ data: this.fromInstitutionsResponse(response),
+ total: response.meta.total,
+ };
+ }
+}
diff --git a/src/app/shared/mappers/institutions/user-institutions.mapper.ts b/src/app/shared/mappers/institutions/user-institutions.mapper.ts
deleted file mode 100644
index c9d12cb8f..000000000
--- a/src/app/shared/mappers/institutions/user-institutions.mapper.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { Institution, UserInstitutionGetResponse } from '@shared/models';
-
-export class UserInstitutionsMapper {
- static fromResponse(response: UserInstitutionGetResponse): Institution {
- return {
- id: response.id,
- type: response.type,
- name: response.attributes.name,
- description: response.attributes.description,
- iri: response.attributes.iri,
- rorIri: response.attributes.ror_iri,
- iris: response.attributes.iris,
- assets: response.attributes.assets,
- institutionalRequestAccessEnabled: response.attributes.institutional_request_access_enabled,
- logoPath: response.attributes.logo_path,
- };
- }
-}
diff --git a/src/app/shared/mappers/resource-overview.mappers.ts b/src/app/shared/mappers/resource-overview.mappers.ts
index b8bc641b4..e422d7fd5 100644
--- a/src/app/shared/mappers/resource-overview.mappers.ts
+++ b/src/app/shared/mappers/resource-overview.mappers.ts
@@ -1,7 +1,7 @@
import { ProjectOverview } from '@osf/features/project/overview/models';
-import { RegistryInstitution, RegistryOverview, RegistrySubject } from '@osf/features/registry/models';
+import { RegistryOverview, RegistrySubject } from '@osf/features/registry/models';
-import { ResourceOverview } from '../models';
+import { Institution, ResourceOverview } from '../models';
export function MapProjectOverview(project: ProjectOverview): ResourceOverview {
return {
@@ -43,7 +43,7 @@ export function MapProjectOverview(project: ProjectOverview): ResourceOverview {
export function MapRegistryOverview(
registry: RegistryOverview,
subjects: RegistrySubject[],
- institutions: RegistryInstitution[]
+ institutions: Institution[]
): ResourceOverview {
return {
id: registry.id,
diff --git a/src/app/shared/models/institutions/index.ts b/src/app/shared/models/institutions/index.ts
index 9dfd7f83d..1078a676e 100644
--- a/src/app/shared/models/institutions/index.ts
+++ b/src/app/shared/models/institutions/index.ts
@@ -1,3 +1,2 @@
export * from './institution-json-api.model';
export * from './institutions.models';
-export * from './institutions-json-api.model';
diff --git a/src/app/shared/models/institutions/institution-json-api.model.ts b/src/app/shared/models/institutions/institution-json-api.model.ts
index 2b824d75e..9cadd88df 100644
--- a/src/app/shared/models/institutions/institution-json-api.model.ts
+++ b/src/app/shared/models/institutions/institution-json-api.model.ts
@@ -1,5 +1,65 @@
-import { InstitutionData } from '@shared/models';
+import { ApiData, InstitutionAssets, JsonApiResponse, ResponseJsonApi } from '@shared/models';
-export interface InstitutionJsonApiModel {
- data: InstitutionData;
+export type InstitutionsJsonApiResponse = JsonApiResponse;
+export type InstitutionsWithMetaJsonApiResponse = ResponseJsonApi;
+export type InstitutionJsonApiResponse = JsonApiResponse;
+
+export type InstitutionDataJsonApi = ApiData<
+ InstitutionAttributesJsonApi,
+ null,
+ InstitutionRelationshipsJsonApi,
+ InstitutionLinksJsonApi
+>;
+
+interface InstitutionAttributesJsonApi {
+ name: string;
+ description: string;
+ iri: string;
+ ror_iri: string | null;
+ iris: string[];
+ assets: InstitutionAssets;
+ institutional_request_access_enabled: boolean;
+ logo_path: string;
+ link_to_external_reports_archive: string;
+}
+
+interface InstitutionLinksJsonApi {
+ self: string;
+ html: string;
+ iri: string;
+}
+
+interface InstitutionRelationshipsJsonApi {
+ nodes: {
+ links: {
+ related: {
+ href: string;
+ meta: Record;
+ };
+ };
+ };
+ registrations: {
+ links: {
+ related: {
+ href: string;
+ meta: Record;
+ };
+ };
+ };
+ users: {
+ links: {
+ related: {
+ href: string;
+ meta: Record;
+ };
+ };
+ };
+ user_metrics: {
+ links: {
+ related: {
+ href: string;
+ meta: Record;
+ };
+ };
+ };
}
diff --git a/src/app/shared/models/institutions/institutions-json-api.model.ts b/src/app/shared/models/institutions/institutions-json-api.model.ts
deleted file mode 100644
index 4d1c0d9bd..000000000
--- a/src/app/shared/models/institutions/institutions-json-api.model.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import { ResponseJsonApi } from '@osf/shared/models';
-import { Institution, InstitutionAttributes } from '@shared/models';
-
-export interface InstitutionRelationships {
- nodes: {
- links: {
- related: {
- href: string;
- meta: Record;
- };
- };
- };
- registrations: {
- links: {
- related: {
- href: string;
- meta: Record;
- };
- };
- };
- users: {
- links: {
- related: {
- href: string;
- meta: Record;
- };
- };
- };
- user_metrics: {
- links: {
- related: {
- href: string;
- meta: Record;
- };
- };
- };
-}
-
-export interface InstitutionLinks {
- self: string;
- html: string;
- iri: string;
-}
-
-export interface InstitutionData {
- id: string;
- type: string;
- attributes: InstitutionAttributes;
- relationships: InstitutionRelationships;
- links: InstitutionLinks;
-}
-
-export interface InstitutionsResponseLinks {
- first: string | null;
- last: string | null;
- prev: string | null;
- next: string | null;
-}
-
-export interface FetchInstitutionsJsonApi extends ResponseJsonApi {
- links: InstitutionsResponseLinks;
-}
-
-export interface GetGeneralInstitutionsResponse {
- data: Institution[];
- total: number;
-}
diff --git a/src/app/shared/models/institutions/institutions.models.ts b/src/app/shared/models/institutions/institutions.models.ts
index 7c42fa874..f00b4a278 100644
--- a/src/app/shared/models/institutions/institutions.models.ts
+++ b/src/app/shared/models/institutions/institutions.models.ts
@@ -1,25 +1,6 @@
-export interface InstitutionAssets {
- logo: string;
- logo_rounded: string;
- banner: string;
-}
-
-export interface InstitutionAttributes {
- name: string;
- description: string;
- iri: string;
- ror_iri: string | null;
- iris: string[];
- assets: InstitutionAssets;
- institutional_request_access_enabled: boolean;
- logo_path: string;
- link_to_external_reports_archive: string;
-}
-
-export interface UserInstitutionGetResponse {
- id: string;
- type: string;
- attributes: InstitutionAttributes;
+export interface InstitutionsWithTotalCount {
+ data: Institution[];
+ total: number;
}
export interface Institution {
@@ -36,3 +17,9 @@ export interface Institution {
userMetricsUrl?: string;
linkToExternalReportsArchive?: string;
}
+
+export interface InstitutionAssets {
+ logo: string;
+ logo_rounded: string;
+ banner: string;
+}
diff --git a/src/app/shared/models/resource-overview.model.ts b/src/app/shared/models/resource-overview.model.ts
index ad81f1de9..8e555ff7f 100644
--- a/src/app/shared/models/resource-overview.model.ts
+++ b/src/app/shared/models/resource-overview.model.ts
@@ -1,5 +1,6 @@
import { ProjectOverviewContributor } from '@osf/features/project/overview/models';
import { RegistrySubject } from '@osf/features/registry/models';
+import { Institution } from '@shared/models/institutions';
export interface ResourceOverview {
id: string;
@@ -59,11 +60,7 @@ export interface ResourceOverview {
id: string;
type: string;
};
- affiliatedInstitutions?: {
- id: string;
- logo: string;
- logoRounded?: string;
- }[];
+ affiliatedInstitutions?: Institution[];
forksCount: number;
viewOnlyLinksCount?: number;
associatedProjectId?: string;
diff --git a/src/app/shared/services/institutions.service.ts b/src/app/shared/services/institutions.service.ts
index 4a8afd5b7..0cc3d2c0d 100644
--- a/src/app/shared/services/institutions.service.ts
+++ b/src/app/shared/services/institutions.service.ts
@@ -3,14 +3,14 @@ import { map } from 'rxjs/operators';
import { inject, Injectable } from '@angular/core';
-import { GeneralInstitutionMapper, UserInstitutionsMapper } from '@shared/mappers';
+import { ResourceType } from '@shared/enums';
+import { InstitutionsMapper } from '@shared/mappers';
import {
- FetchInstitutionsJsonApi,
- GetGeneralInstitutionsResponse,
Institution,
- InstitutionJsonApiModel,
- JsonApiResponse,
- UserInstitutionGetResponse,
+ InstitutionJsonApiResponse,
+ InstitutionsJsonApiResponse,
+ InstitutionsWithMetaJsonApiResponse,
+ InstitutionsWithTotalCount,
} from '@shared/models';
import { JsonApiService } from '@shared/services';
@@ -21,12 +21,12 @@ import { environment } from 'src/environments/environment';
})
export class InstitutionsService {
private readonly jsonApiService = inject(JsonApiService);
+ private readonly urlMap = new Map([
+ [ResourceType.Preprint, 'preprints'],
+ [ResourceType.Agent, 'users'],
+ ]);
- getInstitutions(
- pageNumber: number,
- pageSize: number,
- searchValue?: string
- ): Observable {
+ getInstitutions(pageNumber: number, pageSize: number, searchValue?: string): Observable {
const params: Record = {};
if (pageNumber) {
@@ -42,22 +42,22 @@ export class InstitutionsService {
}
return this.jsonApiService
- .get(`${environment.apiUrl}/institutions`, params)
- .pipe(map((response) => GeneralInstitutionMapper.adaptInstitutions(response)));
+ .get(`${environment.apiUrl}/institutions/`, params)
+ .pipe(map((response) => InstitutionsMapper.fromResponseWithMeta(response)));
}
getUserInstitutions(): Observable {
const url = `${environment.apiUrl}/users/me/institutions/`;
return this.jsonApiService
- .get>(url)
- .pipe(map((response) => response.data.map((item) => UserInstitutionsMapper.fromResponse(item))));
+ .get(url)
+ .pipe(map((response) => InstitutionsMapper.fromInstitutionsResponse(response)));
}
getInstitutionById(institutionId: string): Observable {
return this.jsonApiService
- .get(`${environment.apiUrl}/institutions/${institutionId}/`)
- .pipe(map((result) => GeneralInstitutionMapper.adaptInstitution(result.data)));
+ .get(`${environment.apiUrl}/institutions/${institutionId}/`)
+ .pipe(map((response) => InstitutionsMapper.fromInstitutionData(response.data)));
}
deleteUserInstitution(id: string, userId: string): Observable {
@@ -66,4 +66,25 @@ export class InstitutionsService {
};
return this.jsonApiService.delete(`${environment.apiUrl}/users/${userId}/relationships/institutions/`, payload);
}
+
+ getResourceInstitutions(resourceId: string, resourceType: ResourceType): Observable {
+ const url = `${environment.apiUrl}/${this.urlMap.get(resourceType)}/${resourceId}/institutions/`;
+
+ return this.jsonApiService
+ .get(url)
+ .pipe(map((response) => InstitutionsMapper.fromInstitutionsResponse(response)));
+ }
+
+ updateResourceInstitutions(
+ resourceId: string,
+ resourceType: ResourceType,
+ institutions: Institution[]
+ ): Observable {
+ const baseUrl = `${environment.apiUrl}/${this.urlMap.get(resourceType)}/${resourceId}/relationships/institutions/`;
+ const payload = {
+ data: institutions.map((item) => ({ id: item.id, type: 'institutions' })),
+ };
+
+ return this.jsonApiService.put(baseUrl, payload);
+ }
}
diff --git a/src/app/shared/stores/index.ts b/src/app/shared/stores/index.ts
index 66f706c5b..fd2d02ae5 100644
--- a/src/app/shared/stores/index.ts
+++ b/src/app/shared/stores/index.ts
@@ -4,7 +4,6 @@ export * from './citations';
export * from './collections';
export * from './contributors';
export * from './duplicates';
-export * from './institutions';
export * from './institutions-search';
export * from './licenses';
export * from './my-resources';
diff --git a/src/app/shared/stores/institutions/institutions.actions.ts b/src/app/shared/stores/institutions/institutions.actions.ts
index f8f6c03a5..8e359a433 100644
--- a/src/app/shared/stores/institutions/institutions.actions.ts
+++ b/src/app/shared/stores/institutions/institutions.actions.ts
@@ -1,3 +1,6 @@
+import { ResourceType } from '@shared/enums';
+import { Institution } from '@shared/models';
+
export class FetchUserInstitutions {
static readonly type = '[Institutions] Fetch User Institutions';
}
@@ -11,3 +14,22 @@ export class FetchInstitutions {
public searchValue?: string
) {}
}
+
+export class FetchResourceInstitutions {
+ static readonly type = '[Institutions] Fetch Resource Institutions';
+
+ constructor(
+ public resourceId: string,
+ public resourceType: ResourceType
+ ) {}
+}
+
+export class UpdateResourceInstitutions {
+ static readonly type = '[Institutions] Update Resource Institutions';
+
+ constructor(
+ public resourceId: string,
+ public resourceType: ResourceType,
+ public institutions: Institution[]
+ ) {}
+}
diff --git a/src/app/shared/stores/institutions/institutions.model.ts b/src/app/shared/stores/institutions/institutions.model.ts
index 13fb7e854..27fe568bf 100644
--- a/src/app/shared/stores/institutions/institutions.model.ts
+++ b/src/app/shared/stores/institutions/institutions.model.ts
@@ -1,6 +1,26 @@
-import { AsyncStateWithTotalCount, Institution } from '@osf/shared/models';
+import { AsyncStateModel, AsyncStateWithTotalCount, Institution } from '@osf/shared/models';
export interface InstitutionsStateModel {
- userInstitutions: Institution[];
+ userInstitutions: AsyncStateModel;
institutions: AsyncStateWithTotalCount;
+ resourceInstitutions: AsyncStateModel;
}
+
+export const DefaultState = {
+ userInstitutions: {
+ data: [],
+ isLoading: false,
+ error: null,
+ },
+ institutions: {
+ data: [],
+ isLoading: false,
+ error: null,
+ totalCount: 0,
+ },
+ resourceInstitutions: {
+ data: [],
+ isLoading: false,
+ error: null,
+ },
+};
diff --git a/src/app/shared/stores/institutions/institutions.selectors.ts b/src/app/shared/stores/institutions/institutions.selectors.ts
index 9414d163d..e45a590c7 100644
--- a/src/app/shared/stores/institutions/institutions.selectors.ts
+++ b/src/app/shared/stores/institutions/institutions.selectors.ts
@@ -6,7 +6,12 @@ import { InstitutionsState } from './institutions.state';
export class InstitutionsSelectors {
@Selector([InstitutionsState])
static getUserInstitutions(state: InstitutionsStateModel) {
- return state.userInstitutions;
+ return state.userInstitutions.data;
+ }
+
+ @Selector([InstitutionsState])
+ static areUserInstitutionsLoading(state: InstitutionsStateModel) {
+ return state.userInstitutions.isLoading;
}
@Selector([InstitutionsState])
@@ -23,4 +28,19 @@ export class InstitutionsSelectors {
static getInstitutionsTotalCount(state: InstitutionsStateModel): number {
return state.institutions.totalCount;
}
+
+ @Selector([InstitutionsState])
+ static getResourceInstitutions(state: InstitutionsStateModel) {
+ return state.resourceInstitutions.data;
+ }
+
+ @Selector([InstitutionsState])
+ static areResourceInstitutionsLoading(state: InstitutionsStateModel) {
+ return state.resourceInstitutions.isLoading;
+ }
+
+ @Selector([InstitutionsState])
+ static areResourceInstitutionsSubmitting(state: InstitutionsStateModel) {
+ return state.resourceInstitutions.isSubmitting;
+ }
}
diff --git a/src/app/shared/stores/institutions/institutions.state.ts b/src/app/shared/stores/institutions/institutions.state.ts
index 29728f2bb..69874ded3 100644
--- a/src/app/shared/stores/institutions/institutions.state.ts
+++ b/src/app/shared/stores/institutions/institutions.state.ts
@@ -1,26 +1,24 @@
import { Action, State, StateContext } from '@ngxs/store';
import { patch } from '@ngxs/store/operators';
-import { catchError, tap, throwError } from 'rxjs';
+import { catchError, Observable, tap, throwError } from 'rxjs';
import { inject, Injectable } from '@angular/core';
import { InstitutionsService } from '@osf/shared/services';
+import { handleSectionError } from '@shared/helpers';
-import { FetchInstitutions, FetchUserInstitutions } from './institutions.actions';
-import { InstitutionsStateModel } from './institutions.model';
+import {
+ FetchInstitutions,
+ FetchResourceInstitutions,
+ FetchUserInstitutions,
+ UpdateResourceInstitutions,
+} from './institutions.actions';
+import { DefaultState, InstitutionsStateModel } from './institutions.model';
@State({
name: 'institutions',
- defaults: {
- userInstitutions: [],
- institutions: {
- data: [],
- isLoading: false,
- error: null,
- totalCount: 0,
- },
- },
+ defaults: { ...DefaultState },
})
@Injectable()
export class InstitutionsState {
@@ -28,12 +26,20 @@ export class InstitutionsState {
@Action(FetchUserInstitutions)
getUserInstitutions(ctx: StateContext) {
+ ctx.setState(patch({ userInstitutions: patch({ isLoading: true }) }));
+
return this.institutionsService.getUserInstitutions().pipe(
tap((institutions) => {
- ctx.patchState({
- userInstitutions: institutions,
- });
- })
+ ctx.setState(
+ patch({
+ userInstitutions: patch({
+ isLoading: false,
+ data: institutions,
+ }),
+ })
+ );
+ }),
+ catchError((error) => handleSectionError(ctx, 'userInstitutions', error))
);
}
@@ -73,4 +79,48 @@ export class InstitutionsState {
})
);
}
+
+ @Action(FetchResourceInstitutions)
+ fetchResourceInstitutions(ctx: StateContext, action: FetchResourceInstitutions) {
+ ctx.setState(patch({ resourceInstitutions: patch({ isLoading: true }) }));
+
+ return this.institutionsService.getResourceInstitutions(action.resourceId, action.resourceType).pipe(
+ tap((institutions) => {
+ ctx.setState(
+ patch({
+ resourceInstitutions: patch({
+ data: institutions,
+ isLoading: false,
+ error: null,
+ }),
+ })
+ );
+ }),
+ catchError((error) => handleSectionError(ctx, 'resourceInstitutions', error))
+ );
+ }
+
+ @Action(UpdateResourceInstitutions)
+ updateResourceInstitutions(
+ ctx: StateContext,
+ action: UpdateResourceInstitutions
+ ): Observable {
+ ctx.setState(patch({ resourceInstitutions: patch({ isSubmitting: true }) }));
+
+ return this.institutionsService
+ .updateResourceInstitutions(action.resourceId, action.resourceType, action.institutions)
+ .pipe(
+ tap(() => {
+ ctx.setState(
+ patch({
+ resourceInstitutions: patch({
+ data: action.institutions,
+ isSubmitting: false,
+ }),
+ })
+ );
+ }),
+ catchError((error) => handleSectionError(ctx, 'resourceInstitutions', error))
+ );
+ }
}
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
index 6e1be8e00..e1bfc9fcc 100644
--- a/src/assets/i18n/en.json
+++ b/src/assets/i18n/en.json
@@ -1888,7 +1888,9 @@
},
"tagsTitle": "Tags (optional)",
"publicationDateTitle": "Publication Date (optional)",
- "publicationCitationTitle": "Publication Citation (optional)"
+ "publicationCitationTitle": "Publication Citation (optional)",
+ "affiliatedInstitutionsTitle": "Affiliated Institutions",
+ "affiliatedInstitutionsDescription": "You can affiliate your {{preprintWord}} with your institution if it is an OSF institutional member and has worked with the Center for Open Science to create a dedicated institutional OSF landing page."
},
"authorAssertions": {
"title": "Author Assertions",
@@ -2765,4 +2767,4 @@
"software": "Software",
"other": "Other"
}
-}
\ No newline at end of file
+}