From 82ad1d388c6f9aab2d50255a30320303d6e65448 Mon Sep 17 00:00:00 2001 From: Peter Chapman Date: Tue, 15 Sep 2026 10:28:28 +1200 Subject: [PATCH 1/3] SF-3917 Add a link to Low Draft Quality banner --- .../draft-history-entry.component.html | 24 ++++++++++---- .../draft-history-entry.component.ts | 2 ++ .../draft-import-wizard.component.html | 32 ++++++++++++++++--- .../draft-import-wizard.component.ts | 2 ++ .../editor-draft/editor-draft.component.html | 8 ++++- .../editor-draft.component.spec.ts | 3 ++ .../editor-draft/editor-draft.component.ts | 4 +++ .../src/assets/i18n/non_checking_en.json | 10 +++--- .../src/xforge-common/external-url-class.ts | 4 +++ 9 files changed, 73 insertions(+), 16 deletions(-) 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 144fcf10734..f3cdfb9edaa 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 @@ -40,13 +40,25 @@ @if (draftIsAvailable) { @if (hasLowConfidence(entry)) { @if (booksWithLowConfidence(entry) > 1) { - {{ - t("low_confidence_books", { number: booksWithLowConfidence(entry) }) - }} + + } @else { - {{ - t("low_confidence_book", { book: lowConfidenceBookName(entry) }) - }} + } }

{{ t("click_book_to_preview_draft") }}

diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.ts index a62949418b3..cdf367186cd 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.ts @@ -26,6 +26,7 @@ import { TranslocoModule } from '@ngneat/transloco'; import { TranslocoMarkupModule } from 'ngx-transloco-markup'; import { Subject, takeUntil } from 'rxjs'; import { ActivatedProjectService } from 'xforge-common/activated-project.service'; +import { ExternalUrlService } from 'xforge-common/external-url.service'; import { I18nService } from 'xforge-common/i18n.service'; import { UserService } from 'xforge-common/user.service'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; @@ -333,6 +334,7 @@ export class DraftHistoryEntryComponent { constructor( readonly i18n: I18nService, private readonly projectService: SFProjectService, + protected readonly urlService: ExternalUrlService, private readonly userService: UserService, private readonly trainingDataService: TrainingDataService, private readonly activatedProjectService: ActivatedProjectService, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-import-wizard/draft-import-wizard.component.html b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-import-wizard/draft-import-wizard.component.html index 846c18f3278..fb299a0fe40 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-import-wizard/draft-import-wizard.component.html +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-import-wizard/draft-import-wizard.component.html @@ -64,7 +64,13 @@

{{ t("select_project") }}

} @if (draftHasLowConfidence && !(needsConnection || showBookSelection)) { - {{ t("low_confidence_book", { book: bookNameWithLowConfidence }) }} + } @@ -171,7 +177,13 @@

{{ t("connected_to_project") }}

} @if (draftHasLowConfidence && !showBookSelection) { - {{ t("low_confidence_book", { book: bookNameWithLowConfidence }) }} + }
@@ -211,11 +223,23 @@

{{ t("confirm_books_to_import") }}

@if (selectedBooksWithLowConfidence === 1) { - {{ t("low_confidence_book", { book: bookNameWithLowConfidence }) }} + } @else if (selectedBooksWithLowConfidence > 1) { - {{ t("low_confidence_books", { number: selectedBooksWithLowConfidence }) }} + } diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-import-wizard/draft-import-wizard.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-import-wizard/draft-import-wizard.component.ts index cb14cebecc5..e26f4a3f0fc 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-import-wizard/draft-import-wizard.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-import-wizard/draft-import-wizard.component.ts @@ -23,6 +23,7 @@ import { BehaviorSubject, filter } from 'rxjs'; import { ActivatedProjectService } from 'xforge-common/activated-project.service'; import { AuthService } from 'xforge-common/auth.service'; import { CommandError, CommandErrorCode } from 'xforge-common/command.service'; +import { ExternalUrlService } from 'xforge-common/external-url.service'; import { I18nService } from 'xforge-common/i18n.service'; import { LocationService } from 'xforge-common/location.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; @@ -318,6 +319,7 @@ export class DraftImportWizardComponent implements OnInit { private readonly onlineStatusService: OnlineStatusService, private readonly activatedProjectService: ActivatedProjectService, private readonly authService: AuthService, + protected readonly urlService: ExternalUrlService, private readonly userService: UserService ) { this.draftedScriptureRange = VerboseScriptureRange.fromCombinedRanges( diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.html b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.html index f019c3a4c7d..3a13361bb44 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.html +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.html @@ -75,7 +75,13 @@ } @if (hasLowConfidence) { - {{ "editor_draft_tab.low_confidence_book" | transloco: { book: this.getLocalizedBook() } }} + } } @else { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.spec.ts index 02a39a442db..3c8af96fedf 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.spec.ts @@ -17,6 +17,7 @@ import { AuthService } from 'xforge-common/auth.service'; import { CommandError, CommandErrorCode } from 'xforge-common/command.service'; import { DialogService } from 'xforge-common/dialog.service'; import { ErrorReportingService } from 'xforge-common/error-reporting.service'; +import { ExternalUrlService } from 'xforge-common/external-url.service'; import { I18nService } from 'xforge-common/i18n.service'; import { NoticeService } from 'xforge-common/notice.service'; import { OnlineStatusService } from 'xforge-common/online-status.service'; @@ -53,6 +54,7 @@ const mockNoticeService = mock(NoticeService); const mockProjectNotificationService = mock(ProjectNotificationService); const mockSFProjectService = mock(SFProjectService); const mockTextDocService = mock(TextDocService); +const mockUrlService = mock(ExternalUrlService); describe('EditorDraftComponent', () => { let fixture: ComponentFixture; @@ -82,6 +84,7 @@ describe('EditorDraftComponent', () => { { provide: DraftHandlingService, useMock: mockDraftHandlingService }, { provide: DraftNotificationService, useMock: mockDraftNotificationService }, { provide: ErrorReportingService, useMock: mockErrorReportingService }, + { provide: ExternalUrlService, useMock: mockUrlService }, { provide: I18nService, useMock: mockI18nService }, { provide: OnlineStatusService, useClass: TestOnlineStatusService }, { provide: ProjectNotificationService, useMock: mockProjectNotificationService }, diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.ts index d0ce3eab8cc..cf99412cd30 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.ts @@ -10,6 +10,7 @@ import { MatTooltip } from '@angular/material/tooltip'; import { Router } from '@angular/router'; import { TranslocoModule } from '@ngneat/transloco'; import { Canon } from '@sillsdev/scripture'; +import { TranslocoMarkupModule } from 'ngx-transloco-markup'; import { Delta } from 'quill'; import { SFProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project'; import { DeltaOperation } from 'rich-text'; @@ -36,6 +37,7 @@ import { ActivatedProjectService } from 'xforge-common/activated-project.service import { isNetworkError } from 'xforge-common/command.service'; import { DialogService } from 'xforge-common/dialog.service'; import { ErrorReportingService } from 'xforge-common/error-reporting.service'; +import { ExternalUrlService } from 'xforge-common/external-url.service'; import { I18nService } from 'xforge-common/i18n.service'; import { Locale } from 'xforge-common/models/i18n-locale'; import { NoticeService } from 'xforge-common/notice.service'; @@ -69,6 +71,7 @@ import { HistoryRevisionFormatPipe } from '../editor-history/history-chooser/his styleUrls: ['./editor-draft.component.scss'], imports: [ TranslocoModule, + TranslocoMarkupModule, MatProgressBar, NoticeComponent, DraftPreviewBooksComponent, @@ -151,6 +154,7 @@ export class EditorDraftComponent implements AfterViewInit, OnChanges { private readonly noticeService: NoticeService, private readonly router: Router, private readonly textDocService: TextDocService, + protected readonly urlService: ExternalUrlService, projectNotificationService: ProjectNotificationService ) { this.activatedProjectService.projectId$ 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 48aeb21b3d4..58f4e5f6864 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 @@ -389,8 +389,8 @@ "formatting_options": "Formatting options", "formatting": "Formatting", "hide_model_training_configuration": "Hide model training configuration", - "low_confidence_book": "Draft quality for {{ book }} may be lower than normal.", - "low_confidence_books": "Draft quality for {{ number }} books may be lower than normal.", + "low_confidence_book": "Draft quality for {{ book }} may be lower than normal. [link:learnMoreLink]Learn more[/link]", + "low_confidence_books": "Draft quality for {{ number }} books may be lower than normal. [link:learnMoreLink]Learn more[/link]", "one_book": "1 book", "requested_at": "Requested {{ requestedAtTime }}.", "requested_by": "Requested by {{ requestedByUserName }} at {{ requestedAtTime }}.", @@ -442,8 +442,8 @@ "import_some_chapters_failed": "Imported {{ successful }} chapter(s) successfully. Failed to import {{ failed }} chapter(s). See details above.", "importing_draft": "Importing draft", "importing": "Importing", - "low_confidence_book": "Draft quality for {{ book }} may be lower than normal.", - "low_confidence_books": "Draft quality for {{ number }} books may be lower than normal.", + "low_confidence_book": "Draft quality for {{ book }} may be lower than normal. [link:learnMoreLink]Learn more[/link]", + "low_confidence_books": "Draft quality for {{ number }} books may be lower than normal. [link:learnMoreLink]Learn more[/link]", "next": "Next", "no_books_ready_for_import": "No draft chapters are ready for import. Generate a draft and try again.", "overwrite_book_description": "One or more chapters have existing content that will be overwritten in {{ bookName }} in [b]{{ projectNameLabel }}[/b]. Chapters with existing content are listed below. Click each chapter to view the content.", @@ -573,7 +573,7 @@ "error_applying_draft": "Failed to add the draft to the project. Try again later.", "format_draft": "Formatting options", "format_draft_tooltip": "Customize formatting options for the draft", - "low_confidence_book": "Draft quality for {{ book }} may be lower than normal.", + "low_confidence_book": "Draft quality for {{ book }} may be lower than normal. [link:learnMoreLink]Learn more[/link]", "no_draft_notice": "{{ bookChapterName }} has no draft.", "offline_notice": "Generated drafts are not available offline.", "overwrite": "Adding the draft will overwrite the current chapter. Are you sure you want to continue?", diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/external-url-class.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/external-url-class.ts index 90a9353b958..4df4514ec9c 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/external-url-class.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/external-url-class.ts @@ -27,6 +27,10 @@ export class ExternalUrls { return this.helps + '/understanding-drafts'; } + get understandingDraftQuality(): string { + return this.helps + '/understanding-draft-quality'; + } + get configuringSources(): string { return this.helps + '/preparing-for-ai-drafting'; } From f2255e2bc0e870edf5e87ec9764c9a9d98e48388 Mon Sep 17 00:00:00 2001 From: Peter Chapman Date: Wed, 16 Sep 2026 11:06:47 +1200 Subject: [PATCH 2/3] SF-3917 Refactor into a component --- .../serval-builds.component.html | 10 +--- .../display-confidence.component.html | 36 ++++++++++--- .../display-confidence.component.spec.ts | 51 +++++++++++++++--- .../display-confidence.component.ts | 13 +++-- .../display-confidence.stories.ts | 28 ++++++++-- .../draft-history-entry.component.html | 33 +++--------- .../draft-history-entry.component.spec.ts | 8 +-- .../draft-history-entry.component.ts | 16 +++--- .../draft-import-wizard.component.html | 54 ++++++------------- .../draft-import-wizard.component.ts | 4 +- .../draft-preview-books.component.html | 2 +- .../editor-draft/editor-draft.component.html | 15 +++--- .../editor-draft/editor-draft.component.ts | 4 +- .../src/assets/i18n/non_checking_en.json | 11 ++-- 14 files changed, 153 insertions(+), 132 deletions(-) diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-builds.component.html b/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-builds.component.html index b58f3a7976a..e37a37aa715 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-builds.component.html +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-builds.component.html @@ -105,10 +105,7 @@ warning }
- + @@ -594,10 +591,7 @@ {{ "canon.book_names." + getBookId(bookConfidence) | transloco }} - + } diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.component.html b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.component.html index 044d7be01fe..fe6e680c009 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.component.html +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.component.html @@ -1,12 +1,32 @@ - @if (lowConfidence) { - @if (showText) { -
- warning - {{ t("low_confidence") }} -
- } @else { - warning + @if (showNotice) { + @if (booksWithLowConfidence === 1) { + + + + } @else if (booksWithLowConfidence > 1) { + + + } + } @else if (showIconAndText) { +
+ warning + {{ t("low_confidence") }} +
+ } @else if (showIcon) { + warning }
diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.component.spec.ts index 1ea84c70aba..fc9a1cb1c99 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.component.spec.ts @@ -10,21 +10,45 @@ describe('DisplayConfidenceComponent', () => { })); it('low confidence with icon and text', () => { - const env = new TestEnvironment(true, true); + const env = new TestEnvironment(false, true, false); expect(env.icon).not.toBeNull(); expect(env.text).not.toBeNull(); + expect(env.notice).toBeNull(); }); it('low confidence icon only', () => { - const env = new TestEnvironment(true, false); + const env = new TestEnvironment(true, false, false); expect(env.icon).not.toBeNull(); expect(env.text).toBeNull(); + expect(env.notice).toBeNull(); }); it('not low confidence', () => { - const env = new TestEnvironment(false, true); + const env = new TestEnvironment(false, false, false); expect(env.icon).toBeNull(); expect(env.text).toBeNull(); + expect(env.notice).toBeNull(); + }); + + it('low confidence notice one book with name', () => { + const env = new TestEnvironment(false, false, true, 1, 'Genesis'); + expect(env.icon).toBeNull(); + expect(env.text).toBeNull(); + expect(env.notice).not.toBeNull(); + }); + + it('low confidence notice one book', () => { + const env = new TestEnvironment(false, false, true, 1); + expect(env.icon).toBeNull(); + expect(env.text).toBeNull(); + expect(env.notice).not.toBeNull(); + }); + + it('low confidence notice multiple books', () => { + const env = new TestEnvironment(false, false, true, 2); + expect(env.icon).toBeNull(); + expect(env.text).toBeNull(); + expect(env.notice).not.toBeNull(); }); /** Provides helpers for constructing test data for DisplayConfidenceComponent tests. */ @@ -32,11 +56,20 @@ describe('DisplayConfidenceComponent', () => { readonly component: DisplayConfidenceComponent; readonly fixture: ComponentFixture; - constructor(lowConfidence: boolean, showText: boolean) { + constructor( + showIcon: boolean, + showIconAndText: boolean, + showNotice: boolean, + booksWithLowConfidence: number = 0, + bookNameWithLowConfidence: string | undefined = undefined + ) { this.fixture = TestBed.createComponent(DisplayConfidenceComponent); this.component = this.fixture.componentInstance; - this.component.lowConfidence = lowConfidence; - this.component.showText = showText; + this.component.showIcon = showIcon; + this.component.showIconAndText = showIconAndText; + this.component.showNotice = showNotice; + this.component.booksWithLowConfidence = booksWithLowConfidence; + this.component.bookNameWithLowConfidence = bookNameWithLowConfidence; this.fixture.detectChanges(); } @@ -44,8 +77,12 @@ describe('DisplayConfidenceComponent', () => { return this.fixture.debugElement.query(By.css('mat-icon')); } + get notice(): DebugElement { + return this.fixture.debugElement.query(By.css('app-notice')); + } + get text(): DebugElement { - return this.fixture.debugElement.query(By.css('span')); + return this.fixture.debugElement.query(By.css('.red span')); } } }); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.component.ts index bccd2572547..678f1634960 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.component.ts @@ -2,17 +2,24 @@ import { Component, Input } from '@angular/core'; import { MatIcon } from '@angular/material/icon'; import { MatTooltip } from '@angular/material/tooltip'; import { TranslocoModule } from '@ngneat/transloco'; +import { TranslocoMarkupModule } from 'ngx-transloco-markup'; +import { ExternalUrlService } from 'xforge-common/external-url.service'; +import { NoticeComponent } from '../../../shared/notice/notice.component'; @Component({ selector: 'app-display-confidence', templateUrl: './display-confidence.component.html', styleUrl: './display-confidence.component.scss', - imports: [MatIcon, MatTooltip, TranslocoModule] + imports: [MatIcon, MatTooltip, NoticeComponent, TranslocoModule, TranslocoMarkupModule] }) /** * Displays the confidence value in an human-friendly format. */ export class DisplayConfidenceComponent { - @Input() showText: boolean | undefined; - @Input() lowConfidence: boolean | undefined; + constructor(protected readonly urlService: ExternalUrlService) {} + @Input() bookNameWithLowConfidence: string | undefined; + @Input() booksWithLowConfidence: number = 0; + @Input() showIcon: boolean | undefined; + @Input() showIconAndText: boolean | undefined; + @Input() showNotice: boolean | undefined; } diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.stories.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.stories.ts index 0830a6432ad..175d659e211 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.stories.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.stories.ts @@ -1,22 +1,40 @@ -import { Meta, StoryObj } from '@storybook/angular'; +import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; +import { defaultTranslocoMarkupTranspilers } from 'ngx-transloco-markup'; import { DisplayConfidenceComponent } from './display-confidence.component'; const meta: Meta = { title: 'Draft/Display Confidence Label', - component: DisplayConfidenceComponent + component: DisplayConfidenceComponent, + decorators: [ + moduleMetadata({ + providers: [defaultTranslocoMarkupTranspilers()] + }) + ] }; export default meta; type Story = StoryObj; export const NotLowConfidence: Story = { - args: { lowConfidence: false, showText: true } + args: { showIcon: false, showIconAndText: false } }; export const LowConfidenceWithIconAndText: Story = { - args: { lowConfidence: true, showText: true } + args: { showIcon: false, showIconAndText: true } }; export const LowConfidenceIconOnly: Story = { - args: { lowConfidence: true, showText: false } + args: { showIcon: true, showIconAndText: false } +}; + +export const NoticeOneBookWithName: Story = { + args: { showNotice: true, bookNameWithLowConfidence: 'Genesis', booksWithLowConfidence: 1 } +}; + +export const NoticeOneBook: Story = { + args: { showNotice: true, booksWithLowConfidence: 1 } +}; + +export const NoticeMultipleBooks: Story = { + args: { showNotice: true, booksWithLowConfidence: 2 } }; 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 f3cdfb9edaa..b0ab303c1ef 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 @@ -15,10 +15,7 @@ - + {{ getStatus(entry.state).icons }} {{ t(getStatus(entry.state).text) }} @@ -38,29 +35,11 @@ } @else { @if (draftIsAvailable) { - @if (hasLowConfidence(entry)) { - @if (booksWithLowConfidence(entry) > 1) { - - - } @else { - - } - } +

{{ t("click_book_to_preview_draft") }}

diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.spec.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.spec.ts index b154e3e8bd8..7b667201705 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.spec.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.spec.ts @@ -534,8 +534,8 @@ describe('DraftHistoryEntryComponent', () => { tick(); fixture.detectChanges(); - expect(fixture.nativeElement.querySelector('[data-test-id="low-confidence-book"]')).not.toBeNull(); - expect(fixture.nativeElement.querySelector('[data-test-id="low-confidence-books"]')).toBeNull(); + expect(component.booksWithLowConfidence(entry)).toBe(1); + expect(fixture.nativeElement.querySelector('app-display-confidence')).not.toBeNull(); })); it('should show the multiple book low confidence warning if more than one book has low confidence', fakeAsync(() => { @@ -565,8 +565,8 @@ describe('DraftHistoryEntryComponent', () => { tick(); fixture.detectChanges(); - expect(fixture.nativeElement.querySelector('[data-test-id="low-confidence-book"]')).toBeNull(); - expect(fixture.nativeElement.querySelector('[data-test-id="low-confidence-books"]')).not.toBeNull(); + expect(component.booksWithLowConfidence(entry)).toBe(2); + expect(fixture.nativeElement.querySelector('app-display-confidence')).not.toBeNull(); })); }); diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.ts index cdf367186cd..5833cd8c6b8 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.ts @@ -26,7 +26,6 @@ import { TranslocoModule } from '@ngneat/transloco'; import { TranslocoMarkupModule } from 'ngx-transloco-markup'; import { Subject, takeUntil } from 'rxjs'; import { ActivatedProjectService } from 'xforge-common/activated-project.service'; -import { ExternalUrlService } from 'xforge-common/external-url.service'; import { I18nService } from 'xforge-common/i18n.service'; import { UserService } from 'xforge-common/user.service'; import { quietTakeUntilDestroyed } from 'xforge-common/util/rxjs-util'; @@ -35,7 +34,6 @@ import { PermissionsService } from '../../../../core/permissions.service'; import { SFProjectService } from '../../../../core/sf-project.service'; import { BuildDto, ServalDiagnosticCode } from '../../../../machine-api/build-dto'; import { BuildStates } from '../../../../machine-api/build-states'; -import { NoticeComponent } from '../../../../shared/notice/notice.component'; import { trainingSourceRangesWithTargetDetail, VerboseScriptureRange } from '../../../../shared/scripture-range'; import { formatScriptureRangeWithChapters } from '../../../../shared/scripture-range-display'; import { RIGHT_TO_LEFT_MARK } from '../../../../shared/verse-utils'; @@ -98,7 +96,6 @@ interface SourceInfo { MatHeaderRowDef, MatRow, MatRowDef, - NoticeComponent, RouterLink, TranslocoModule, TranslocoMarkupModule @@ -334,7 +331,6 @@ export class DraftHistoryEntryComponent { constructor( readonly i18n: I18nService, private readonly projectService: SFProjectService, - protected readonly urlService: ExternalUrlService, private readonly userService: UserService, private readonly trainingDataService: TrainingDataService, private readonly activatedProjectService: ActivatedProjectService, @@ -380,22 +376,22 @@ export class DraftHistoryEntryComponent { }); } - protected hasLowConfidence(build: BuildDto): boolean { - return hasLowConfidence(build); + booksWithLowConfidence(build: BuildDto): number { + return build?.executionData?.diagnostics?.filter(d => d.code === ServalDiagnosticCode.LowConfidence).length ?? 0; } - protected booksWithLowConfidence(build: BuildDto): number { - return build?.executionData?.diagnostics?.filter(d => d.code === ServalDiagnosticCode.LowConfidence).length ?? 0; + protected hasLowConfidence(build: BuildDto): boolean { + return hasLowConfidence(build); } - protected lowConfidenceBookName(build: BuildDto): string { + protected lowConfidenceBookName(build: BuildDto): string | undefined { const bookId: string | undefined = build?.executionData?.diagnostics?.find( d => d.code === ServalDiagnosticCode.LowConfidence )?.data?.bookId; if (bookId != null) { return this.i18n.localizeBook(bookId); } else { - return this.i18n.translateStatic('draft_history_entry.one_book'); + return undefined; } } diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-import-wizard/draft-import-wizard.component.html b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-import-wizard/draft-import-wizard.component.html index fb299a0fe40..989f70303b0 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-import-wizard/draft-import-wizard.component.html +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-import-wizard/draft-import-wizard.component.html @@ -63,15 +63,11 @@

{{ t("select_project") }}

}} } @if (draftHasLowConfidence && !(needsConnection || showBookSelection)) { - - - + } @@ -176,15 +172,11 @@

{{ t("connected_to_project") }}

} } @if (draftHasLowConfidence && !showBookSelection) { - - - + }
- @if (selectedBooksWithLowConfidence === 1) { - - - - } @else if (selectedBooksWithLowConfidence > 1) { - - - - } +
} @empty { {{ t("no_books_have_drafts") }} diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.html b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.html index 3a13361bb44..4111ad0205a 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.html +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.html @@ -73,16 +73,13 @@ } + @if (hasLowConfidence) { - - - + } } @else { diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.ts b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.ts index cf99412cd30..1ce9933cdea 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.ts @@ -37,7 +37,6 @@ import { ActivatedProjectService } from 'xforge-common/activated-project.service import { isNetworkError } from 'xforge-common/command.service'; import { DialogService } from 'xforge-common/dialog.service'; import { ErrorReportingService } from 'xforge-common/error-reporting.service'; -import { ExternalUrlService } from 'xforge-common/external-url.service'; import { I18nService } from 'xforge-common/i18n.service'; import { Locale } from 'xforge-common/models/i18n-locale'; import { NoticeService } from 'xforge-common/notice.service'; @@ -53,6 +52,7 @@ import { BuildDto } from '../../../machine-api/build-dto'; import { BuildStates } from '../../../machine-api/build-states'; import { NoticeComponent } from '../../../shared/notice/notice.component'; import { TextComponent } from '../../../shared/text/text.component'; +import { DisplayConfidenceComponent } from '../../draft-generation/build-confidences/display-confidence.component'; import { DraftGenerationService } from '../../draft-generation/draft-generation.service'; import { DraftHandlingService } from '../../draft-generation/draft-handling.service'; import { @@ -74,6 +74,7 @@ import { HistoryRevisionFormatPipe } from '../editor-history/history-chooser/his TranslocoMarkupModule, MatProgressBar, NoticeComponent, + DisplayConfidenceComponent, DraftPreviewBooksComponent, MatFormField, MatSelect, @@ -154,7 +155,6 @@ export class EditorDraftComponent implements AfterViewInit, OnChanges { private readonly noticeService: NoticeService, private readonly router: Router, private readonly textDocService: TextDocService, - protected readonly urlService: ExternalUrlService, projectNotificationService: ProjectNotificationService ) { this.activatedProjectService.projectId$ 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 58f4e5f6864..6764d9af806 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 @@ -320,7 +320,10 @@ } }, "draft_confidence": { - "low_confidence": "Low confidence" + "low_confidence": "Low confidence", + "low_confidence_book": "Draft quality for {{ book }} may be lower than normal. [link:learnMoreLink]Learn more[/link]", + "low_confidence_books": "Draft quality for {{ number }} books may be lower than normal. [link:learnMoreLink]Learn more[/link]", + "one_book": "1 book" }, "draft_generation_steps": { "back": "Back", @@ -389,9 +392,6 @@ "formatting_options": "Formatting options", "formatting": "Formatting", "hide_model_training_configuration": "Hide model training configuration", - "low_confidence_book": "Draft quality for {{ book }} may be lower than normal. [link:learnMoreLink]Learn more[/link]", - "low_confidence_books": "Draft quality for {{ number }} books may be lower than normal. [link:learnMoreLink]Learn more[/link]", - "one_book": "1 book", "requested_at": "Requested {{ requestedAtTime }}.", "requested_by": "Requested by {{ requestedByUserName }} at {{ requestedAtTime }}.", "select_formatting_options": "The draft has been created. Choose formatting options to continue.", @@ -442,8 +442,6 @@ "import_some_chapters_failed": "Imported {{ successful }} chapter(s) successfully. Failed to import {{ failed }} chapter(s). See details above.", "importing_draft": "Importing draft", "importing": "Importing", - "low_confidence_book": "Draft quality for {{ book }} may be lower than normal. [link:learnMoreLink]Learn more[/link]", - "low_confidence_books": "Draft quality for {{ number }} books may be lower than normal. [link:learnMoreLink]Learn more[/link]", "next": "Next", "no_books_ready_for_import": "No draft chapters are ready for import. Generate a draft and try again.", "overwrite_book_description": "One or more chapters have existing content that will be overwritten in {{ bookName }} in [b]{{ projectNameLabel }}[/b]. Chapters with existing content are listed below. Click each chapter to view the content.", @@ -573,7 +571,6 @@ "error_applying_draft": "Failed to add the draft to the project. Try again later.", "format_draft": "Formatting options", "format_draft_tooltip": "Customize formatting options for the draft", - "low_confidence_book": "Draft quality for {{ book }} may be lower than normal. [link:learnMoreLink]Learn more[/link]", "no_draft_notice": "{{ bookChapterName }} has no draft.", "offline_notice": "Generated drafts are not available offline.", "overwrite": "Adding the draft will overwrite the current chapter. Are you sure you want to continue?", From f6d1d75a8208ca34442746819e1ce388a789e40e Mon Sep 17 00:00:00 2001 From: Raymond Luong Date: Thu, 24 Sep 2026 12:02:25 -0600 Subject: [PATCH 3/3] Update draft quality link --- .../build-confidences/display-confidence.component.html | 4 ++-- .../ClientApp/src/xforge-common/external-url-class.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.component.html b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.component.html index fe6e680c009..293a5b54eea 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.component.html +++ b/src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/build-confidences/display-confidence.component.html @@ -6,7 +6,7 @@ key="draft_confidence.low_confidence_book" [params]="{ book: bookNameWithLowConfidence ?? t('one_book'), - learnMoreLink: urlService.understandingDraftQuality + learnMoreLink: urlService.improvingDraftQuality }" > @@ -16,7 +16,7 @@ key="draft_confidence.low_confidence_books" [params]="{ number: booksWithLowConfidence, - learnMoreLink: urlService.understandingDraftQuality + learnMoreLink: urlService.improvingDraftQuality }" > diff --git a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/external-url-class.ts b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/external-url-class.ts index 4df4514ec9c..89669f0e78b 100644 --- a/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/external-url-class.ts +++ b/src/SIL.XForge.Scripture/ClientApp/src/xforge-common/external-url-class.ts @@ -27,8 +27,8 @@ export class ExternalUrls { return this.helps + '/understanding-drafts'; } - get understandingDraftQuality(): string { - return this.helps + '/understanding-draft-quality'; + get improvingDraftQuality(): string { + return this.helps + '/improving-draft-quality'; } get configuringSources(): string {