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
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,10 @@ <h4>{{ 'common.labels.dateModified' | translate }}</h4>
<div class="flex flex-column gap-2">
<h4>{{ 'common.labels.contributors' | translate }}</h4>

<osf-contributors-list [contributors]="resourceContributors" [anonymous]="hasViewOnly"></osf-contributors-list>
<osf-contributors-list
[contributors]="resourceContributors"
[anonymous]="isAnonymous()"
></osf-contributors-list>
</div>
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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<FileResourceMetadataComponent>;
let mockRouter: RouterMockType;
let viewOnlyService: ViewOnlyLinkHelperMockType;

const mockResourceMetadata: ResourceMetadata = {
title: 'Test Resource',
Expand All @@ -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) }),
],
});
Expand Down Expand Up @@ -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', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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<string>('nodes');

resourceType = input<string>('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);
}
9 changes: 6 additions & 3 deletions src/app/features/files/store/files.state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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))
);
Expand Down
6 changes: 6 additions & 0 deletions src/app/shared/models/files/file.model.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions src/app/shared/services/files.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -178,10 +178,10 @@ export class FilesService {
return `${link}${separator}zip=`;
}

getFileTarget(fileGuid: string): Observable<FileDetailsModel> {
getFileTarget(fileGuid: string): Observable<FileDetailsWithMeta> {
return this.jsonApiService
.get<FileDetailsResponseJsonApi>(`${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<FileModel> {
Expand Down
6 changes: 3 additions & 3 deletions src/testing/providers/files-service.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -39,7 +39,7 @@ type MoveFileFn = (
replace?: boolean
) => Observable<unknown>;
type GetFolderDownloadLinkFn = (link: string) => string;
type GetFileTargetFn = (fileGuid: string) => Observable<FileDetailsModel>;
type GetFileTargetFn = (fileGuid: string) => Observable<FileDetailsWithMeta>;
type GetFileGuidFn = (id: string) => Observable<FileModel>;
type GetFileByIdFn = (fileGuid: string) => Observable<FileModel>;
type GetFileVersionsFn = (fileGuid: string) => Observable<FileVersionModel[]>;
Expand Down Expand Up @@ -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([])),
Expand Down
Loading