diff --git a/src/app/features/files/components/file-resource-metadata/file-resource-metadata.component.html b/src/app/features/files/components/file-resource-metadata/file-resource-metadata.component.html index 541f7af8c..cb784e3b8 100644 --- a/src/app/features/files/components/file-resource-metadata/file-resource-metadata.component.html +++ b/src/app/features/files/components/file-resource-metadata/file-resource-metadata.component.html @@ -105,7 +105,10 @@

{{ 'common.labels.dateModified' | translate }}

{{ 'common.labels.contributors' | translate }}

- +
} } diff --git a/src/app/features/files/components/file-resource-metadata/file-resource-metadata.component.spec.ts b/src/app/features/files/components/file-resource-metadata/file-resource-metadata.component.spec.ts index fffe0f5b0..f2c66555a 100644 --- a/src/app/features/files/components/file-resource-metadata/file-resource-metadata.component.spec.ts +++ b/src/app/features/files/components/file-resource-metadata/file-resource-metadata.component.spec.ts @@ -1,31 +1,21 @@ -import { MockComponent, MockProvider } from 'ng-mocks'; +import { MockComponent } from 'ng-mocks'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { Router } from '@angular/router'; import { ContributorsListComponent } from '@osf/shared/components/contributors-list/contributors-list.component'; import { ResourceMetadata } from '@osf/shared/models/resource-metadata.model'; -import { ViewOnlyLinkHelperService } from '@osf/shared/services/view-only-link-helper.service'; import { MOCK_CONTRIBUTOR, MOCK_CONTRIBUTOR_WITHOUT_HISTORY } from '@testing/mocks/contributors.mock'; import { provideOSFCore } from '@testing/osf.testing.provider'; -import { RouterMockBuilder, RouterMockType } from '@testing/providers/router-provider.mock'; import { BaseSetupOverrides, mergeSignalOverrides, provideMockStore } from '@testing/providers/store-provider.mock'; -import { ViewOnlyLinkHelperMock, ViewOnlyLinkHelperMockType } from '@testing/providers/view-only-link-helper.mock'; import { FilesSelectors } from '../../store'; import { FileResourceMetadataComponent } from './file-resource-metadata.component'; -interface SetupOverrides extends BaseSetupOverrides { - hasViewOnly?: boolean; -} - describe('FileResourceMetadataComponent', () => { let component: FileResourceMetadataComponent; let fixture: ComponentFixture; - let mockRouter: RouterMockType; - let viewOnlyService: ViewOnlyLinkHelperMockType; const mockResourceMetadata: ResourceMetadata = { title: 'Test Resource', @@ -45,18 +35,14 @@ describe('FileResourceMetadataComponent', () => { { selector: FilesSelectors.getContributors, value: mockContributors }, { selector: FilesSelectors.isResourceMetadataLoading, value: false }, { selector: FilesSelectors.isResourceContributorsLoading, value: false }, + { selector: FilesSelectors.isFilesAnonymous, value: false }, ]; - function setup(overrides: SetupOverrides = {}): void { - mockRouter = RouterMockBuilder.create().withUrl('/test').build(); - viewOnlyService = ViewOnlyLinkHelperMock.simple(overrides.hasViewOnly ?? false); - + function setup(overrides: BaseSetupOverrides = {}): void { TestBed.configureTestingModule({ imports: [FileResourceMetadataComponent, MockComponent(ContributorsListComponent)], providers: [ provideOSFCore(), - MockProvider(Router, mockRouter), - MockProvider(ViewOnlyLinkHelperService, viewOnlyService), provideMockStore({ signals: mergeSignalOverrides(defaultSignals, overrides.selectorOverrides) }), ], }); @@ -102,12 +88,12 @@ describe('FileResourceMetadataComponent', () => { expect(component.isResourceContributorsLoading()).toBe(true); }); - it('should set hasViewOnly based on helper service', () => { - setup({ hasViewOnly: true }); + it('should expose isAnonymous from store', () => { + setup({ + selectorOverrides: [{ selector: FilesSelectors.isFilesAnonymous, value: true }], + }); - expect(component.hasViewOnly).toBe(true); - expect(viewOnlyService.hasViewOnlyParam).toHaveBeenCalled(); - expect(viewOnlyService.hasViewOnlyParam).toHaveBeenCalledWith(expect.objectContaining({ url: '/test' })); + expect(component.isAnonymous()).toBe(true); }); it('should handle input changes', () => { diff --git a/src/app/features/files/components/file-resource-metadata/file-resource-metadata.component.ts b/src/app/features/files/components/file-resource-metadata/file-resource-metadata.component.ts index 6a56cc300..cd11f29b4 100644 --- a/src/app/features/files/components/file-resource-metadata/file-resource-metadata.component.ts +++ b/src/app/features/files/components/file-resource-metadata/file-resource-metadata.component.ts @@ -5,11 +5,9 @@ import { TranslatePipe } from '@ngx-translate/core'; import { Skeleton } from 'primeng/skeleton'; import { DatePipe } from '@angular/common'; -import { ChangeDetectionStrategy, Component, inject, input } from '@angular/core'; -import { Router } from '@angular/router'; +import { ChangeDetectionStrategy, Component, input } from '@angular/core'; import { ContributorsListComponent } from '@osf/shared/components/contributors-list/contributors-list.component'; -import { ViewOnlyLinkHelperService } from '@osf/shared/services/view-only-link-helper.service'; import { FilesSelectors } from '../../store'; @@ -21,15 +19,11 @@ import { FilesSelectors } from '../../store'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class FileResourceMetadataComponent { - private readonly router = inject(Router); - private readonly viewOnlyService = inject(ViewOnlyLinkHelperService); + readonly resourceType = input('nodes'); - resourceType = input('nodes'); - - resourceMetadata = select(FilesSelectors.getResourceMetadata); - contributors = select(FilesSelectors.getContributors); - isResourceMetadataLoading = select(FilesSelectors.isResourceMetadataLoading); - isResourceContributorsLoading = select(FilesSelectors.isResourceContributorsLoading); - - hasViewOnly = this.viewOnlyService.hasViewOnlyParam(this.router); + readonly resourceMetadata = select(FilesSelectors.getResourceMetadata); + readonly contributors = select(FilesSelectors.getContributors); + readonly isResourceMetadataLoading = select(FilesSelectors.isResourceMetadataLoading); + readonly isResourceContributorsLoading = select(FilesSelectors.isResourceContributorsLoading); + readonly isAnonymous = select(FilesSelectors.isFilesAnonymous); } diff --git a/src/app/features/files/store/files.state.ts b/src/app/features/files/store/files.state.ts index 5ba307e6d..9b84843c5 100644 --- a/src/app/features/files/store/files.state.ts +++ b/src/app/features/files/store/files.state.ts @@ -159,9 +159,12 @@ export class FilesState { ctx.patchState({ tags: { ...state.tags, isLoading: true, error: null } }); return this.filesService.getFileTarget(action.fileGuid).pipe( - tap((file) => { - ctx.patchState({ openedFile: { data: file, isLoading: false, error: null } }); - ctx.patchState({ tags: { data: file.tags, isLoading: false, error: null } }); + tap(({ file, meta }) => { + ctx.patchState({ + openedFile: { data: file, isLoading: false, error: null }, + tags: { data: file.tags, isLoading: false, error: null }, + isAnonymous: meta?.anonymous ?? false, + }); }), catchError((error) => handleSectionError(ctx, 'openedFile', error)) ); diff --git a/src/app/shared/models/files/file.model.ts b/src/app/shared/models/files/file.model.ts index f49bc8215..602165a68 100644 --- a/src/app/shared/models/files/file.model.ts +++ b/src/app/shared/models/files/file.model.ts @@ -1,3 +1,4 @@ +import { MetaJsonApi } from '../common/json-api.model'; import { BaseNodeModel } from '../nodes/base-node.model'; import { FileKind } from './../../enums/file-kind.enum'; @@ -32,6 +33,11 @@ export interface FileDetailsModel extends BaseFileModel { target: BaseNodeModel | null; } +export interface FileDetailsWithMeta { + file: FileDetailsModel; + meta?: MetaJsonApi; +} + export interface FileExtraModel { hashes: FileHashesModel; downloads: number; diff --git a/src/app/shared/services/files.service.ts b/src/app/shared/services/files.service.ts index 5d5becd79..4958da928 100644 --- a/src/app/shared/services/files.service.ts +++ b/src/app/shared/services/files.service.ts @@ -30,7 +30,7 @@ import { ConfiguredAddonModel } from '../models/addons/configured-addon.model'; import { ApiData, JsonApiResponse, MetaJsonApi } from '../models/common/json-api.model'; import { ContributorModel } from '../models/contributors/contributor.model'; import { ContributorsResponseJsonApi } from '../models/contributors/contributor-response-json-api.model'; -import { FileDetailsModel, FileModel } from '../models/files/file.model'; +import { FileDetailsModel, FileDetailsWithMeta, FileModel } from '../models/files/file.model'; import { FileFolderModel } from '../models/files/file-folder.model'; import { FileFolderDataJsonApi, @@ -178,10 +178,10 @@ export class FilesService { return `${link}${separator}zip=`; } - getFileTarget(fileGuid: string): Observable { + getFileTarget(fileGuid: string): Observable { return this.jsonApiService .get(`${this.apiUrl}/files/${fileGuid}/?embed=target`) - .pipe(map((response) => FilesMapper.getFileDetails(response.data))); + .pipe(map((response) => ({ file: FilesMapper.getFileDetails(response.data), meta: response.meta }))); } getFileGuid(id: string): Observable { diff --git a/src/testing/providers/files-service.mock.ts b/src/testing/providers/files-service.mock.ts index 37d32e6ee..026b3ca50 100644 --- a/src/testing/providers/files-service.mock.ts +++ b/src/testing/providers/files-service.mock.ts @@ -5,7 +5,7 @@ import { Mock, vi } from 'vitest'; import { HttpEvent } from '@angular/common/http'; import { MetaJsonApi } from '@osf/shared/models/common/json-api.model'; -import { FileDetailsModel, FileModel } from '@osf/shared/models/files/file.model'; +import { FileDetailsModel, FileDetailsWithMeta, FileModel } from '@osf/shared/models/files/file.model'; import { FileFolderModel } from '@osf/shared/models/files/file-folder.model'; import { FileVersionModel } from '@osf/shared/models/files/file-version.model'; import { PaginatedData } from '@osf/shared/models/paginated-data.model'; @@ -39,7 +39,7 @@ type MoveFileFn = ( replace?: boolean ) => Observable; type GetFolderDownloadLinkFn = (link: string) => string; -type GetFileTargetFn = (fileGuid: string) => Observable; +type GetFileTargetFn = (fileGuid: string) => Observable; type GetFileGuidFn = (id: string) => Observable; type GetFileByIdFn = (fileGuid: string) => Observable; type GetFileVersionsFn = (fileGuid: string) => Observable; @@ -113,7 +113,7 @@ export const FilesServiceMock = { renameEntry: vi.fn().mockReturnValue(of(file)), moveFile: vi.fn().mockReturnValue(of({})), getFolderDownloadLink: vi.fn().mockImplementation((link: string) => `${link}?zip=`), - getFileTarget: vi.fn().mockReturnValue(of(fileDetails)), + getFileTarget: vi.fn().mockReturnValue(of({ file: fileDetails })), getFileGuid: vi.fn().mockReturnValue(of(file)), getFileById: vi.fn().mockReturnValue(of(file)), getFileVersions: vi.fn().mockReturnValue(of([])),