Skip to content

Commit 6e30deb

Browse files
authored
Merge pull request #685 from mkovalua/feature/ENG-9127-v2
ENG-9127 implement coping of contributors from parent project
2 parents 3a49725 + 92e7cb2 commit 6e30deb

File tree

12 files changed

+109
-11
lines changed

12 files changed

+109
-11
lines changed

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

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import {
4949
AcceptRequestAccess,
5050
AddContributor,
5151
BulkAddContributors,
52+
BulkAddContributorsFromParentProject,
5253
BulkUpdateContributors,
5354
ContributorsSelectors,
5455
CreateViewOnlyLink,
@@ -159,6 +160,7 @@ export class ContributorsComponent implements OnInit {
159160
deleteContributor: DeleteContributor,
160161
bulkUpdateContributors: BulkUpdateContributors,
161162
bulkAddContributors: BulkAddContributors,
163+
bulkAddContributorsFromParentProject: BulkAddContributorsFromParentProject,
162164
addContributor: AddContributor,
163165
createViewOnlyLink: CreateViewOnlyLink,
164166
deleteViewOnlyLink: DeleteViewOnlyLink,
@@ -246,17 +248,19 @@ export class ContributorsComponent implements OnInit {
246248

247249
openAddContributorDialog() {
248250
const addedContributorIds = this.initialContributors().map((x) => x.userId);
249-
const rootParentId = this.resourceDetails().rootParentId ?? this.resourceId();
251+
const resourceDetails = this.resourceDetails();
252+
const resourceId = this.resourceId();
253+
const rootParentId = resourceDetails.rootParentId ?? resourceId;
250254

251255
this.loaderService.show();
252256

253257
this.actions
254-
.getResourceWithChildren(rootParentId, this.resourceId(), this.resourceType())
258+
.getResourceWithChildren(rootParentId, resourceId, this.resourceType())
255259
.pipe(takeUntilDestroyed(this.destroyRef))
256260
.subscribe(() => {
257261
this.loaderService.hide();
258262

259-
const components = this.mapNodesToComponentCheckboxItems(this.resourceChildren(), this.resourceId());
263+
const components = this.mapNodesToComponentCheckboxItems(this.resourceChildren(), resourceId);
260264

261265
this.customDialogService
262266
.open(AddContributorDialogComponent, {
@@ -265,15 +269,22 @@ export class ContributorsComponent implements OnInit {
265269
data: {
266270
addedContributorIds,
267271
components,
268-
resourceName: this.resourceDetails().title,
272+
resourceName: resourceDetails.title,
273+
parentResourceName: resourceDetails.parent?.title,
274+
allowAddingContributorsFromParentProject:
275+
this.resourceType() === ResourceType.Project &&
276+
resourceDetails.rootParentId &&
277+
resourceDetails.rootParentId !== resourceId,
269278
},
270279
})
271280
.onClose.pipe(
272281
filter((res: ContributorDialogAddModel) => !!res),
273282
takeUntilDestroyed(this.destroyRef)
274283
)
275284
.subscribe((res: ContributorDialogAddModel) => {
276-
if (res.type === AddContributorType.Unregistered) {
285+
if (res.type === AddContributorType.ParentProject) {
286+
this.addContributorsFromParentProjectToComponents();
287+
} else if (res.type === AddContributorType.Unregistered) {
277288
this.openAddUnregisteredContributorDialog();
278289
} else {
279290
this.addContributorsToComponents(res);
@@ -303,6 +314,13 @@ export class ContributorsComponent implements OnInit {
303314
.subscribe(() => this.toastService.showSuccess('project.contributors.toastMessages.multipleAddSuccessMessage'));
304315
}
305316

317+
private addContributorsFromParentProjectToComponents(): void {
318+
this.actions
319+
.bulkAddContributorsFromParentProject(this.resourceId(), this.resourceType())
320+
.pipe(takeUntilDestroyed(this.destroyRef))
321+
.subscribe(() => this.toastService.showSuccess('project.contributors.toastMessages.multipleAddSuccessMessage'));
322+
}
323+
306324
openAddUnregisteredContributorDialog() {
307325
this.customDialogService
308326
.open(AddUnregisteredContributorDialogComponent, {

src/app/shared/components/contributors/add-contributor-dialog/add-contributor-dialog.component.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,22 @@
6565
</div>
6666
}
6767

68+
@if (allowAddingContributorsFromParentProject() && this.isSearchState()) {
69+
<div class="flex justify-content-center mt-2">
70+
<p-button
71+
class="w-full"
72+
styleClass="w-full"
73+
severity="secondary"
74+
(onClick)="addSourceProjectContributors()"
75+
[label]="
76+
'project.contributors.addDialog.addingContributorsFromParentProject'
77+
| translate: { projectName: parentResourceName() }
78+
"
79+
>
80+
</p-button>
81+
</div>
82+
}
83+
6884
<div class="flex gap-2 mt-6">
6985
<p-button
7086
class="w-full"

src/app/shared/components/contributors/add-contributor-dialog/add-contributor-dialog.component.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ export class AddContributorDialogComponent implements OnInit, OnDestroy {
6969
readonly selectedUsers = signal<ContributorAddModel[]>([]);
7070
readonly components = signal<ComponentCheckboxItemModel[]>([]);
7171
readonly resourceName = signal<string>('');
72+
readonly parentResourceName = signal<string>('');
73+
readonly allowAddingContributorsFromParentProject = signal<boolean>(false);
7274

7375
readonly contributorNames = computed(() =>
7476
this.selectedUsers()
@@ -113,6 +115,10 @@ export class AddContributorDialogComponent implements OnInit, OnDestroy {
113115
}
114116
}
115117

118+
addSourceProjectContributors(): void {
119+
this.closeDialogWithData(AddContributorType.ParentProject);
120+
}
121+
116122
addUnregistered(): void {
117123
this.dialogRef.close({
118124
data: [],
@@ -129,7 +135,8 @@ export class AddContributorDialogComponent implements OnInit, OnDestroy {
129135
private initializeDialogData(): void {
130136
this.selectedUsers.set([]);
131137

132-
const { components, resourceName } = this.config.data || {};
138+
const { components, resourceName, parentResourceName, allowAddingContributorsFromParentProject } =
139+
this.config.data || {};
133140

134141
if (components) {
135142
this.components.set(components);
@@ -138,16 +145,24 @@ export class AddContributorDialogComponent implements OnInit, OnDestroy {
138145
if (resourceName) {
139146
this.resourceName.set(resourceName);
140147
}
148+
149+
if (allowAddingContributorsFromParentProject) {
150+
this.allowAddingContributorsFromParentProject.set(allowAddingContributorsFromParentProject);
151+
}
152+
153+
if (parentResourceName) {
154+
this.parentResourceName.set(parentResourceName);
155+
}
141156
}
142157

143-
private closeDialogWithData(): void {
158+
private closeDialogWithData(AddContributorTypeValue = AddContributorType.Registered): void {
144159
const childNodeIds = this.components()
145160
.filter((c) => c.checked && !c.isCurrent)
146161
.map((c) => c.id);
147162

148163
this.dialogRef.close({
149164
data: this.selectedUsers(),
150-
type: AddContributorType.Registered,
165+
type: AddContributorTypeValue,
151166
childNodeIds: childNodeIds.length > 0 ? childNodeIds : undefined,
152167
} as ContributorDialogAddModel);
153168
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export enum AddContributorType {
22
Registered = 1,
33
Unregistered,
4+
ParentProject,
45
}

src/app/shared/mappers/nodes/base-node.mapper.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export class BaseNodeMapper {
6060
wikiEnabled: data.attributes.wiki_enabled,
6161
customCitation: data.attributes.custom_citation || undefined,
6262
rootParentId: data.relationships.root?.data?.id,
63+
parent: data.embeds?.parent?.data ? this.getNodeData(data.embeds?.parent.data) : undefined,
6364
};
6465
}
6566

src/app/shared/models/nodes/base-node-embeds-json-api.model.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
BaseNodeDataJsonApi,
23
ContributorDataJsonApi,
34
IdentifierAttributes,
45
IdentifiersJsonApiData,
@@ -23,6 +24,9 @@ export interface BaseNodeEmbedsJsonApi {
2324
region?: {
2425
data: RegionDataJsonApi;
2526
};
27+
parent?: {
28+
data: BaseNodeDataJsonApi;
29+
};
2630
}
2731

2832
export interface JsonApiResource<T extends string, A> {

src/app/shared/models/nodes/base-node.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export interface BaseNodeModel {
2323
wikiEnabled: boolean;
2424
rootParentId?: string;
2525
type: string;
26+
parent?: BaseNodeModel;
2627
}
2728

2829
export interface NodeModel extends BaseNodeModel {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,12 @@ export class ContributorsService {
164164
.pipe(map((contributor) => ContributorsMapper.getContributor(contributor.data)));
165165
}
166166

167+
addContributorsFromProject(resourceType: ResourceType, resourceId: string): Observable<void> {
168+
const baseUrl = `${this.getBaseUrl(resourceType, resourceId)}/?copy_contributors_from_parent_project=true`;
169+
const contributorData = { data: { type: AddContributorType.ParentProject } };
170+
return this.jsonApiService.patch(baseUrl, contributorData);
171+
}
172+
167173
deleteContributor(resourceType: ResourceType, resourceId: string, userId: string): Observable<void> {
168174
const baseUrl = `${this.getBaseUrl(resourceType, resourceId)}/${userId}/`;
169175

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,11 @@ export class ResourceGuidService {
6666

6767
getResourceDetails(resourceId: string, resourceType: ResourceType): Observable<BaseNodeModel> {
6868
const resourcePath = this.urlMap.get(resourceType);
69-
69+
const params: Record<string, unknown> = {
70+
embed: 'parent',
71+
};
7072
return this.jsonApiService
71-
.get<ResponseDataJsonApi<BaseNodeDataJsonApi>>(`${this.apiUrl}/${resourcePath}/${resourceId}/`)
73+
.get<ResponseDataJsonApi<BaseNodeDataJsonApi>>(`${this.apiUrl}/${resourcePath}/${resourceId}/`, params)
7274
.pipe(map((response) => BaseNodeMapper.getNodeData(response.data)));
7375
}
7476

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,15 @@ export class BulkAddContributors {
6262
) {}
6363
}
6464

65+
export class BulkAddContributorsFromParentProject {
66+
static readonly type = '[Contributors] Bulk Add Contributors From Parent Project';
67+
68+
constructor(
69+
public resourceId: string | undefined | null,
70+
public resourceType: ResourceType | undefined
71+
) {}
72+
}
73+
6574
export class DeleteContributor {
6675
static readonly type = '[Contributors] Delete Contributor';
6776

0 commit comments

Comments
 (0)