Skip to content

Commit 73d906c

Browse files
authored
fix(settings): refactored project settings (#573)
1 parent 012963c commit 73d906c

File tree

12 files changed

+85
-89
lines changed

12 files changed

+85
-89
lines changed

src/app/core/components/root/root.component.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,8 @@
2121
</div>
2222
</div>
2323

24-
<p-confirm-dialog id="dialog" styleClass="w-full md:w-6 xl:w-5" [header]="'common.dialogs.confirmation' | translate" />
24+
<p-confirm-dialog
25+
id="dialog"
26+
styleClass="w-full md:w-6 xl:w-5"
27+
[header]="'common.accessibility.confirmation' | translate"
28+
/>

src/app/features/project/settings/components/delete-project-dialog/delete-project-dialog.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<strong> {{ selectedScientist() }}</strong>
1818
</p>
1919

20-
<input pInputText class="mt-3" [ngModel]="userInput()" (ngModelChange)="onInputChange($event)" />
20+
<input pInputText class="mt-3" [(ngModel)]="userInput" />
2121
} @else {
2222
<p [innerHTML]="'project.deleteProject.dialog.noPermissionsMessage' | translate"></p>
2323
}

src/app/features/project/settings/components/delete-project-dialog/delete-project-dialog.component.ts

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
1212
import { FormsModule } from '@angular/forms';
1313
import { Router } from '@angular/router';
1414

15-
import { DeleteProject, SettingsSelectors } from '@osf/features/project/settings/store';
1615
import { ScientistsNames } from '@osf/shared/constants';
16+
import { UserPermissions } from '@osf/shared/enums';
1717
import { ToastService } from '@osf/shared/services';
1818
import { CurrentResourceSelectors } from '@osf/shared/stores';
19-
import { UserPermissions } from '@shared/enums';
19+
20+
import { DeleteProject, SettingsSelectors } from '../../store';
2021

2122
@Component({
2223
selector: 'osf-delete-project-dialog',
@@ -28,6 +29,7 @@ import { UserPermissions } from '@shared/enums';
2829
export class DeleteProjectDialogComponent {
2930
private toastService = inject(ToastService);
3031
private router = inject(Router);
32+
3133
dialogRef = inject(DynamicDialogRef);
3234
destroyRef = inject(DestroyRef);
3335

@@ -42,32 +44,22 @@ export class DeleteProjectDialogComponent {
4244
const projects = this.projects();
4345
if (!projects || !projects.length) return false;
4446

45-
return projects.every((project) => {
46-
return project.permissions?.includes(UserPermissions.Admin);
47-
});
47+
return projects.every((project) => project.permissions?.includes(UserPermissions.Admin));
4848
});
4949

5050
selectedScientist = computed(() => {
5151
const names = Object.values(this.scientistNames);
5252
return names[Math.floor(Math.random() * names.length)];
5353
});
5454

55-
actions = createDispatchMap({
56-
deleteProject: DeleteProject,
57-
});
58-
59-
isInputValid(): boolean {
60-
return this.userInput() === this.selectedScientist();
61-
}
55+
actions = createDispatchMap({ deleteProject: DeleteProject });
6256

63-
onInputChange(value: string): void {
64-
this.userInput.set(value);
65-
}
57+
isInputValid = computed(() => this.userInput() === this.selectedScientist());
6658

6759
handleDeleteProject(): void {
6860
const projects = this.projects();
6961

70-
if (!projects || !projects.length) return;
62+
if (!projects?.length) return;
7163

7264
this.actions
7365
.deleteProject(projects)

src/app/features/project/settings/mappers/settings.mapper.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import { RegionsMapper } from '@osf/shared/mappers/regions';
55
import {
66
NodeDataJsonApi,
77
NodeDetailsModel,
8-
ProjectSettingsData,
8+
ProjectSettingsDataJsonApi,
99
ProjectSettingsModel,
10-
ProjectSettingsResponseModel,
10+
ProjectSettingsResponseJsonApi,
1111
} from '../models';
1212

1313
export class SettingsMapper {
1414
static fromResponse(
15-
response: ProjectSettingsResponseModel | ProjectSettingsData,
15+
response: ProjectSettingsResponseJsonApi | ProjectSettingsDataJsonApi,
1616
nodeId: string
1717
): ProjectSettingsModel {
1818
const result = 'data' in response ? response.data : response;
@@ -38,6 +38,7 @@ export class SettingsMapper {
3838
? InstitutionsMapper.fromInstitutionsResponse(data.embeds.affiliated_institutions)
3939
: [],
4040
currentUserPermissions: data.attributes.current_user_permissions as UserPermissions[],
41+
rootId: data.relationships.root?.data?.id,
4142
parentId: data.relationships.parent?.data?.id,
4243
lastFetched: Date.now(),
4344
};

src/app/features/project/settings/models/node-details.model.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { UserPermissions } from '@osf/shared/enums';
12
import { IdName, Institution } from '@osf/shared/models';
23

34
export interface NodeDetailsModel {
@@ -7,7 +8,8 @@ export interface NodeDetailsModel {
78
isPublic: boolean;
89
region: IdName;
910
affiliatedInstitutions: Institution[];
10-
currentUserPermissions: string[];
11+
currentUserPermissions: UserPermissions[];
12+
rootId?: string;
1113
parentId?: string;
1214
lastFetched: number;
1315
}
Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,36 @@
1-
export interface ProjectSettingsAttributes {
2-
access_requests_enabled: boolean;
3-
anyone_can_edit_wiki: boolean;
4-
wiki_enabled: boolean;
5-
}
6-
7-
export interface RelatedLink {
8-
href: string;
9-
meta: Record<string, unknown>;
10-
}
11-
12-
export interface ProjectSettingsRelationships {
13-
view_only_links: {
14-
links: {
15-
related: RelatedLink;
16-
};
1+
export interface ProjectSettingsResponseJsonApi {
2+
data: ProjectSettingsDataJsonApi;
3+
meta: {
4+
version: string;
175
};
186
}
197

20-
export interface ProjectSettingsData {
8+
export interface ProjectSettingsDataJsonApi {
219
id: string;
2210
type: 'node-settings';
23-
attributes: ProjectSettingsAttributes;
24-
relationships: ProjectSettingsRelationships;
11+
attributes: ProjectSettingsAttributesJsonApi;
12+
relationships: ProjectSettingsRelationshipsJsonApi;
2513
links: {
2614
self: string;
2715
iri: string;
2816
};
2917
}
3018

31-
export interface ProjectSettingsResponseModel {
32-
data: ProjectSettingsData;
33-
meta: {
34-
version: string;
19+
export interface ProjectSettingsAttributesJsonApi {
20+
access_requests_enabled: boolean;
21+
anyone_can_edit_wiki: boolean;
22+
wiki_enabled: boolean;
23+
}
24+
25+
interface ProjectSettingsRelationshipsJsonApi {
26+
view_only_links: {
27+
links: {
28+
related: RelatedLinkJsonApi;
29+
};
3530
};
3631
}
32+
33+
interface RelatedLinkJsonApi {
34+
href: string;
35+
meta: Record<string, unknown>;
36+
}

src/app/features/project/settings/services/settings.service.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ import {
1919
NodeDataJsonApi,
2020
NodeDetailsModel,
2121
NodeResponseJsonApi,
22-
ProjectSettingsData,
22+
ProjectSettingsDataJsonApi,
2323
ProjectSettingsModel,
24-
ProjectSettingsResponseModel,
24+
ProjectSettingsResponseJsonApi,
2525
} from '../models';
2626

2727
@Injectable({
@@ -37,13 +37,13 @@ export class SettingsService {
3737

3838
getProjectSettings(nodeId: string): Observable<ProjectSettingsModel> {
3939
return this.jsonApiService
40-
.get<ProjectSettingsResponseModel>(`${this.apiUrl}/nodes/${nodeId}/settings/`)
40+
.get<ProjectSettingsResponseJsonApi>(`${this.apiUrl}/nodes/${nodeId}/settings/`)
4141
.pipe(map((response) => SettingsMapper.fromResponse(response, nodeId)));
4242
}
4343

44-
updateProjectSettings(model: ProjectSettingsData): Observable<ProjectSettingsModel> {
44+
updateProjectSettings(model: ProjectSettingsDataJsonApi): Observable<ProjectSettingsModel> {
4545
return this.jsonApiService
46-
.patch<ProjectSettingsResponseModel>(`${this.apiUrl}/nodes/${model.id}/settings/`, { data: model })
46+
.patch<ProjectSettingsResponseJsonApi>(`${this.apiUrl}/nodes/${model.id}/settings/`, { data: model })
4747
.pipe(map((response) => SettingsMapper.fromResponse(response, model.id)));
4848
}
4949

src/app/features/project/settings/settings.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@
3636
(anyoneCanEditWikiEmitValue)="onAnyoneCanEditWikiRequestChange($event)"
3737
[wikiEnabled]="wikiEnabled()"
3838
[anyoneCanEditWiki]="anyoneCanEditWiki()"
39-
[title]="title()"
39+
[title]="projectDetails().title"
4040
[isPublic]="projectDetails().isPublic"
4141
/>
4242
}
4343

4444
<osf-project-setting-notifications
4545
(notificationEmitValue)="onNotificationRequestChange($event)"
46-
[title]="title()"
46+
[title]="projectDetails().title"
4747
[notifications]="notifications()"
4848
/>
4949

src/app/features/project/settings/settings.component.ts

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,17 @@ import { TranslatePipe } from '@ngx-translate/core';
44

55
import { map, of } from 'rxjs';
66

7-
import { ChangeDetectionStrategy, Component, computed, effect, inject, OnInit, signal } from '@angular/core';
7+
import { ChangeDetectionStrategy, Component, effect, inject, OnInit, signal } from '@angular/core';
88
import { toSignal } from '@angular/core/rxjs-interop';
99
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
1010
import { ActivatedRoute } from '@angular/router';
1111

1212
import { UserSelectors } from '@core/store/user';
1313
import { LoadingSpinnerComponent, SubHeaderComponent } from '@osf/shared/components';
14-
import { ResourceType, SubscriptionEvent, SubscriptionFrequency, UserPermissions } from '@osf/shared/enums';
15-
import { IS_MEDIUM } from '@osf/shared/helpers';
14+
import { ResourceType, SubscriptionEvent, SubscriptionFrequency } from '@osf/shared/enums';
1615
import { Institution, UpdateNodeRequestModel, ViewOnlyLinkModel } from '@osf/shared/models';
1716
import { CustomConfirmationService, CustomDialogService, LoaderService, ToastService } from '@osf/shared/services';
1817
import {
19-
CurrentResourceSelectors,
2018
DeleteViewOnlyLink,
2119
FetchViewOnlyLinks,
2220
GetResource,
@@ -34,7 +32,7 @@ import {
3432
SettingsViewOnlyLinksCardComponent,
3533
SettingsWikiCardComponent,
3634
} from './components';
37-
import { ProjectDetailsModel, ProjectSettingsAttributes, ProjectSettingsData } from './models';
35+
import { ProjectDetailsModel, ProjectSettingsAttributesJsonApi, ProjectSettingsDataJsonApi } from './models';
3836
import {
3937
DeleteInstitution,
4038
DeleteProject,
@@ -76,18 +74,16 @@ export class SettingsComponent implements OnInit {
7674

7775
readonly projectId = toSignal(this.route.parent?.params.pipe(map((params) => params['id'])) ?? of(undefined));
7876

77+
currentUser = select(UserSelectors.getCurrentUser);
7978
settings = select(SettingsSelectors.getSettings);
8079
notifications = select(SettingsSelectors.getNotificationSubscriptions);
8180
areNotificationsLoading = select(SettingsSelectors.areNotificationsLoading);
8281
projectDetails = select(SettingsSelectors.getProjectDetails);
8382
areProjectDetailsLoading = select(SettingsSelectors.areProjectDetailsLoading);
83+
hasAdminAccess = select(SettingsSelectors.hasAdminAccess);
84+
hasWriteAccess = select(SettingsSelectors.hasWriteAccess);
8485
viewOnlyLinks = select(ViewOnlyLinkSelectors.getViewOnlyLinks);
8586
isViewOnlyLinksLoading = select(ViewOnlyLinkSelectors.isViewOnlyLinksLoading);
86-
currentUser = select(UserSelectors.getCurrentUser);
87-
currentProject = select(CurrentResourceSelectors.getCurrentResource);
88-
isMedium = toSignal(inject(IS_MEDIUM));
89-
90-
rootProjectId = computed(() => this.currentProject()?.rootResourceId);
9187

9288
actions = createDispatchMap({
9389
getSettings: GetProjectSettings,
@@ -108,11 +104,6 @@ export class SettingsComponent implements OnInit {
108104
wikiEnabled = signal(false);
109105
anyoneCanEditWiki = signal(false);
110106
anyoneCanComment = signal(false);
111-
title = signal('');
112-
113-
userPermissions = computed(() => this.projectDetails()?.currentUserPermissions || []);
114-
hasAdminAccess = computed(() => this.userPermissions().includes(UserPermissions.Admin));
115-
hasWriteAccess = computed(() => this.userPermissions().includes(UserPermissions.Write));
116107

117108
constructor() {
118109
this.setupEffects();
@@ -190,14 +181,19 @@ export class SettingsComponent implements OnInit {
190181
}
191182

192183
deleteProject(): void {
193-
const dialogWidth = this.isMedium() ? '500px' : '95vw';
194-
195-
this.actions.getComponentsTree(this.rootProjectId() || this.projectId(), this.projectId(), ResourceType.Project);
184+
this.loaderService.show();
196185

197-
this.customDialogService.open(DeleteProjectDialogComponent, {
198-
header: 'project.deleteProject.dialog.deleteProject',
199-
width: dialogWidth,
200-
});
186+
this.actions
187+
.getComponentsTree(this.projectDetails()?.rootId || this.projectId(), this.projectId(), ResourceType.Project)
188+
.subscribe({
189+
next: () => {
190+
this.loaderService.hide();
191+
this.customDialogService.open(DeleteProjectDialogComponent, {
192+
header: 'project.deleteProject.dialog.deleteProject',
193+
width: '500px',
194+
});
195+
},
196+
});
201197
}
202198

203199
removeAffiliation(affiliation: Institution): void {
@@ -217,7 +213,7 @@ export class SettingsComponent implements OnInit {
217213
}
218214

219215
private syncSettingsChanges(changedField: string, value: boolean): void {
220-
const payload: Partial<ProjectSettingsAttributes> = {};
216+
const payload: Partial<ProjectSettingsAttributesJsonApi> = {};
221217

222218
switch (changedField) {
223219
case 'access_requests_enabled':
@@ -231,7 +227,7 @@ export class SettingsComponent implements OnInit {
231227
id: this.projectId(),
232228
type: 'node-settings',
233229
attributes: { ...payload },
234-
} as ProjectSettingsData;
230+
} as ProjectSettingsDataJsonApi;
235231

236232
this.loaderService.show();
237233

@@ -253,14 +249,6 @@ export class SettingsComponent implements OnInit {
253249
}
254250
});
255251

256-
effect(() => {
257-
const project = this.projectDetails();
258-
259-
if (project) {
260-
this.title.set(project.title);
261-
}
262-
});
263-
264252
effect(() => {
265253
const id = this.projectId();
266254

src/app/features/project/settings/store/settings.actions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { SubscriptionFrequency } from '@osf/shared/enums';
22
import { NodeShortInfoModel, UpdateNodeRequestModel } from '@shared/models';
33

4-
import { ProjectSettingsData } from '../models';
4+
import { ProjectSettingsDataJsonApi } from '../models';
55

66
export class GetProjectSettings {
77
static readonly type = '[Project Settings] Get Project Settings';
@@ -18,7 +18,7 @@ export class GetProjectDetails {
1818
export class UpdateProjectSettings {
1919
static readonly type = '[Project Settings] Update Project Settings';
2020

21-
constructor(public payload: ProjectSettingsData) {}
21+
constructor(public payload: ProjectSettingsDataJsonApi) {}
2222
}
2323

2424
export class UpdateProjectDetails {

0 commit comments

Comments
 (0)