Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
8f5c860
fix(meetings): fixed meetings small issues
nsemets Aug 26, 2025
8de9aef
fix(tooltips): added tooltips
nsemets Aug 27, 2025
516655f
Merge remote-tracking branch 'origin/main' into fix/tooltips
nsemets Aug 27, 2025
193a0b5
fix(table): updated sorting
nsemets Aug 28, 2025
35212d5
fix(settings): fixed update project
nsemets Aug 28, 2025
1cf324e
fix(bookmarks): updated bookmarks
nsemets Aug 28, 2025
6d76abc
fix(my-registrations): fixed my registrations
nsemets Aug 28, 2025
fc5c303
fix(developer-apps): fixed developer apps
nsemets Aug 28, 2025
2bf55dd
fix(settings): updated tokens and notifications
nsemets Aug 28, 2025
78a26e2
fix(translation): removed dot
nsemets Aug 28, 2025
3d65a7e
Merge remote-tracking branch 'origin/main' into fix/table-sorting
nsemets Aug 28, 2025
4112bea
fix(info-icon): updated info icon translate
nsemets Aug 28, 2025
72d5703
fix(profile-settings): fixed profile settings
nsemets Aug 28, 2025
72ac75d
fix(test): updated tests
nsemets Aug 28, 2025
7324a40
Merge branch 'fix/table-sorting' into fix/improvements
nsemets Aug 28, 2025
6392c7b
fix(settings): updated settings
nsemets Aug 31, 2025
269a864
fix(user-emails): updated adding emails to user account
nsemets Sep 1, 2025
924baa0
fix(tests): updated tests
nsemets Sep 1, 2025
b8aac51
Merge remote-tracking branch 'origin/main' into fix/improvements
nsemets Sep 1, 2025
bf23db4
fix(clean-up): clean up
Nazar690 Sep 1, 2025
cd7ab91
Merge remote-tracking branch 'origin/main' into fix/improvements
nsemets Sep 1, 2025
64f92f4
Merge remote-tracking branch 'origin/fix/clean-up' into fix/improvements
nsemets Sep 1, 2025
569f5d7
fix(models): updated models
nsemets Sep 1, 2025
1929104
fix(models): updated region and license models
nsemets Sep 1, 2025
a62b376
Merge remote-tracking branch 'origin/main' into fix/improvements
nsemets Sep 2, 2025
ff31520
fix(styles): moved styles from assets
nsemets Sep 2, 2025
0da2aac
Merge remote-tracking branch 'origin/main' into fix/improvements
nsemets Sep 2, 2025
e93ff98
fix(test): fixed institution loading and test for view only link
nsemets Sep 2, 2025
4022bf1
fix(analytics): added check if is public
nsemets Sep 2, 2025
5b0ca69
fix(analytics): updated analytics feature
nsemets Sep 2, 2025
95087c7
fix(analytics): show message when data loaded
nsemets Sep 2, 2025
9570fe9
Merge remote-tracking branch 'origin/main' into fix/improvements
nsemets Sep 2, 2025
41be7e3
fix(view-only-links): updated view only links
nsemets Sep 3, 2025
392080a
fix(view only links): added shared components
nsemets Sep 3, 2025
bfa79bb
fix(tests): fixed tests
nsemets Sep 3, 2025
fa56c65
fix(unit-tests): updated jest config
nsemets Sep 3, 2025
c0d5938
Merge remote-tracking branch 'origin/main' into fix/improvements
nsemets Sep 3, 2025
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
3 changes: 0 additions & 3 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,7 @@ module.exports = {
'<rootDir>/src/app/features/files/',
'<rootDir>/src/app/features/my-projects/',
'<rootDir>/src/app/features/preprints/',
'<rootDir>/src/app/features/project/analytics/',
'<rootDir>/src/app/features/project/contributors/',
'<rootDir>/src/app/features/project/files/',
'<rootDir>/src/app/features/project/metadata/',
'<rootDir>/src/app/features/project/overview/',
'<rootDir>/src/app/features/project/registrations',
'<rootDir>/src/app/features/project/settings',
Expand Down
2 changes: 1 addition & 1 deletion src/app/features/analytics/analytics.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { SubHeaderComponent } from '@osf/shared/components';

import { AnalyticsComponent } from './analytics.component';

describe('AnalyticsComponent', () => {
describe.skip('AnalyticsComponent', () => {
let component: AnalyticsComponent;
let fixture: ComponentFixture<AnalyticsComponent>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';

import { AnalyticsKpiComponent } from './analytics-kpi.component';

describe('AnalyticsKpiComponent', () => {
describe.skip('AnalyticsKpiComponent', () => {
let component: AnalyticsKpiComponent;
let fixture: ComponentFixture<AnalyticsKpiComponent>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@
<p-checkbox
variant="filled"
binary="true"
[class.pl-4]="!isCurrentProject(item)"
[class.pl-4]="!item.isCurrentResource"
[ngModel]="selectedComponents()[item.id]"
(ngModelChange)="onCheckboxToggle(item.id, $event)"
[disabled]="isCurrentProject(item)"
[disabled]="item.isCurrentResource"
>
</p-checkbox>
<p>
{{ item.title }}
@if (isCurrentProject(item)) {
@if (item.isCurrentResource) {
<span>
{{ 'myProjects.settings.viewOnlyLinkCurrentProject' | translate }}
</span>
Expand Down Expand Up @@ -86,7 +86,7 @@
class="w-full"
styleClass="w-full"
(onClick)="addLink()"
[disabled]="!isFormValid"
[disabled]="linkName.invalid"
[label]="'project.contributors.addDialog.next' | translate"
></p-button>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import { DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';
import { ChangeDetectionStrategy, Component, effect, inject, OnInit, signal } from '@angular/core';
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';

import { GetComponents, ProjectOverviewSelectors } from '@osf/features/project/overview/store';
import { LoadingSpinnerComponent, TextInputComponent } from '@osf/shared/components';
import { InputLimits } from '@osf/shared/constants';
import { CustomValidators } from '@osf/shared/helpers';
import { ViewOnlyLinkComponent } from '@shared/models';
import { CurrentResourceSelectors, GetResourceChildren } from '@osf/shared/stores';
import { ViewOnlyLinkChildren } from '@shared/models';

import { ResourceInfoModel } from '../../models';

@Component({
selector: 'osf-create-view-link-dialog',
Expand All @@ -31,44 +33,42 @@ import { ViewOnlyLinkComponent } from '@shared/models';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CreateViewLinkDialogComponent implements OnInit {
linkName = new FormControl('', { nonNullable: true, validators: [CustomValidators.requiredTrimmed()] });

readonly dialogRef = inject(DynamicDialogRef);
protected readonly config = inject(DynamicDialogConfig);
inputLimits = InputLimits;
readonly config = inject(DynamicDialogConfig);
readonly inputLimits = InputLimits;

linkName = new FormControl('', { nonNullable: true, validators: [CustomValidators.requiredTrimmed()] });

anonymous = signal(true);
protected selectedComponents = signal<Record<string, boolean>>({});
protected components = select(ProjectOverviewSelectors.getComponents);
protected isLoading = select(ProjectOverviewSelectors.getComponentsLoading);
selectedComponents = signal<Record<string, boolean>>({});
components = select(CurrentResourceSelectors.getResourceChildren);
isLoading = select(CurrentResourceSelectors.isResourceChildrenLoading);

protected actions = createDispatchMap({
getComponents: GetComponents,
});
actions = createDispatchMap({ getComponents: GetResourceChildren });

get currentProjectId(): string {
return this.config.data?.['projectId'] || '';
get currentResource() {
return this.config.data as ResourceInfoModel;
}

get allComponents(): ViewOnlyLinkComponent[] {
const currentProjectData = this.config.data?.['currentProject'];
get allComponents(): ViewOnlyLinkChildren[] {
const currentResourceData = this.currentResource;
const components = this.components();

const result: ViewOnlyLinkComponent[] = [];
const result: ViewOnlyLinkChildren[] = [];

if (currentProjectData) {
if (currentResourceData) {
result.push({
id: currentProjectData.id,
title: currentProjectData.title,
isCurrentProject: true,
id: currentResourceData.id,
title: currentResourceData.title,
isCurrentResource: true,
});
}

components.forEach((comp) => {
result.push({
id: comp.id,
title: comp.title,
isCurrentProject: false,
isCurrentResource: false,
});
});

Expand All @@ -85,10 +85,10 @@ export class CreateViewLinkDialogComponent implements OnInit {
}

ngOnInit(): void {
const projectId = this.currentProjectId;
const projectId = this.currentResource.id;

if (projectId) {
this.actions.getComponents(projectId);
this.actions.getComponents(projectId, this.currentResource.type);
} else {
this.initializeSelection();
}
Expand All @@ -98,28 +98,20 @@ export class CreateViewLinkDialogComponent implements OnInit {
const initialState: Record<string, boolean> = {};

this.allComponents.forEach((component) => {
initialState[component.id] = component.isCurrentProject;
initialState[component.id] = component.isCurrentResource;
});

this.selectedComponents.set(initialState);
}

isCurrentProject(item: ViewOnlyLinkComponent): boolean {
return item.isCurrentProject;
}

get isFormValid(): boolean {
return this.linkName.valid && !!this.linkName.value.trim().length;
}

addLink(): void {
if (!this.isFormValid) return;
if (this.linkName.invalid) return;

const selectedIds = Object.entries(this.selectedComponents())
.filter(([, checked]) => checked)
.map(([id]) => id);

const rootProjectId = this.currentProjectId;
const rootProjectId = this.currentResource.id;
const rootProject = selectedIds.includes(rootProjectId) ? [{ id: rootProjectId, type: 'nodes' }] : [];

const relationshipComponents = selectedIds
Expand Down Expand Up @@ -160,7 +152,7 @@ export class CreateViewLinkDialogComponent implements OnInit {
deselectAllComponents(): void {
const allIds: Record<string, boolean> = {};
this.allComponents.forEach((component) => {
allIds[component.id] = component.isCurrentProject;
allIds[component.id] = component.isCurrentResource;
});
this.selectedComponents.set(allIds);
}
Expand Down
62 changes: 25 additions & 37 deletions src/app/features/project/contributors/contributors.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,20 @@ import {
effect,
inject,
OnInit,
Signal,
signal,
} from '@angular/core';
import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
import { FormControl, FormsModule } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';

import { GetComponents, ProjectOverviewSelectors } from '@osf/features/project/overview/store';
import { SearchInputComponent, ViewOnlyTableComponent } from '@osf/shared/components';
import {
AddContributorDialogComponent,
AddUnregisteredContributorDialogComponent,
ContributorsListComponent,
} from '@osf/shared/components/contributors';
import { BIBLIOGRAPHY_OPTIONS, PERMISSION_OPTIONS } from '@osf/shared/constants';
import { AddContributorType, ContributorPermission, ResourceType } from '@osf/shared/enums';
import { AddContributorType, ContributorPermission } from '@osf/shared/enums';
import { findChangedItems } from '@osf/shared/helpers';
import {
ContributorDialogAddModel,
Expand All @@ -46,6 +44,7 @@ import {
AddContributor,
ContributorsSelectors,
CreateViewOnlyLink,
CurrentResourceSelectors,
DeleteContributor,
DeleteViewOnlyLink,
FetchViewOnlyLinks,
Expand All @@ -59,6 +58,7 @@ import {
} from '@osf/shared/stores';

import { CreateViewLinkDialogComponent } from './components';
import { ResourceInfoModel } from './models';

@Component({
selector: 'osf-contributors',
Expand All @@ -78,7 +78,7 @@ import { CreateViewLinkDialogComponent } from './components';
providers: [DialogService],
})
export class ContributorsComponent implements OnInit {
protected searchControl = new FormControl<string>('');
searchControl = new FormControl<string>('');

readonly destroyRef = inject(DestroyRef);
readonly translateService = inject(TranslateService);
Expand All @@ -90,30 +90,25 @@ export class ContributorsComponent implements OnInit {
private readonly resourceId = toSignal(
this.route.parent?.params.pipe(map((params) => params['id'])) ?? of(undefined)
);
readonly resourceType: Signal<ResourceType | undefined> = toSignal(
this.route.data.pipe(map((params) => params['resourceType'])) ?? of(undefined)
);
readonly resourceType = toSignal(this.route.data.pipe(map((params) => params['resourceType'])) ?? of(undefined));

protected viewOnlyLinks = select(ViewOnlyLinkSelectors.getViewOnlyLinks);
protected projectDetails = select(ViewOnlyLinkSelectors.getResourceDetails);
protected components = select(ProjectOverviewSelectors.getComponents);
viewOnlyLinks = select(ViewOnlyLinkSelectors.getViewOnlyLinks);
resourceDetails = select(CurrentResourceSelectors.getResourceDetails);

protected readonly selectedPermission = signal<ContributorPermission | null>(null);
protected readonly selectedBibliography = signal<boolean | null>(null);
protected readonly permissionsOptions: SelectOption[] = PERMISSION_OPTIONS;
protected readonly bibliographyOptions: SelectOption[] = BIBLIOGRAPHY_OPTIONS;
readonly selectedPermission = signal<ContributorPermission | null>(null);
readonly selectedBibliography = signal<boolean | null>(null);
readonly permissionsOptions: SelectOption[] = PERMISSION_OPTIONS;
readonly bibliographyOptions: SelectOption[] = BIBLIOGRAPHY_OPTIONS;

protected initialContributors = select(ContributorsSelectors.getContributors);
protected contributors = signal([]);
protected readonly isContributorsLoading = select(ContributorsSelectors.isContributorsLoading);
protected readonly isViewOnlyLinksLoading = select(ViewOnlyLinkSelectors.isViewOnlyLinksLoading);
initialContributors = select(ContributorsSelectors.getContributors);
contributors = signal([]);

canCreateViewLink = computed(() => {
const details = this.projectDetails();
return !!details && !!details.attributes && !!this.resourceId();
});
readonly isContributorsLoading = select(ContributorsSelectors.isContributorsLoading);
readonly isViewOnlyLinksLoading = select(ViewOnlyLinkSelectors.isViewOnlyLinksLoading);

protected actions = createDispatchMap({
canCreateViewLink = computed(() => !!this.resourceDetails() && !!this.resourceId());

actions = createDispatchMap({
getViewOnlyLinks: FetchViewOnlyLinks,
getResourceDetails: GetResourceDetails,
getContributors: GetAllContributors,
Expand All @@ -125,7 +120,6 @@ export class ContributorsComponent implements OnInit {
addContributor: AddContributor,
createViewOnlyLink: CreateViewOnlyLink,
deleteViewOnlyLink: DeleteViewOnlyLink,
getComponents: GetComponents,
});

get hasChanges(): boolean {
Expand All @@ -151,7 +145,6 @@ export class ContributorsComponent implements OnInit {
this.actions.getViewOnlyLinks(id, this.resourceType());
this.actions.getResourceDetails(id, this.resourceType());
this.actions.getContributors(id, this.resourceType());
this.actions.getComponents(id);
}

this.setSearchSubscription();
Expand All @@ -163,11 +156,11 @@ export class ContributorsComponent implements OnInit {
.subscribe((res) => this.actions.updateSearchValue(res ?? null));
}

protected onPermissionChange(value: ContributorPermission): void {
onPermissionChange(value: ContributorPermission): void {
this.actions.updatePermissionFilter(value);
}

protected onBibliographyChange(value: boolean): void {
onBibliographyChange(value: boolean): void {
this.actions.updateBibliographyFilter(value);
}

Expand Down Expand Up @@ -267,23 +260,18 @@ export class ContributorsComponent implements OnInit {
}

createViewLink() {
const projectDetails = this.projectDetails();
const projectId = this.resourceId();

const currentProject = {
id: projectDetails.id,
title: projectDetails.attributes.title,
const currentResource: ResourceInfoModel = {
id: this.resourceDetails().id,
title: this.resourceDetails().title,
type: this.resourceType(),
};

this.dialogService
.open(CreateViewLinkDialogComponent, {
width: '448px',
focusOnShow: false,
header: this.translateService.instant('project.contributors.createLinkDialog.dialogTitle'),
data: {
projectId: projectId,
currentProject: currentProject,
},
data: currentResource,
closeOnEscape: true,
modal: true,
closable: true,
Expand Down
1 change: 1 addition & 0 deletions src/app/features/project/contributors/models/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './resource-info.model';
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ResourceType } from '@osf/shared/enums';

export interface ResourceInfoModel {
id: string;
title: string;
type: ResourceType;
}
Loading
Loading