Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 17 additions & 0 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,20 @@
"namedChunks": true
},
"development": {
"outputMode": "static",
"server": false,
"ssr": false,
"optimization": false,
"extractLicenses": false,
"sourceMap": true,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.development.ts"
}
]
},
"dev-ssr": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true,
Expand Down Expand Up @@ -164,6 +178,9 @@
"development": {
"buildTarget": "osf:build:development"
},
"dev-ssr": {
"buildTarget": "osf:build:dev-ssr"
},
"docker": {
"buildTarget": "osf:build:docker"
},
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"ngxs:store": "ng generate @ngxs/store:store --name --path",
"prepare": "husky",
"start": "ng serve",
"start:ssr": "ng serve --configuration dev-ssr",
"start:docker": "npm run check:config && ng serve --host 0.0.0.0 --port 4200 --poll 2000 --configuration development",
"start:docker:local": "npm run check:config && ng serve --host 0.0.0.0 --port 4200 --poll 2000 --configuration docker",
"test": "jest",
Expand Down
9 changes: 2 additions & 7 deletions src/app/features/files/files.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const filesRoutes: Routes = [
{
path: ':fileProvider',
canMatch: [isFileProvider],
data: { canonicalPathTemplate: 'files/:fileProvider' },
loadComponent: () => import('@osf/features/files/pages/files/files.component').then((c) => c.FilesComponent),
},
{
Expand All @@ -27,18 +28,12 @@ export const filesRoutes: Routes = [
},
{
path: ':fileGuid',
data: { canonicalPathTemplate: 'files/:fileGuid' },
loadComponent: () => {
return import('@osf/features/files/pages/file-detail/file-detail.component').then(
(c) => c.FileDetailComponent
);
},
children: [
{
path: 'metadata',
loadChildren: () => import('@osf/features/metadata/metadata.routes').then((mod) => mod.metadataRoutes),
data: { resourceType: ResourceType.File },
},
],
},
],
},
Expand Down
33 changes: 9 additions & 24 deletions src/app/features/files/pages/file-detail/file-detail.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createDispatchMap, select, Store } from '@ngxs/store';

import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import { TranslatePipe } from '@ngx-translate/core';

import { Button } from 'primeng/button';
import { Menu } from 'primeng/menu';
Expand All @@ -10,7 +10,6 @@ import { Tab, TabList, Tabs } from 'primeng/tabs';
import { switchMap } from 'rxjs';

import { Clipboard } from '@angular/cdk/clipboard';
import { DatePipe } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
Expand Down Expand Up @@ -43,10 +42,10 @@ import { MetadataTabsComponent } from '@osf/shared/components/metadata-tabs/meta
import { SubHeaderComponent } from '@osf/shared/components/sub-header/sub-header.component';
import { MetadataResourceEnum } from '@osf/shared/enums/metadata-resource.enum';
import { ResourceType } from '@osf/shared/enums/resource-type.enum';
import { pathJoin } from '@osf/shared/helpers/path-join.helper';
import { CustomConfirmationService } from '@osf/shared/services/custom-confirmation.service';
import { DataciteService } from '@osf/shared/services/datacite/datacite.service';
import { MetaTagsService } from '@osf/shared/services/meta-tags.service';
import { MetaTagsBuilderService } from '@osf/shared/services/meta-tags-builder.service';
import { ToastService } from '@osf/shared/services/toast.service';
import { ViewOnlyLinkHelperService } from '@osf/shared/services/view-only-link-helper.service';
import { FileDetailsModel } from '@shared/models/files/file.model';
Expand Down Expand Up @@ -92,7 +91,6 @@ import {
templateUrl: './file-detail.component.html',
styleUrl: './file-detail.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [DatePipe],
})
export class FileDetailComponent {
@HostBinding('class') classes = 'flex flex-column flex-1 w-full h-full';
Expand All @@ -106,16 +104,13 @@ export class FileDetailComponent {
readonly customConfirmationService = inject(CustomConfirmationService);

private readonly metaTags = inject(MetaTagsService);
private readonly datePipe = inject(DatePipe);
private readonly metaTagsBuilder = inject(MetaTagsBuilderService);
private readonly viewOnlyService = inject(ViewOnlyLinkHelperService);
private readonly translateService = inject(TranslateService);
private readonly environment = inject(ENVIRONMENT);
private readonly clipboard = inject(Clipboard);

readonly dataciteService = inject(DataciteService);

private readonly webUrl = this.environment.webUrl;

private readonly actions = createDispatchMap({
getFile: GetFile,
getFileRevisions: GetFileRevisions,
Expand Down Expand Up @@ -204,24 +199,14 @@ export class FileDetailComponent {
}

const file = this.file();

if (!file) return null;

return {
osfGuid: file.guid,
title: this.fileCustomMetadata()?.title || file.name,
type: this.fileCustomMetadata()?.resourceTypeGeneral,
description:
this.fileCustomMetadata()?.description ?? this.translateService.instant('files.metaTagDescriptionPlaceholder'),
url: pathJoin(this.webUrl, this.fileGuid),
publishedDate: this.datePipe.transform(file.dateCreated, 'yyyy-MM-dd'),
modifiedDate: this.datePipe.transform(file.dateModified, 'yyyy-MM-dd'),
language: this.fileCustomMetadata()?.language,
contributors: this.resourceContributors()?.map((contributor) => ({
fullName: contributor.fullName,
givenName: contributor.givenName,
familyName: contributor.familyName,
})),
};
return this.metaTagsBuilder.buildFileMetaTagsData({
file,
fileMetadata: this.fileCustomMetadata(),
contributors: this.resourceContributors() ?? [],
});
});

constructor() {
Expand Down
1 change: 1 addition & 0 deletions src/app/features/metadata/metadata.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const metadataRoutes: Routes = [
},
{
path: ':recordId',
data: { canonicalPathTemplate: 'metadata/:recordId' },
component: MetadataComponent,
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ import { ActivatedRoute, Router } from '@angular/router';
import { HelpScoutService } from '@core/services/help-scout.service';
import { PrerenderReadyService } from '@core/services/prerender-ready.service';
import { ClearCurrentProvider } from '@core/store/provider';
import { MetaTagsData } from '@osf/shared/models/meta-tags/meta-tags-data.model';
import { CustomDialogService } from '@osf/shared/services/custom-dialog.service';
import { DataciteService } from '@osf/shared/services/datacite/datacite.service';
import { MetaTagsService } from '@osf/shared/services/meta-tags.service';
import { MetaTagsBuilderService } from '@osf/shared/services/meta-tags-builder.service';
import { ToastService } from '@osf/shared/services/toast.service';
import { ContributorsSelectors } from '@osf/shared/stores/contributors';

Expand Down Expand Up @@ -55,6 +57,7 @@ import { provideOSFCore } from '@testing/osf.testing.provider';
import { CustomDialogServiceMockBuilder } from '@testing/providers/custom-dialog-provider.mock';
import { HelpScoutServiceMockFactory } from '@testing/providers/help-scout.service.mock';
import { MetaTagsServiceMockFactory } from '@testing/providers/meta-tags.service.mock';
import { MetaTagsBuilderServiceMockFactory } from '@testing/providers/meta-tags-builder.service.mock';
import { PrerenderReadyServiceMockFactory } from '@testing/providers/prerender-ready.service.mock';
import { ActivatedRouteMockBuilder } from '@testing/providers/route-provider.mock';
import { RouterMockBuilder, RouterMockType } from '@testing/providers/router-provider.mock';
Expand All @@ -70,6 +73,7 @@ describe('PreprintDetailsComponent', () => {
let prerenderReadyServiceMock: jest.Mocked<PrerenderReadyService>;
let dataciteServiceMock: ReturnType<typeof DataciteMockFactory>;
let metaTagsServiceMock: ReturnType<typeof MetaTagsServiceMockFactory>;
let metaTagsBuilderServiceMock: ReturnType<typeof MetaTagsBuilderServiceMockFactory>;
let customDialogServiceMock: ReturnType<CustomDialogServiceMockBuilder['build']>;
let toastService: ToastServiceMockType;

Expand Down Expand Up @@ -122,6 +126,13 @@ describe('PreprintDetailsComponent', () => {
prerenderReadyServiceMock = PrerenderReadyServiceMockFactory();
dataciteServiceMock = DataciteMockFactory();
metaTagsServiceMock = MetaTagsServiceMockFactory();
metaTagsBuilderServiceMock = MetaTagsBuilderServiceMockFactory();
metaTagsBuilderServiceMock.buildPreprintMetaTagsData.mockImplementation(
({ providerId, preprint }) =>
({
canonicalUrl: `http://localhost:4200/preprints/${providerId}/${preprint?.id}`,
}) as MetaTagsData
);
toastService = ToastServiceMock.simple();
customDialogServiceMock =
overrides?.dialogReturnsCloseValue === false
Expand Down Expand Up @@ -167,6 +178,7 @@ describe('PreprintDetailsComponent', () => {
MockProvider(PrerenderReadyService, prerenderReadyServiceMock),
MockProvider(DataciteService, dataciteServiceMock),
MockProvider(MetaTagsService, metaTagsServiceMock),
MockProvider(MetaTagsBuilderService, metaTagsBuilderServiceMock),
MockProvider(CustomDialogService, customDialogServiceMock),
provideMockStore({ signals }),
],
Expand Down Expand Up @@ -199,7 +211,19 @@ describe('PreprintDetailsComponent', () => {
it('should update meta tags when preprint and contributors are loaded', () => {
setup();

expect(metaTagsServiceMock.updateMetaTags).toHaveBeenCalled();
expect(metaTagsBuilderServiceMock.buildPreprintMetaTagsData).toHaveBeenCalledWith(
expect.objectContaining({
providerId: 'osf',
preprint: expect.objectContaining({ id: 'preprint-1' }),
})
);

expect(metaTagsServiceMock.updateMetaTags).toHaveBeenCalledWith(
expect.objectContaining({
canonicalUrl: 'http://localhost:4200/preprints/osf/preprint-1',
}),
expect.anything()
);
});

it('should not fetch moderation actions when not moderator and no permissions', () => {
Expand Down Expand Up @@ -532,6 +556,7 @@ describe('PreprintDetailsComponent SSR', () => {
MockProvider(Router, routerMock),
MockProvider(CustomDialogService, CustomDialogServiceMockBuilder.create().withDefaultOpen().build()),
MockProvider(DataciteService, DataciteMockFactory()),
MockProvider(MetaTagsBuilderService, MetaTagsBuilderServiceMockFactory()),
MockProvider(MetaTagsService, MetaTagsServiceMockFactory()),
MockProvider(PrerenderReadyService, PrerenderReadyServiceMockFactory()),
MockProvider(HelpScoutService, helpScoutServiceMock),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Skeleton } from 'primeng/skeleton';

import { catchError, EMPTY, filter, map } from 'rxjs';

import { DatePipe, isPlatformBrowser } from '@angular/common';
import { isPlatformBrowser } from '@angular/common';
import { HttpErrorResponse } from '@angular/common/http';
import {
ChangeDetectionStrategy,
Expand All @@ -30,10 +30,10 @@ import { PrerenderReadyService } from '@core/services/prerender-ready.service';
import { ClearCurrentProvider } from '@core/store/provider';
import { UserSelectors } from '@core/store/user';
import { ReviewPermissions } from '@osf/shared/enums/review-permissions.enum';
import { pathJoin } from '@osf/shared/helpers/path-join.helper';
import { CustomDialogService } from '@osf/shared/services/custom-dialog.service';
import { DataciteService } from '@osf/shared/services/datacite/datacite.service';
import { MetaTagsService } from '@osf/shared/services/meta-tags.service';
import { MetaTagsBuilderService } from '@osf/shared/services/meta-tags-builder.service';
import { ToastService } from '@osf/shared/services/toast.service';
import { ContributorsSelectors } from '@osf/shared/stores/contributors';

Expand Down Expand Up @@ -82,7 +82,6 @@ import { CreateNewVersion, PreprintStepperSelectors } from '../../store/preprint
],
templateUrl: './preprint-details.component.html',
styleUrl: './preprint-details.component.scss',
providers: [DatePipe],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PreprintDetailsComponent implements OnInit, OnDestroy {
Expand All @@ -97,14 +96,13 @@ export class PreprintDetailsComponent implements OnInit, OnDestroy {
private readonly customDialogService = inject(CustomDialogService);
private readonly translateService = inject(TranslateService);
private readonly metaTags = inject(MetaTagsService);
private readonly datePipe = inject(DatePipe);
private readonly metaTagsBuilder = inject(MetaTagsBuilderService);
private readonly dataciteService = inject(DataciteService);
private readonly prerenderReady = inject(PrerenderReadyService);
private readonly platformId = inject(PLATFORM_ID);
private readonly environment = inject(ENVIRONMENT);
private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));

private readonly isBrowser = isPlatformBrowser(this.platformId);

readonly providerId = toSignal(this.route.params.pipe(map((params) => params['providerId'])));
private readonly preprintId = toSignal(this.route.params.pipe(map((params) => params['id'])));

private readonly actions = createDispatchMap({
Expand All @@ -118,7 +116,6 @@ export class PreprintDetailsComponent implements OnInit, OnDestroy {
clearCurrentProvider: ClearCurrentProvider,
});

readonly providerId = toSignal(this.route.params.pipe(map((params) => params['providerId'])));
currentUser = select(UserSelectors.getCurrentUser);
preprintProvider = select(PreprintProvidersSelectors.getPreprintProviderDetails(this.providerId()));
isPreprintProviderLoading = select(PreprintProvidersSelectors.isPreprintProviderDetailsLoading);
Expand Down Expand Up @@ -410,26 +407,13 @@ export class PreprintDetailsComponent implements OnInit, OnDestroy {
}

private setMetaTags() {
this.metaTags.updateMetaTags(
{
osfGuid: this.preprint()?.id,
title: this.preprint()?.title,
description: this.preprint()?.description,
publishedDate: this.datePipe.transform(this.preprint()?.datePublished, 'yyyy-MM-dd'),
modifiedDate: this.datePipe.transform(this.preprint()?.dateModified, 'yyyy-MM-dd'),
url: pathJoin(this.environment.webUrl, this.preprint()?.id ?? ''),
doi: this.preprint()?.doi,
keywords: this.preprint()?.tags,
siteName: 'OSF',
license: this.preprint()?.embeddedLicense?.name,
contributors: this.contributors().map((contributor) => ({
fullName: contributor.fullName,
givenName: contributor.givenName,
familyName: contributor.familyName,
})),
},
this.destroyRef
);
const metaTags = this.metaTagsBuilder.buildPreprintMetaTagsData({
providerId: this.providerId(),
preprint: this.preprint(),
contributors: this.contributors(),
});

this.metaTags.updateMetaTags(metaTags, this.destroyRef);
}

private checkAndSetVersionToTheUrl() {
Expand Down
Loading
Loading