Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { createTestProjectProfile } from 'realtime-server/lib/esm/scriptureforge
import { TextInfoPermission } from 'realtime-server/lib/esm/scriptureforge/models/text-info-permission';
import { of } from 'rxjs';
import { anything, mock, verify, when } from 'ts-mockito';
import { ActivatedProjectService } from 'xforge-common/activated-project.service';
import { OnlineStatusService } from 'xforge-common/online-status.service';
import { TestOnlineStatusModule } from 'xforge-common/test-online-status.module';
import { TestOnlineStatusService } from 'xforge-common/test-online-status.service';
Expand All @@ -22,11 +23,14 @@ import { TextDoc } from '../../../core/models/text-doc';
import { SFProjectService } from '../../../core/sf-project.service';
import { TextDocService } from '../../../core/text-doc.service';
import { CustomValidatorState } from '../../../shared/sfvalidators';
import { DraftGenerationService } from '../draft-generation.service';
import { DraftApplyDialogComponent } from './draft-apply-dialog.component';

const mockedActivatedProjectService = mock(ActivatedProjectService);
const mockedUserProjectsService = mock(SFUserProjectsService);
const mockedProjectService = mock(SFProjectService);
const mockedUserService = mock(UserService);
const mockedDraftGenerationService = mock(DraftGenerationService);
const mockedDialogRef = mock(MatDialogRef);
const mockedTextDocService = mock(TextDocService);

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

let env: TestEnvironment;

describe('DraftApplyDialogComponent', () => {
fdescribe('DraftApplyDialogComponent', () => {
configureTestingModule(() => ({
imports: [
TestTranslocoModule,
Expand All @@ -48,9 +52,11 @@ describe('DraftApplyDialogComponent', () => {
TestOnlineStatusModule.forRoot()
],
providers: [
{ provide: ActivatedProjectService, useMock: mockedActivatedProjectService },
{ provide: SFUserProjectsService, useMock: mockedUserProjectsService },
{ provide: SFProjectService, useMock: mockedProjectService },
{ provide: UserService, useMock: mockedUserService },
{ provide: DraftGenerationService, useMock: mockedDraftGenerationService },
{ provide: TextDocService, useMock: mockedTextDocService },
{ provide: OnlineStatusService, useClass: TestOnlineStatusService },
{ provide: MatDialogRef, useMock: mockedDialogRef },
Expand Down Expand Up @@ -343,7 +349,9 @@ class TestEnvironment {
const mockedTextDoc = {
getNonEmptyVerses: (): string[] => ['verse_1_1', 'verse_1_2', 'verse_1_3']
} as TextDoc;
when(mockedActivatedProjectService.projectId$).thenReturn(of('project01'));
when(mockedProjectService.getText(anything())).thenResolve(mockedTextDoc);
when(mockedTextDocService.userHasGeneralEditRight(anything())).thenReturn(true);
when(mockedDraftGenerationService.getDraftChaptersForBook(anything(), anything())).thenReturn(of([1, 2]));
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { CommonModule } from '@angular/common';
import { Component, Inject, OnInit, ViewChild } from '@angular/core';
import { Component, DestroyRef, Inject, OnInit, ViewChild } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { TranslocoModule } from '@ngneat/transloco';
import { SFProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project';
import { Chapter, TextInfo } from 'realtime-server/lib/esm/scriptureforge/models/text-info';
import { TextInfoPermission } from 'realtime-server/lib/esm/scriptureforge/models/text-info-permission';
import { BehaviorSubject, map } from 'rxjs';
import { BehaviorSubject, map, switchMap } from 'rxjs';
import { ActivatedProjectService } from 'xforge-common/activated-project.service';
import { I18nService } from 'xforge-common/i18n.service';
import { OnlineStatusService } from 'xforge-common/online-status.service';
import { UICommonModule } from 'xforge-common/ui-common.module';
import { SFUserProjectsService } from 'xforge-common/user-projects.service';
import { UserService } from 'xforge-common/user.service';
import { filterNullish } from 'xforge-common/util/rxjs-util';
import { filterNullish, quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util';
import { XForgeCommonModule } from 'xforge-common/xforge-common.module';
import { SFProjectProfileDoc } from '../../../core/models/sf-project-profile-doc';
import { TextDoc, TextDocId } from '../../../core/models/text-doc';
Expand All @@ -23,15 +24,16 @@ import { ProjectSelectComponent } from '../../../project-select/project-select.c
import { CustomValidatorState as CustomErrorState, SFValidators } from '../../../shared/sfvalidators';
import { SharedModule } from '../../../shared/shared.module';
import { compareProjectsForSorting } from '../../../shared/utils';
import { DraftGenerationService } from '../draft-generation.service';

export interface DraftApplyDialogResult {
projectId: string;
chapters: number[];
}

export interface DraftApplyDialogConfig {
initialParatextId?: string;
bookNum: number;
chapters: number[];
}

@Component({
Expand Down Expand Up @@ -69,21 +71,25 @@ export class DraftApplyDialogComponent implements OnInit {
bookName: this.bookName
})
};
isValid: boolean = false;

// the project id to add the draft to
private targetProjectId?: string;
private paratextIdToProjectId: Map<string, string> = new Map<string, string>();
isValid: boolean = false;
private chaptersWithDrafts: number[] = [];

constructor(
@Inject(MAT_DIALOG_DATA) private data: DraftApplyDialogConfig,
@Inject(MatDialogRef) private dialogRef: MatDialogRef<DraftApplyDialogComponent, DraftApplyDialogResult>,
private readonly userProjectsService: SFUserProjectsService,
private readonly projectService: SFProjectService,
private readonly activatedProjectService: ActivatedProjectService,
private readonly draftGenerationService: DraftGenerationService,
private readonly textDocService: TextDocService,
readonly i18n: I18nService,
private readonly userService: UserService,
private readonly onlineStatusService: OnlineStatusService
private readonly onlineStatusService: OnlineStatusService,
private readonly destroyRef: DestroyRef
) {
this.targetProject$.pipe(filterNullish()).subscribe(async project => {
const chapters: number = await this.chaptersWithTextAsync(project);
Expand Down Expand Up @@ -149,6 +155,18 @@ export class DraftApplyDialogComponent implements OnInit {
this._projects = projects;
this.isLoading = false;
});

this.activatedProjectService.projectId$
.pipe(
quietTakeUntilDestroyed(this.destroyRef),
filterNullish(),
switchMap(projectId => {
return this.draftGenerationService.getDraftChaptersForBook(projectId, this.data.bookNum);
})
)
.subscribe(draftChapters => {
this.chaptersWithDrafts = draftChapters ?? [];
});
}

addToProject(): void {
Expand All @@ -157,7 +175,7 @@ export class DraftApplyDialogComponent implements OnInit {
if (!this.isAppOnline || !this.isFormValid || this.targetProjectId == null || !this.canEditProject) {
return;
}
this.dialogRef.close({ projectId: this.targetProjectId });
this.dialogRef.close({ projectId: this.targetProjectId, chapters: this.chaptersWithDrafts });
}

projectSelected(paratextId: string): void {
Expand Down Expand Up @@ -185,7 +203,7 @@ export class DraftApplyDialogComponent implements OnInit {
const bookIsEmpty: boolean = targetBook?.chapters.length === 1 && targetBook?.chapters[0].lastVerse < 1;
const targetBookChapters: number[] = targetBook?.chapters.map(c => c.number) ?? [];
this.projectHasMissingChapters =
bookIsEmpty || this.data.chapters.filter(c => !targetBookChapters.includes(c)).length > 0;
bookIsEmpty || this.chaptersWithDrafts.filter(c => !targetBookChapters.includes(c)).length > 0;
if (this.projectHasMissingChapters) {
this.createChaptersControl.addValidators(Validators.requiredTrue);
this.createChaptersControl.updateValueAndValidity();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,23 @@ export class DraftGenerationService {
return this.getGeneratedDraft(projectId, book, chapter).pipe(map(draft => Object.keys(draft).length > 0));
}

/**
* Gets the number of draft chapters for a specific book.
* @param projectId The SF project id for the target translation.
* @param bookNum The book number.
* @returns An observable containing the number of draft chapters or undefined if not found.
*/
getDraftChaptersForBook(projectId: string, bookNum: number): Observable<number[] | undefined> {
return this.httpClient
.get<number[]>(`translation/engines/project:${projectId}/actions/pretranslate/${bookNum}/chapters`)
.pipe(
map(res => res.data),
catchError(_ => {
return of(undefined);
})
);
}

/**
* Calls the machine api to start a pre-translation build job.
* This should only be called if no build is currently active.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
@for (book of booksWithDrafts$ | async; track book.bookId) {
<mat-button-toggle-group
class="draft-book-option"
[disabled]="book.chaptersWithDrafts.length === 0"
[disabled]="book.existingChapters.length === 0"
(change)="$event.source.checked = false"
>
<mat-button-toggle class="book-name" (click)="navigate(book)">
Expand Down
Loading
Loading