Skip to content

Commit e25084e

Browse files
committed
SF-3554 Create chapters when adding draft to project
1 parent a6bf0dc commit e25084e

File tree

12 files changed

+215
-65
lines changed

12 files changed

+215
-65
lines changed

src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-dialog/draft-apply-dialog.component.spec.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { createTestProjectProfile } from 'realtime-server/lib/esm/scriptureforge
1111
import { TextInfoPermission } from 'realtime-server/lib/esm/scriptureforge/models/text-info-permission';
1212
import { of } from 'rxjs';
1313
import { anything, mock, verify, when } from 'ts-mockito';
14+
import { ActivatedProjectService } from 'xforge-common/activated-project.service';
1415
import { OnlineStatusService } from 'xforge-common/online-status.service';
1516
import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module';
1617
import { TestOnlineStatusService } from 'xforge-common/test-online-status.service';
@@ -22,11 +23,14 @@ import { TextDoc } from '../../../core/models/text-doc';
2223
import { SFProjectService } from '../../../core/sf-project.service';
2324
import { TextDocService } from '../../../core/text-doc.service';
2425
import { CustomValidatorState } from '../../../shared/sfvalidators';
26+
import { DraftGenerationService } from '../draft-generation.service';
2527
import { DraftApplyDialogComponent } from './draft-apply-dialog.component';
2628

29+
const mockedActivatedProjectService = mock(ActivatedProjectService);
2730
const mockedUserProjectsService = mock(SFUserProjectsService);
2831
const mockedProjectService = mock(SFProjectService);
2932
const mockedUserService = mock(UserService);
33+
const mockedDraftGenerationService = mock(DraftGenerationService);
3034
const mockedDialogRef = mock(MatDialogRef);
3135
const mockedTextDocService = mock(TextDocService);
3236

@@ -39,7 +43,7 @@ const ROUTES: Route[] = [{ path: 'projects', component: MockComponent }];
3943

4044
let env: TestEnvironment;
4145

42-
describe('DraftApplyDialogComponent', () => {
46+
fdescribe('DraftApplyDialogComponent', () => {
4347
configureTestingModule(() => ({
4448
imports: [
4549
TestTranslocoModule,
@@ -48,9 +52,11 @@ describe('DraftApplyDialogComponent', () => {
4852
TestOnlineStatusModule.forRoot()
4953
],
5054
providers: [
55+
{ provide: ActivatedProjectService, useMock: mockedActivatedProjectService },
5156
{ provide: SFUserProjectsService, useMock: mockedUserProjectsService },
5257
{ provide: SFProjectService, useMock: mockedProjectService },
5358
{ provide: UserService, useMock: mockedUserService },
59+
{ provide: DraftGenerationService, useMock: mockedDraftGenerationService },
5460
{ provide: TextDocService, useMock: mockedTextDocService },
5561
{ provide: OnlineStatusService, useClass: TestOnlineStatusService },
5662
{ provide: MatDialogRef, useMock: mockedDialogRef },
@@ -343,7 +349,9 @@ class TestEnvironment {
343349
const mockedTextDoc = {
344350
getNonEmptyVerses: (): string[] => ['verse_1_1', 'verse_1_2', 'verse_1_3']
345351
} as TextDoc;
352+
when(mockedActivatedProjectService.projectId$).thenReturn(of('project01'));
346353
when(mockedProjectService.getText(anything())).thenResolve(mockedTextDoc);
347354
when(mockedTextDocService.userHasGeneralEditRight(anything())).thenReturn(true);
355+
when(mockedDraftGenerationService.getDraftChaptersForBook(anything(), anything())).thenReturn(of([1, 2]));
348356
}
349357
}

src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-apply-dialog/draft-apply-dialog.component.ts

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
import { CommonModule } from '@angular/common';
2-
import { Component, Inject, OnInit, ViewChild } from '@angular/core';
2+
import { Component, DestroyRef, Inject, OnInit, ViewChild } from '@angular/core';
33
import { FormControl, FormGroup, Validators } from '@angular/forms';
44
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
55
import { TranslocoModule } from '@ngneat/transloco';
66
import { SFProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project';
77
import { Chapter, TextInfo } from 'realtime-server/lib/esm/scriptureforge/models/text-info';
88
import { TextInfoPermission } from 'realtime-server/lib/esm/scriptureforge/models/text-info-permission';
9-
import { BehaviorSubject, map } from 'rxjs';
9+
import { BehaviorSubject, map, switchMap } from 'rxjs';
10+
import { ActivatedProjectService } from 'xforge-common/activated-project.service';
1011
import { I18nService } from 'xforge-common/i18n.service';
1112
import { OnlineStatusService } from 'xforge-common/online-status.service';
1213
import { UICommonModule } from 'xforge-common/ui-common.module';
1314
import { SFUserProjectsService } from 'xforge-common/user-projects.service';
1415
import { UserService } from 'xforge-common/user.service';
15-
import { filterNullish } from 'xforge-common/util/rxjs-util';
16+
import { filterNullish, quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util';
1617
import { XForgeCommonModule } from 'xforge-common/xforge-common.module';
1718
import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc';
1819
import { TextDoc, TextDocId } from '../../../core/models/text-doc';
@@ -23,15 +24,16 @@ import { ProjectSelectComponent } from '../../../project-select/project-select.c
2324
import { CustomValidatorState as CustomErrorState, SFValidators } from '../../../shared/sfvalidators';
2425
import { SharedModule } from '../../../shared/shared.module';
2526
import { compareProjectsForSorting } from '../../../shared/utils';
27+
import { DraftGenerationService } from '../draft-generation.service';
2628

2729
export interface DraftApplyDialogResult {
2830
projectId: string;
31+
chapters: number[];
2932
}
3033

3134
export interface DraftApplyDialogConfig {
3235
initialParatextId?: string;
3336
bookNum: number;
34-
chapters: number[];
3537
}
3638

3739
@Component({
@@ -69,21 +71,25 @@ export class DraftApplyDialogComponent implements OnInit {
6971
bookName: this.bookName
7072
})
7173
};
74+
isValid: boolean = false;
7275

7376
// the project id to add the draft to
7477
private targetProjectId?: string;
7578
private paratextIdToProjectId: Map<string, string> = new Map<string, string>();
76-
isValid: boolean = false;
79+
private chaptersWithDrafts: number[] = [];
7780

7881
constructor(
7982
@Inject(MAT_DIALOG_DATA) private data: DraftApplyDialogConfig,
8083
@Inject(MatDialogRef) private dialogRef: MatDialogRef<DraftApplyDialogComponent, DraftApplyDialogResult>,
8184
private readonly userProjectsService: SFUserProjectsService,
8285
private readonly projectService: SFProjectService,
86+
private readonly activatedProjectService: ActivatedProjectService,
87+
private readonly draftGenerationService: DraftGenerationService,
8388
private readonly textDocService: TextDocService,
8489
readonly i18n: I18nService,
8590
private readonly userService: UserService,
86-
private readonly onlineStatusService: OnlineStatusService
91+
private readonly onlineStatusService: OnlineStatusService,
92+
private readonly destroyRef: DestroyRef
8793
) {
8894
this.targetProject$.pipe(filterNullish()).subscribe(async project => {
8995
const chapters: number = await this.chaptersWithTextAsync(project);
@@ -149,6 +155,18 @@ export class DraftApplyDialogComponent implements OnInit {
149155
this._projects = projects;
150156
this.isLoading = false;
151157
});
158+
159+
this.activatedProjectService.projectId$
160+
.pipe(
161+
quietTakeUntilDestroyed(this.destroyRef),
162+
filterNullish(),
163+
switchMap(projectId => {
164+
return this.draftGenerationService.getDraftChaptersForBook(projectId, this.data.bookNum);
165+
})
166+
)
167+
.subscribe(draftChapters => {
168+
this.chaptersWithDrafts = draftChapters ?? [];
169+
});
152170
}
153171

154172
addToProject(): void {
@@ -157,7 +175,7 @@ export class DraftApplyDialogComponent implements OnInit {
157175
if (!this.isAppOnline || !this.isFormValid || this.targetProjectId == null || !this.canEditProject) {
158176
return;
159177
}
160-
this.dialogRef.close({ projectId: this.targetProjectId });
178+
this.dialogRef.close({ projectId: this.targetProjectId, chapters: this.chaptersWithDrafts });
161179
}
162180

163181
projectSelected(paratextId: string): void {
@@ -185,7 +203,7 @@ export class DraftApplyDialogComponent implements OnInit {
185203
const bookIsEmpty: boolean = targetBook?.chapters.length === 1 && targetBook?.chapters[0].lastVerse < 1;
186204
const targetBookChapters: number[] = targetBook?.chapters.map(c => c.number) ?? [];
187205
this.projectHasMissingChapters =
188-
bookIsEmpty || this.data.chapters.filter(c => !targetBookChapters.includes(c)).length > 0;
206+
bookIsEmpty || this.chaptersWithDrafts.filter(c => !targetBookChapters.includes(c)).length > 0;
189207
if (this.projectHasMissingChapters) {
190208
this.createChaptersControl.addValidators(Validators.requiredTrue);
191209
this.createChaptersControl.updateValueAndValidity();

src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation.service.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,23 @@ export class DraftGenerationService {
401401
return this.getGeneratedDraft(projectId, book, chapter).pipe(map(draft => Object.keys(draft).length > 0));
402402
}
403403

404+
/**
405+
* Gets the number of draft chapters for a specific book.
406+
* @param projectId The SF project id for the target translation.
407+
* @param bookNum The book number.
408+
* @returns An observable containing the number of draft chapters or undefined if not found.
409+
*/
410+
getDraftChaptersForBook(projectId: string, bookNum: number): Observable<number[] | undefined> {
411+
return this.httpClient
412+
.get<number[]>(`translation/engines/project:${projectId}/actions/pretranslate/${bookNum}/chapters`)
413+
.pipe(
414+
map(res => res.data),
415+
catchError(_ => {
416+
return of(undefined);
417+
})
418+
);
419+
}
420+
404421
/**
405422
* Calls the machine api to start a pre-translation build job.
406423
* This should only be called if no build is currently active.

src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-preview-books/draft-preview-books.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
@for (book of booksWithDrafts$ | async; track book.bookId) {
33
<mat-button-toggle-group
44
class="draft-book-option"
5-
[disabled]="book.chaptersWithDrafts.length === 0"
5+
[disabled]="book.existingChapters.length === 0"
66
(change)="$event.source.checked = false"
77
>
88
<mat-button-toggle class="book-name" (click)="navigate(book)">

0 commit comments

Comments
 (0)