diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.html b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.html index 15f2a029be..ea9e6aa5b8 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.html +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.html @@ -21,7 +21,7 @@
- @if (formattingOptionsSupported && !formattingOptionsSelected && isLatestBuild && draftIsAvailable) { + @if (formattingOptionsSupported && !formattingOptionsSelected && draftIsAvailable) {

{{ t("select_formatting_options") }}

diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-usfm-format/draft-usfm-format.component.html b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-usfm-format/draft-usfm-format.component.html index 4c224958b9..9cb61866a2 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-usfm-format/draft-usfm-format.component.html +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-usfm-format/draft-usfm-format.component.html @@ -70,14 +70,20 @@

{{ t("formatting_options") }}

- + @if (!canPreviewDraft) { + + {{ t("new_draft_required") }} + + } @else { + + }
{ const env = new TestEnvironment({ canDenormalizeQuotes: false }); expect(env.quoteFormatWarning).not.toBeNull(); })); + + it('shows a notice if we are configuring for a build that is not the latest', fakeAsync(async () => { + const env = new TestEnvironment({ hasDraft: false }); + verify(mockedDraftHandlingService.getDraft(anything(), anything())).never(); + expect(env.harnesses?.length).toEqual(5); + await env.harnesses![0].check(); + tick(); + expect(env.component.canPreviewDraft).toBe(false); + expect(env.cannotPreviewDraftWarning).not.toBeNull(); + env.fixture.detectChanges(); + const config: DraftUsfmConfig = { + paragraphFormat: ParagraphBreakFormat.BestGuess, + quoteFormat: QuoteFormat.Denormalized + }; + verify(mockedProjectService.onlineSetUsfmConfig(env.projectId, anything())).never(); + verify(mockedDraftHandlingService.getDraft(anything(), anything())).never(); + + // redirect to generate draft + env.saveButton.click(); + tick(); + env.fixture.detectChanges(); + verify(mockedProjectService.onlineSetUsfmConfig(env.projectId, deepEqual(config))).once(); + verify(mockedServalAdministration.onlineRetrievePreTranslationStatus(env.projectId)).never(); + verify(mockedLocation.back()).once(); + })); }); class TestEnvironment { @@ -322,7 +347,7 @@ class TestEnvironment { readonly projectId = 'project01'; onlineStatusService: TestOnlineStatusService; - constructor(args: { project?: Partial; canDenormalizeQuotes?: boolean } = {}) { + constructor(args: { project?: Partial; canDenormalizeQuotes?: boolean; hasDraft?: boolean } = {}) { const userDoc = mock(UserDoc); this.onlineStatusService = TestBed.inject(OnlineStatusService) as TestOnlineStatusService; when(mockedDraftGenerationService.getLastCompletedBuild(anything())).thenReturn( @@ -342,7 +367,7 @@ class TestEnvironment { when(mockedNoticeService.show(anything())).thenResolve(); when(mockedDialogService.confirm(anything(), anything(), anything())).thenResolve(true); when(mockedServalAdministration.onlineRetrievePreTranslationStatus(anything())).thenResolve(); - when(mockedProjectService.hasDraft(anything(), anything(), anything())).thenReturn(true); + when(mockedProjectService.hasDraft(anything(), anything(), anything())).thenReturn(args.hasDraft ?? true); this.setupProject(args.project); this.fixture = TestBed.createComponent(DraftUsfmFormatComponent); this.component = this.fixture.componentInstance; @@ -368,6 +393,10 @@ class TestEnvironment { return this.fixture.nativeElement.querySelector('.quote-format-warning'); } + get cannotPreviewDraftWarning(): HTMLElement | null { + return this.fixture.nativeElement.querySelector('.preview-draft-warning'); + } + setupProject(project?: Partial): void { const texts: TextInfo[] = [ { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-usfm-format/draft-usfm-format.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-usfm-format/draft-usfm-format.component.ts index 6091a63a34..d31152ab28 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-usfm-format/draft-usfm-format.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-usfm-format/draft-usfm-format.component.ts @@ -77,6 +77,7 @@ export class DraftUsfmFormatComponent extends DataLoadingComponent implements Af isInitializing: boolean = true; paragraphBreakFormat = ParagraphBreakFormat; quoteStyle = QuoteFormat; + canPreviewDraft: boolean = true; paragraphFormat = new FormControl(ParagraphBreakFormat.BestGuess); quoteFormat = new FormControl(QuoteFormat.Denormalized); @@ -158,6 +159,7 @@ export class DraftUsfmFormatComponent extends DataLoadingComponent implements Af const projectDoc = this.activatedProjectService.projectDoc; if (projectDoc?.data == null) return; this.setUsfmConfig(projectDoc.data.translateConfig.draftConfig.usfmConfig); + this.canPreviewDraft = this.projectService.hasDraft(projectDoc.data, undefined, true); const texts: TextInfo[] = projectDoc.data.texts; this.booksWithDrafts = texts .filter(t => this.projectService.hasDraft(projectDoc.data, t.bookNum, true)) @@ -218,8 +220,10 @@ export class DraftUsfmFormatComponent extends DataLoadingComponent implements Af } reloadText(): void { - this.loadingStarted(); - this.updateDraftConfig$.next(this.currentFormat); + if (this.canPreviewDraft) { + this.loadingStarted(); + this.updateDraftConfig$.next(this.currentFormat); + } } async saveChanges(): Promise { @@ -229,8 +233,11 @@ export class DraftUsfmFormatComponent extends DataLoadingComponent implements Af this.saving = true; await this.projectService.onlineSetUsfmConfig(this.projectId, this.currentFormat); this.lastSavedState = this.currentFormat; + // If the user could not preview the draft, we should not update it, as a blank draft will result + if (this.canPreviewDraft) { + await this.servalAdministration.onlineRetrievePreTranslationStatus(this.projectId); + } // The user is redirected to the draft generation page if the format is saved. - await this.servalAdministration.onlineRetrievePreTranslationStatus(this.projectId); this.close(); } catch (err) { console.error('Error occurred while saving draft format', err); @@ -267,7 +274,7 @@ export class DraftUsfmFormatComponent extends DataLoadingComponent implements Af quietTakeUntilDestroyed(this.destroyRef) ) .subscribe(isOnline => { - if (isOnline) this.reloadText(); + if (isOnline && this.canPreviewDraft) this.reloadText(); }); } diff --git a/src/SIL.XForge.Scripture/ClientApp/src/assets/i18n/non_checking_en.json b/src/SIL.XForge.Scripture/ClientApp/src/assets/i18n/non_checking_en.json index b32c469766..1425c04280 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/assets/i18n/non_checking_en.json +++ b/src/SIL.XForge.Scripture/ClientApp/src/assets/i18n/non_checking_en.json @@ -369,6 +369,7 @@ "paragraph_breaks_description": "Scripture Forge translates complete verses, without paragraph breaks, because this gives the best translation. Choose where to place the paragraph breaks from the source.", "paragraph_breaks_title": "Paragraph breaks", "new": "new", + "new_draft_required": "You must generate a new draft to preview the formatting options. Changing these options will not update any existing drafts you may have.", "no_quote_convention_detected": "No quote convention could be detected for your project. Straight quotes will be used in the draft regardless of which option you choose.", "option_best_guess": "Best guess", "option_best_guess_description": "Paragraph breaks in the source will be placed at the best guess of where they should be in the draft. Recommended for most projects.",