Skip to content

Commit a5f1ed2

Browse files
committed
feat(contributors): delete contributors from all components
1 parent 16cc0bf commit a5f1ed2

File tree

10 files changed

+139
-23
lines changed

10 files changed

+139
-23
lines changed

src/app/features/contributors/contributors.component.ts

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
AddContributorDialogComponent,
2929
AddUnregisteredContributorDialogComponent,
3030
ContributorsTableComponent,
31+
RemoveContributorDialogComponent,
3132
RequestAccessTableComponent,
3233
} from '@osf/shared/components/contributors';
3334
import { SearchInputComponent } from '@osf/shared/components/search-input/search-input.component';
@@ -397,26 +398,37 @@ export class ContributorsComponent implements OnInit, OnDestroy {
397398
removeContributor(contributor: ContributorModel) {
398399
const isDeletingSelf = contributor.userId === this.currentUser()?.id;
399400

400-
this.customConfirmationService.confirmDelete({
401-
headerKey: 'project.contributors.removeDialog.title',
402-
messageKey: 'project.contributors.removeDialog.message',
403-
messageParams: { name: contributor.fullName },
404-
acceptLabelKey: 'common.buttons.remove',
405-
onConfirm: () => {
406-
this.actions
407-
.deleteContributor(this.resourceId(), this.resourceType(), contributor.userId, isDeletingSelf)
408-
.pipe(takeUntilDestroyed(this.destroyRef))
409-
.subscribe(() => {
410-
this.toastService.showSuccess('project.contributors.removeDialog.successMessage', {
411-
name: contributor.fullName,
412-
});
401+
this.customDialogService
402+
.open(RemoveContributorDialogComponent, {
403+
header: 'project.contributors.removeDialog.title',
404+
width: '448px',
405+
data: {
406+
messageKey: 'project.contributors.removeDialog.message',
407+
messageParams: { name: contributor.fullName },
408+
},
409+
})
410+
.onClose.pipe(
411+
filter((res) => res !== undefined),
412+
switchMap((removeFromChildren: boolean) =>
413+
this.actions.deleteContributor(
414+
this.resourceId(),
415+
this.resourceType(),
416+
contributor.userId,
417+
isDeletingSelf,
418+
removeFromChildren
419+
)
420+
),
421+
takeUntilDestroyed(this.destroyRef)
422+
)
423+
.subscribe(() => {
424+
this.toastService.showSuccess('project.contributors.removeDialog.successMessage', {
425+
name: contributor.fullName,
426+
});
413427

414-
if (isDeletingSelf) {
415-
this.router.navigate(['/']);
416-
}
417-
});
418-
},
419-
});
428+
if (isDeletingSelf) {
429+
this.router.navigate(['/']);
430+
}
431+
});
420432
}
421433

422434
loadMoreContributors(): void {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './add-contributor-dialog/add-contributor-dialog.component';
22
export * from './add-unregistered-contributor-dialog/add-unregistered-contributor-dialog.component';
33
export * from './contributors-table/contributors-table.component';
4+
export * from './remove-contributor-dialog/remove-contributor-dialog.component';
45
export * from './request-access-table/request-access-table.component';
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<div class="flex flex-column">
2+
<p [innerHTML]="messageKey ? (messageKey | translate: messageParams) : ''"></p>
3+
4+
<div class="p-field-radiobutton flex align-items-center mt-3 mb-2">
5+
<p-radioButton name="removeMode" [value]="false" [(ngModel)]="selectedOption" inputId="projectOnly">
6+
</p-radioButton>
7+
<label for="projectOnly" class="ml-2">{{ 'project.contributors.removeDialog.thisProjectOnly' | translate }}</label>
8+
</div>
9+
<div class="p-field-radiobutton flex align-items-center mb-3">
10+
<p-radioButton name="removeMode" [value]="true" [(ngModel)]="selectedOption" inputId="projectAll"> </p-radioButton>
11+
<label for="projectAll" class="ml-2">{{
12+
'project.contributors.removeDialog.thisProjectAndComponents' | translate
13+
}}</label>
14+
</div>
15+
16+
<div class="flex gap-2 mt-3">
17+
<p-button
18+
class="w-full"
19+
styleClass="w-full"
20+
(click)="cancel()"
21+
severity="info"
22+
[label]="'common.buttons.cancel' | translate"
23+
></p-button>
24+
<p-button
25+
class="w-full"
26+
styleClass="w-full"
27+
(click)="confirm()"
28+
severity="danger"
29+
[label]="'common.buttons.remove' | translate"
30+
></p-button>
31+
</div>
32+
</div>

src/app/shared/components/contributors/remove-contributor-dialog/remove-contributor-dialog.component.scss

Whitespace-only changes.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { RemoveContributorDialogComponent } from './remove-contributor-dialog.component';
4+
5+
describe('RemoveContributorDialogComponent', () => {
6+
let component: RemoveContributorDialogComponent;
7+
let fixture: ComponentFixture<RemoveContributorDialogComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
imports: [RemoveContributorDialogComponent],
12+
}).compileComponents();
13+
14+
fixture = TestBed.createComponent(RemoveContributorDialogComponent);
15+
component = fixture.componentInstance;
16+
fixture.detectChanges();
17+
});
18+
19+
it('should create', () => {
20+
expect(component).toBeTruthy();
21+
});
22+
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { TranslatePipe } from '@ngx-translate/core';
2+
3+
import { Button } from 'primeng/button';
4+
import { DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';
5+
import { RadioButton } from 'primeng/radiobutton';
6+
7+
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
8+
import { FormsModule } from '@angular/forms';
9+
10+
@Component({
11+
selector: 'osf-remove-contributor-dialog',
12+
imports: [RadioButton, FormsModule, Button, TranslatePipe],
13+
templateUrl: './remove-contributor-dialog.component.html',
14+
styleUrl: './remove-contributor-dialog.component.scss',
15+
changeDetection: ChangeDetectionStrategy.OnPush,
16+
})
17+
export class RemoveContributorDialogComponent {
18+
readonly dialogRef = inject(DynamicDialogRef);
19+
readonly config = inject(DynamicDialogConfig);
20+
selectedOption = false;
21+
22+
get messageKey(): string | undefined {
23+
return this.config?.data?.messageKey as string | undefined;
24+
}
25+
26+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
27+
get messageParams(): any {
28+
return this.config?.data?.messageParams;
29+
}
30+
31+
confirm(): void {
32+
this.dialogRef.close(this.selectedOption);
33+
}
34+
35+
cancel(): void {
36+
this.dialogRef.close();
37+
}
38+
}

src/app/shared/services/contributors.service.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,16 @@ export class ContributorsService {
170170
return this.jsonApiService.patch(baseUrl, contributorData);
171171
}
172172

173-
deleteContributor(resourceType: ResourceType, resourceId: string, userId: string): Observable<void> {
174-
const baseUrl = `${this.getBaseUrl(resourceType, resourceId)}/${userId}/`;
173+
deleteContributor(
174+
resourceType: ResourceType,
175+
resourceId: string,
176+
userId: string,
177+
removeFromChildren = false
178+
): Observable<void> {
179+
let baseUrl = `${this.getBaseUrl(resourceType, resourceId)}/${userId}/`;
180+
if (removeFromChildren) {
181+
baseUrl = baseUrl.concat('?propagate_to_children=true');
182+
}
175183

176184
return this.jsonApiService.delete(baseUrl);
177185
}

src/app/shared/stores/contributors/contributors.actions.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ export class DeleteContributor {
8080
public resourceId: string | undefined | null,
8181
public resourceType: ResourceType | undefined,
8282
public contributorId: string,
83-
public skipRefresh = false
83+
public skipRefresh = false,
84+
public removeFromChildren = false
8485
) {}
8586
}
8687

src/app/shared/stores/contributors/contributors.state.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ export class ContributorsState {
251251
});
252252

253253
return this.contributorsService
254-
.deleteContributor(action.resourceType, action.resourceId, action.contributorId)
254+
.deleteContributor(action.resourceType, action.resourceId, action.contributorId, action.removeFromChildren)
255255
.pipe(
256256
tap(() => {
257257
if (!action.skipRefresh) {

src/assets/i18n/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,8 @@
618618
},
619619
"removeDialog": {
620620
"title": "Remove contributor",
621+
"thisProjectOnly": "This project only",
622+
"thisProjectAndComponents": "This project and all it's components",
621623
"message": "Are you sure you want to remove <b>{{name}}</b> contributor?",
622624
"successMessage": "Contributor {{name}} successfully removed."
623625
},

0 commit comments

Comments
 (0)