From 725bcedc31eaa0ed82c9c76fb985278ad497feb4 Mon Sep 17 00:00:00 2001 From: DarKylX Date: Wed, 21 Oct 2026 13:38:43 +0300 Subject: [PATCH] fix: confirm removal from program application teams --- .../program/program-management.model.ts | 9 ++++ .../program-management-http.adapter.spec.ts | 15 +++++- .../program-management-http.adapter.ts | 1 + .../management/management.component.html | 31 ++++++++++- .../management/management.component.spec.ts | 51 ++++++++++++++++++- 5 files changed, 102 insertions(+), 5 deletions(-) diff --git a/projects/social_platform/src/app/domain/program/program-management.model.ts b/projects/social_platform/src/app/domain/program/program-management.model.ts index 913dd1d5a..a08af1b82 100644 --- a/projects/social_platform/src/app/domain/program/program-management.model.ts +++ b/projects/social_platform/src/app/domain/program/program-management.model.ts @@ -149,10 +149,19 @@ export interface ManagementSelection { projects?: ManagementSelectionProject[]; } export interface ParticipantRemovalPreview { + confirmationVersion: 2; previewToken: string; participantCount: number; applications: { id: number; projectId: number; name: string; submitted: boolean }[]; assignmentsCount: number; + teamChanges: { + id: number; + projectId: number; + name: string; + submitted: boolean; + members: { id: number; name: string }[]; + invitationsCount: number; + }[]; } export interface ManagementSettingsWrite { expectedUpdatedAt: string; diff --git a/projects/social_platform/src/app/infrastructure/adapters/program/program-management-http.adapter.spec.ts b/projects/social_platform/src/app/infrastructure/adapters/program/program-management-http.adapter.spec.ts index 6639e0e2e..72ec267e0 100644 --- a/projects/social_platform/src/app/infrastructure/adapters/program/program-management-http.adapter.spec.ts +++ b/projects/social_platform/src/app/infrastructure/adapters/program/program-management-http.adapter.spec.ts @@ -141,11 +141,22 @@ describe("Контракт HTTP панели организатора", () => { .previewParticipantRemoval(4, [1, 21]) .subscribe(result => expect(result.previewToken).toBe("proof")); const preview = http.expectOne(r => r.url.endsWith("/remove-preview/")); - preview.flush({ preview_token: "proof", participant_count: 2, applications: [] }); + preview.flush({ + confirmation_version: 2, + preview_token: "proof", + participant_count: 2, + applications: [], + team_changes: [], + assignments_count: 0, + }); const failed = vi.fn(); adapter.removeParticipants(4, [1, 21], "proof").subscribe({ error: failed }); const removal = http.expectOne(r => r.url.endsWith("/participants/remove/")); - expect(removal.request.body).toEqual({ ids: [1, 21], preview_token: "proof" }); + expect(removal.request.body).toEqual({ + ids: [1, 21], + preview_token: "proof", + confirmation_version: 2, + }); removal.flush({ detail: "Изменено" }, { status: 409, statusText: "Conflict" }); expect(failed).toHaveBeenCalledOnce(); http.expectNone(r => r.url.endsWith("/participants/remove/")); diff --git a/projects/social_platform/src/app/infrastructure/adapters/program/program-management-http.adapter.ts b/projects/social_platform/src/app/infrastructure/adapters/program/program-management-http.adapter.ts index ab7aeaba7..dd1399048 100644 --- a/projects/social_platform/src/app/infrastructure/adapters/program/program-management-http.adapter.ts +++ b/projects/social_platform/src/app/infrastructure/adapters/program/program-management-http.adapter.ts @@ -88,6 +88,7 @@ export class ProgramManagementHttpAdapter implements ProgramManagementRepository return this.api.post<{ removed: number }>(`${this.root(id)}/participants/remove/`, { ids, previewToken, + confirmationVersion: 2, }); } private participantParams(q: ManagementQuery): HttpParams { diff --git a/projects/social_platform/src/app/ui/pages/program/management/management.component.html b/projects/social_platform/src/app/ui/pages/program/management/management.component.html index 90b9d56c5..f5c265514 100644 --- a/projects/social_platform/src/app/ui/pages/program/management/management.component.html +++ b/projects/social_platform/src/app/ui/pages/program/management/management.component.html @@ -866,7 +866,36 @@

В программе пока нет материалов

Удалить участников из программы?

Участников: {{ removal.preview.participantCount }}. Аккаунты на платформе сохранятся.

-

Участники останутся в командах проектов на платформе.

+

+ Участники будут удалены из команд проектов-заявок этой программы. Команды исходных проектов + на платформе сохранятся. +

+ @if (removal.preview.teamChanges.length) { +
+

Изменятся команды заявок

+
    + @for (change of removal.preview.teamChanges; track change.id) { +
  • + {{ change.name }} + @if (change.members.length) { +

    + Удаляем из команды: + @for (member of change.members; track member.id; let last = $last) { + {{ member.name }}{{ last ? "" : ", " }} + } +

    + } + @if (change.invitationsCount) { +

    Приглашений в заявку к отзыву: {{ change.invitationsCount }}.

    + } + @if (change.submitted) { +

    Заявка уже сдана. Сохраненные оценки не изменятся.

    + } +
  • + } +
+
+ } @if (removal.preview.applications.length) {
Среди выбранных есть руководители проектов diff --git a/projects/social_platform/src/app/ui/pages/program/management/management.component.spec.ts b/projects/social_platform/src/app/ui/pages/program/management/management.component.spec.ts index e6e0481a6..d60707479 100644 --- a/projects/social_platform/src/app/ui/pages/program/management/management.component.spec.ts +++ b/projects/social_platform/src/app/ui/pages/program/management/management.component.spec.ts @@ -15,6 +15,7 @@ import { ManagementProject, ManagementProjectsPage, ProgramManagement, + ParticipantRemovalPreview, } from "@domain/program/program-management.model"; import { ProgramManagementComponent } from "./management.component"; import { ProgramProjectAssignmentSelection } from "@api/program/facades/detail/program-project-assignment-selection.service"; @@ -189,8 +190,15 @@ describe("Списки управления программой в DOM", () => context: null as ManagementContext | null, api: { selection: vi.fn(() => of({ ids: Array.from({ length: 41 }, (_, i) => i + 1) })), - previewParticipantRemoval: vi.fn(() => - of({ previewToken: "proof", participantCount: 1, applications: [], assignmentsCount: 0 }), + previewParticipantRemoval: vi.fn<() => Observable>(() => + of({ + confirmationVersion: 2, + previewToken: "proof", + participantCount: 1, + applications: [], + assignmentsCount: 0, + teamChanges: [], + }), ), removeParticipants: vi.fn(() => of({ removed: 1 })), }, @@ -624,4 +632,43 @@ describe("Списки управления программой в DOM", () => expect(component.selectedRows().size).toBe(0); expect(state.retry).toHaveBeenCalledOnce(); }); + it("подтверждение показывает команду заявки и сохраняемый исходный проект отдельно", async () => { + const { component, state, harness, element } = await setup(); + state.api.previewParticipantRemoval.mockReturnValue( + of({ + confirmationVersion: 2, + previewToken: "proof", + participantCount: 1, + applications: [], + assignmentsCount: 0, + teamChanges: [ + { + id: 11, + projectId: 91, + name: "Заявка команды", + submitted: true, + members: [{ id: 51, name: "Анна" }], + invitationsCount: 1, + }, + ], + }), + ); + component.previewParticipantRemoval([1]); + harness.detectChanges(); + await vi.waitFor(() => { + harness.detectChanges(); + expect( + document.querySelector('[role="dialog"][aria-labelledby="participant-removal-title"]'), + ).toBeTruthy(); + }); + const dialog = document.querySelector( + '[role="dialog"][aria-labelledby="participant-removal-title"]', + )!; + expect(dialog.textContent).toContain("Команды исходных проектов на платформе сохранятся"); + expect(dialog.textContent).toContain("Заявка команды"); + expect(dialog.textContent).toContain("Анна"); + expect(dialog.textContent).toContain("Сохраненные оценки не изменятся"); + expect(state.api.removeParticipants).not.toHaveBeenCalled(); + expect(element().querySelector(".management__participants")).toBeTruthy(); + }); });