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
2 changes: 2 additions & 0 deletions src/app/core/constants/ngxs-states.constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { MeetingsState } from '@osf/features/meetings/store';
import { MyProjectsState } from '@osf/features/my-projects/store';
import { AnalyticsState } from '@osf/features/project/analytics/store';
import { ProjectOverviewState } from '@osf/features/project/overview/store';
import { SettingsState } from '@osf/features/project/settings/store';
import { WikiState } from '@osf/features/project/wiki/store/wiki.state';
import { AccountSettingsState } from '@osf/features/settings/account-settings/store/account-settings.state';
import { AddonsState } from '@osf/features/settings/addons/store';
Expand All @@ -25,6 +26,7 @@ export const STATES = [
DeveloperAppsState,
AccountSettingsState,
AnalyticsState,
SettingsState,
NotificationSubscriptionState,
ProjectOverviewState,
CollectionsState,
Expand Down
4 changes: 2 additions & 2 deletions src/app/core/interceptors/auth.interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export const authInterceptor: HttpInterceptorFn = (
next: HttpHandlerFn
): Observable<HttpEvent<unknown>> => {
const authToken = 'UlO9O9GNKgVzJD7pUeY53jiQTKJ4U2znXVWNvh0KZQruoENuILx0IIYf9LoDz7Duq72EIm';
// OBJoUomBgbUuDgQo5JoaSKNya6XaYcd0ojAX1XOLmWi6J2arQPzByxyEi81fHE60drQUWv
// UlO9O9GNKgVzJD7pUeY53jiQTKJ4U2znXVWNvh0KZQruoENuILx0IIYf9LoDz7Duq72EIm kyrylo
// '2rjFZwmdDG4rtKj7hGkEMO6XyHBM2lN7XBbsA1e8OqcFhOWu6Z7fQZiheu9RXtzSeVrgOt';
// 'OBJoUomBgbUuDgQo5JoaSKNya6XaYcd0ojAX1XOLmWi6J2arQPzByxyEi81fHE60drQUWv';

if (authToken) {
const authReq = req.clone({
Expand Down
49 changes: 38 additions & 11 deletions src/app/features/my-projects/services/my-projects.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { map } from 'rxjs/operators';
import { inject, Injectable } from '@angular/core';

import { JsonApiService } from '@osf/core/services';
import { SparseCollectionsResponse } from '@osf/features/collections/models';
import { SortOrder } from '@osf/shared/enums';
import { NodeResponseModel, UpdateNodeRequestModel } from '@shared/models';

import { MyProjectsMapper } from '../mappers';
import {
Expand All @@ -23,13 +25,15 @@ import { environment } from 'src/environments/environment';
providedIn: 'root',
})
export class MyProjectsService {
#jsonApiService = inject(JsonApiService);
#sortFieldMap: Record<string, string> = {
private apiUrl = environment.apiUrl;
private sortFieldMap: Record<string, string> = {
title: 'title',
dateModified: 'date_modified',
};

#getMyItems(
private readonly jsonApiService = inject(JsonApiService);

private getMyItems(
endpoint: EndpointType,
filters?: MyProjectsSearchFilters,
pageNumber?: number,
Expand All @@ -53,8 +57,8 @@ export class MyProjectsService {
params['page[size]'] = pageSize;
}

if (filters?.sortColumn && this.#sortFieldMap[filters.sortColumn]) {
const apiField = this.#sortFieldMap[filters.sortColumn];
if (filters?.sortColumn && this.sortFieldMap[filters.sortColumn]) {
const apiField = this.sortFieldMap[filters.sortColumn];
const sortPrefix = filters.sortOrder === SortOrder.Desc ? '-' : '';
params['sort'] = `${sortPrefix}${apiField}`;
} else {
Expand All @@ -65,7 +69,7 @@ export class MyProjectsService {
? environment.apiUrl + '/' + endpoint
: environment.apiUrl + '/users/me/' + endpoint;

return this.#jsonApiService.get<MyProjectsJsonApiResponse>(url, params).pipe(
return this.jsonApiService.get<MyProjectsJsonApiResponse>(url, params).pipe(
map((response: MyProjectsJsonApiResponse) => ({
data: response.data.map((item: MyProjectsItemGetResponse) => MyProjectsMapper.fromResponse(item)),
links: response.links,
Expand All @@ -78,23 +82,38 @@ export class MyProjectsService {
pageNumber?: number,
pageSize?: number
): Observable<MyProjectsItemResponse> {
return this.#getMyItems('nodes', filters, pageNumber, pageSize);
return this.getMyItems('nodes', filters, pageNumber, pageSize);
}

getBookmarksCollectionId(): Observable<string> {
const params: Record<string, unknown> = {
'fields[collections]': 'title,bookmarks',
};

return this.jsonApiService.get<SparseCollectionsResponse>(environment.apiUrl + '/collections/', params).pipe(
map((response) => {
const bookmarksCollection = response.data.find(
(collection) => collection.attributes.title === 'Bookmarks' && collection.attributes.bookmarks
);
return bookmarksCollection?.id ?? '';
})
);
}

getMyRegistrations(
filters?: MyProjectsSearchFilters,
pageNumber?: number,
pageSize?: number
): Observable<MyProjectsItemResponse> {
return this.#getMyItems('registrations', filters, pageNumber, pageSize);
return this.getMyItems('registrations', filters, pageNumber, pageSize);
}

getMyPreprints(
filters?: MyProjectsSearchFilters,
pageNumber?: number,
pageSize?: number
): Observable<MyProjectsItemResponse> {
return this.#getMyItems('preprints', filters, pageNumber, pageSize);
return this.getMyItems('preprints', filters, pageNumber, pageSize);
}

getMyBookmarks(
Expand All @@ -103,7 +122,7 @@ export class MyProjectsService {
pageNumber?: number,
pageSize?: number
): Observable<MyProjectsItemResponse> {
return this.#getMyItems(`collections/${collectionId}/linked_nodes/`, filters, pageNumber, pageSize);
return this.getMyItems(`collections/${collectionId}/linked_nodes/`, filters, pageNumber, pageSize);
}

createProject(
Expand Down Expand Up @@ -147,8 +166,16 @@ export class MyProjectsService {
'fields[users]': 'family_name,full_name,given_name,middle_name',
};

return this.#jsonApiService
return this.jsonApiService
.post<MyProjectsItemGetResponse>(`${environment.apiUrl}/nodes/`, payload, params)
.pipe(map((response) => MyProjectsMapper.fromResponse(response)));
}

getProjectById(projectId: string): Observable<NodeResponseModel> {
return this.jsonApiService.get(`${this.apiUrl}/nodes/${projectId}`);
}

updateProjectById(model: UpdateNodeRequestModel): Observable<NodeResponseModel> {
return this.jsonApiService.patch(`${this.apiUrl}/nodes/${model?.data?.id}`, model);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
type="text"
pInputText
placeholder="Type link name"
required
[ngModel]="linkName()"
(ngModelChange)="onLinkNameChange($event)"
/>
Expand Down Expand Up @@ -34,18 +35,19 @@
</p>

<div class="flex flex-column gap-2">
<div class="flex gap-1">
<p-checkbox variant="filled" binary="true" [(ngModel)]="componentExample1"></p-checkbox>
<p>Component Name Example</p>
</div>
<div class="flex gap-1">
<p-checkbox variant="filled" binary="true" [(ngModel)]="componentExample2"></p-checkbox>
<p>Component Name Example</p>
</div>
<div class="flex gap-1">
<p-checkbox variant="filled" binary="true" [(ngModel)]="componentExample3"></p-checkbox>
<p>Component Name Example</p>
</div>
@for (item of config.data.sharedComponents; track item.id) {
<div class="flex gap-1">
<p-checkbox
variant="filled"
binary="true"
[ngModel]="selectedComponents()[item.id]"
(ngModelChange)="onCheckboxToggle(item.id, $event)"
[disabled]="isCurrentProject(item)"
>
</p-checkbox>
<p>{{ item.title }}</p>
</div>
}
</div>

<div class="flex gap-2">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,80 @@ import { TranslatePipe } from '@ngx-translate/core';

import { Button } from 'primeng/button';
import { Checkbox } from 'primeng/checkbox';
import { DynamicDialogRef } from 'primeng/dynamicdialog';
import { DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';
import { InputText } from 'primeng/inputtext';

import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';
import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import { ViewOnlyLinkNodeModel } from '@osf/features/project/settings/models';

@Component({
selector: 'osf-create-view-link-dialog',
imports: [Button, TranslatePipe, InputText, ReactiveFormsModule, FormsModule, Checkbox],
templateUrl: './create-view-link-dialog.component.html',
styleUrl: './create-view-link-dialog.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CreateViewLinkDialogComponent {
dialogRef = inject(DynamicDialogRef);
export class CreateViewLinkDialogComponent implements OnInit {
readonly dialogRef = inject(DynamicDialogRef);
protected readonly config = inject(DynamicDialogConfig);

protected selectedComponents = signal<Record<string, boolean>>({});
protected linkName = signal('');
anonymous = signal(true);
componentExample1 = signal(true);
componentExample2 = signal(false);
componentExample3 = signal(false);
readonly projectId = signal('');

ngOnInit(): void {
const data = (this.config.data?.['sharedComponents'] as ViewOnlyLinkNodeModel[]) || [];
this.projectId.set(this.config.data?.['projectId']);
const initialState = data.reduce(
(acc, curr) => {
if (curr.id) {
acc[curr.id] = true;
}
return acc;
},
{} as Record<string, boolean>
);
this.selectedComponents.set(initialState);
}

isCurrentProject(item: ViewOnlyLinkNodeModel): boolean {
return item.category === 'project' && item.id === this.projectId();
}

addContributor(): void {
this.dialogRef.close();
if (!this.linkName()) return;

const components = (this.config.data?.['sharedComponents'] as ViewOnlyLinkNodeModel[]) || [];
const selectedIds = Object.entries(this.selectedComponents()).filter(([component, checked]) => checked);

const selected = components
.filter((comp: ViewOnlyLinkNodeModel) =>
selectedIds.find(([id, checked]: [string, boolean]) => id === comp.id && checked)
)
.map((comp) => ({
id: comp.id,
type: 'nodes',
}));

const data = {
attributes: {
name: this.linkName(),
anonymous: this.anonymous(),
},
nodes: selected,
};

this.dialogRef.close(data);
}

onLinkNameChange(value: string): void {
this.linkName.set(value);
}

onCheckboxToggle(id: string, checked: boolean): void {
this.selectedComponents.update((prev) => ({ ...prev, [id]: checked }));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ <h2>{{ 'project.contributors.viewOnly' | translate }}</h2>
[label]="'project.contributors.createButton' | translate"
(click)="createViewLink()"
></p-button>
<osf-view-only-table [tableData]="tableData"></osf-view-only-table>

<osf-view-only-table (deleteLink)="deleteLinkItem($event)" [tableData]="viewOnlyLinks()" />
</div>
</section>
Loading