Skip to content

Commit e4312d7

Browse files
committed
SF-3566 Guide user to formatting options on draft tab
1 parent 32028bb commit e4312d7

File tree

5 files changed

+108
-36
lines changed

5 files changed

+108
-36
lines changed

src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.html

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,24 @@
4444
}
4545
<div class="apply-draft-button-container">
4646
@if (featureFlags.usfmFormat.enabled) {
47-
<span
48-
[matTooltip]="t(doesLatestHaveDraft ? 'format_draft_can' : 'format_draft_cannot')"
49-
[style.cursor]="doesLatestHaveDraft ? 'pointer' : 'not-allowed'"
50-
>
51-
<button mat-button (click)="navigateToFormatting()" [disabled]="!doesLatestHaveDraft">
47+
@if (mustChooseFormattingOptions) {
48+
<button mat-flat-button (click)="navigateToFormatting()">
5249
<mat-icon>build</mat-icon>
53-
<transloco key="editor_draft_tab.format_draft"></transloco>
50+
<transloco class="hide-lt-md" key="editor_draft_tab.format_draft"></transloco>
51+
<transloco class="hide-gt-md" key="editor_draft_tab.formatting"></transloco>
5452
</button>
55-
</span>
53+
} @else {
54+
<span
55+
[matTooltip]="t(doesLatestHaveDraft ? 'format_draft_can' : 'format_draft_cannot')"
56+
[style.cursor]="doesLatestHaveDraft ? 'pointer' : 'not-allowed'"
57+
>
58+
<button mat-button (click)="navigateToFormatting()" [disabled]="!doesLatestHaveDraft">
59+
<mat-icon>build</mat-icon>
60+
<transloco class="hide-lt-md" key="editor_draft_tab.format_draft"></transloco>
61+
<transloco class="hide-gt-md" key="editor_draft_tab.formatting"></transloco>
62+
</button>
63+
</span>
64+
}
5665
}
5766
@if (userAppliedDraft) {
5867
<span class="draft-indicator">
@@ -61,16 +70,20 @@
6170
</span>
6271
}
6372
@if (canApplyDraft) {
64-
<button mat-flat-button color="primary" (click)="applyDraft()">
65-
<mat-icon>auto_awesome</mat-icon>
66-
@if (isDraftApplied) {
67-
<transloco key="editor_draft_tab.reapply_to_project"></transloco>
68-
} @else {
69-
<transloco key="editor_draft_tab.apply_to_project"></transloco>
70-
}
71-
</button>
72-
}
73-
@if (!canApplyDraft) {
73+
<span
74+
[matTooltip]="t(mustChooseFormattingOptions ? 'format_draft_before' : 'add_chapter_to_project')"
75+
[style.cursor]="mustChooseFormattingOptions ? 'not-allowed' : 'pointer'"
76+
>
77+
<button mat-flat-button color="primary" (click)="applyDraft()" [disabled]="mustChooseFormattingOptions">
78+
<mat-icon>auto_awesome</mat-icon>
79+
@if (isDraftApplied) {
80+
<transloco key="editor_draft_tab.reapply_to_project"></transloco>
81+
} @else {
82+
<transloco key="editor_draft_tab.apply_to_project"></transloco>
83+
}
84+
</button>
85+
</span>
86+
} @else {
7487
<app-notice icon="warning" type="warning" mode="fill-dark">
7588
{{ "editor_draft_tab.cannot_import" | transloco }}
7689
</app-notice>

src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ app-notice {
3131
flex-grow: 1;
3232
display: flex;
3333
justify-content: flex-end;
34-
column-gap: 4px;
34+
gap: 4px;
3535
align-items: center;
3636
flex-wrap: wrap;
3737
}

src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.spec.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { cloneDeep } from 'lodash-es';
88
import { TranslocoMarkupModule } from 'ngx-transloco-markup';
99
import { Delta } from 'quill';
1010
import { createTestProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-test-data';
11+
import { ParagraphBreakFormat, QuoteFormat } from 'realtime-server/lib/esm/scriptureforge/models/translate-config';
1112
import { of } from 'rxjs';
1213
import { anything, mock, verify, when } from 'ts-mockito';
1314
import { ActivatedProjectService } from 'xforge-common/activated-project.service';
@@ -351,6 +352,54 @@ describe('EditorDraftComponent', () => {
351352
}));
352353

353354
describe('applyDraft', () => {
355+
it('should allow user to apply draft when formatting selected', fakeAsync(() => {
356+
const testProjectDoc: SFProjectProfileDoc = {
357+
data: createTestProjectProfile({
358+
translateConfig: {
359+
draftConfig: {
360+
usfmConfig: { paragraphFormat: ParagraphBreakFormat.BestGuess, quoteFormat: QuoteFormat.Denormalized }
361+
}
362+
}
363+
})
364+
} as SFProjectProfileDoc;
365+
when(mockDraftGenerationService.draftExists(anything(), anything(), anything())).thenReturn(of(true));
366+
when(mockDraftGenerationService.getGeneratedDraftHistory(anything(), anything(), anything())).thenReturn(
367+
of(draftHistory)
368+
);
369+
when(mockActivatedProjectService.changes$).thenReturn(of(testProjectDoc));
370+
when(mockDialogService.confirm(anything(), anything())).thenResolve(true);
371+
spyOn<any>(component, 'getTargetOps').and.returnValue(of(targetDelta.ops));
372+
when(mockDraftHandlingService.getDraft(anything(), anything())).thenReturn(of(draftDelta.ops!));
373+
when(mockDraftHandlingService.draftDataToOps(anything(), anything())).thenReturn(draftDelta.ops!);
374+
375+
fixture.detectChanges();
376+
tick(EDITOR_READY_TIMEOUT);
377+
378+
expect(component.mustChooseFormattingOptions).toBe(false);
379+
flush();
380+
}));
381+
382+
it('should guide user to select formatting options when formatting not selected', fakeAsync(() => {
383+
const testProjectDoc: SFProjectProfileDoc = {
384+
data: createTestProjectProfile()
385+
} as SFProjectProfileDoc;
386+
when(mockDraftGenerationService.draftExists(anything(), anything(), anything())).thenReturn(of(true));
387+
when(mockDraftGenerationService.getGeneratedDraftHistory(anything(), anything(), anything())).thenReturn(
388+
of(draftHistory)
389+
);
390+
when(mockActivatedProjectService.changes$).thenReturn(of(testProjectDoc));
391+
when(mockDialogService.confirm(anything(), anything())).thenResolve(true);
392+
spyOn<any>(component, 'getTargetOps').and.returnValue(of(targetDelta.ops));
393+
when(mockDraftHandlingService.getDraft(anything(), anything())).thenReturn(of(draftDelta.ops!));
394+
when(mockDraftHandlingService.draftDataToOps(anything(), anything())).thenReturn(draftDelta.ops!);
395+
396+
fixture.detectChanges();
397+
tick(EDITOR_READY_TIMEOUT);
398+
399+
expect(component.mustChooseFormattingOptions).toBe(true);
400+
flush();
401+
}));
402+
354403
it('should show a prompt when applying if the target has content', fakeAsync(() => {
355404
const testProjectDoc: SFProjectProfileDoc = {
356405
data: createTestProjectProfile()

src/SIL.XForge.Scripture/ClientApp/src/app/translate/editor/editor-draft/editor-draft.component.ts

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export class EditorDraftComponent implements AfterViewInit, OnChanges {
6666
isDraftReady = false;
6767
isDraftApplied = false;
6868
userAppliedDraft = false;
69+
hasFormattingSelected = true;
6970

7071
private selectedRevisionSubject = new BehaviorSubject<Revision | undefined>(undefined);
7172
private selectedRevision$ = this.selectedRevisionSubject.asObservable();
@@ -98,6 +99,28 @@ export class EditorDraftComponent implements AfterViewInit, OnChanges {
9899
private readonly router: Router
99100
) {}
100101

102+
get bookId(): string {
103+
return this.bookNum !== undefined ? Canon.bookNumberToId(this.bookNum) : '';
104+
}
105+
106+
get canApplyDraft(): boolean {
107+
if (this.targetProject == null || this.bookNum == null || this.chapter == null || this.draftDelta?.ops == null) {
108+
return false;
109+
}
110+
return this.draftHandlingService.canApplyDraft(this.targetProject, this.bookNum, this.chapter, this.draftDelta.ops);
111+
}
112+
113+
get doesLatestHaveDraft(): boolean {
114+
return (
115+
this.targetProject?.texts.find(t => t.bookNum === this.bookNum)?.chapters.find(c => c.number === this.chapter)
116+
?.hasDraft ?? false
117+
);
118+
}
119+
120+
get mustChooseFormattingOptions(): boolean {
121+
return this.featureFlags.usfmFormat.enabled && !this.hasFormattingSelected;
122+
}
123+
101124
ngOnChanges(): void {
102125
if (this.projectId == null || this.bookNum == null || this.chapter == null) {
103126
throw new Error('projectId, bookNum, or chapter is null');
@@ -117,10 +140,6 @@ export class EditorDraftComponent implements AfterViewInit, OnChanges {
117140
this.selectedRevisionSubject.next(this.selectedRevision);
118141
}
119142

120-
get bookId(): string {
121-
return this.bookNum !== undefined ? Canon.bookNumberToId(this.bookNum) : '';
122-
}
123-
124143
populateDraftTextInit(): void {
125144
combineLatest([
126145
this.onlineStatusService.onlineStatus$,
@@ -177,6 +196,8 @@ export class EditorDraftComponent implements AfterViewInit, OnChanges {
177196
filterNullish(),
178197
tap(projectDoc => {
179198
this.targetProject = projectDoc.data;
199+
console.log(this.targetProject);
200+
this.hasFormattingSelected = projectDoc.data?.translateConfig.draftConfig.usfmConfig != null;
180201
}),
181202
distinctUntilChanged(),
182203
map(() => initialTimestamp)
@@ -237,20 +258,6 @@ export class EditorDraftComponent implements AfterViewInit, OnChanges {
237258
});
238259
}
239260

240-
get canApplyDraft(): boolean {
241-
if (this.targetProject == null || this.bookNum == null || this.chapter == null || this.draftDelta?.ops == null) {
242-
return false;
243-
}
244-
return this.draftHandlingService.canApplyDraft(this.targetProject, this.bookNum, this.chapter, this.draftDelta.ops);
245-
}
246-
247-
get doesLatestHaveDraft(): boolean {
248-
return (
249-
this.targetProject?.texts.find(t => t.bookNum === this.bookNum)?.chapters.find(c => c.number === this.chapter)
250-
?.hasDraft ?? false
251-
);
252-
}
253-
254261
navigateToFormatting(): void {
255262
this.router.navigateByUrl(`/projects/${this.projectId}/draft-generation/format/${this.bookId}/${this.chapter}`);
256263
}

src/SIL.XForge.Scripture/ClientApp/src/assets/i18n/non_checking_en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,13 +399,16 @@
399399
"your_comment": "Your comment"
400400
},
401401
"editor_draft_tab": {
402+
"add_chapter_to_project": "Add this chapter to the project",
402403
"apply_to_project": "Add to project",
403404
"cannot_import": "You cannot import this draft because you do not have permission to edit this chapter. Permissions can be updated in Paratext.",
404405
"click_book_to_preview": "Click a book below to preview the draft and add it to your project.",
405406
"draft_indicator_applied": "Added",
406407
"draft_legacy_warning": "We have updated our drafting functionality. You can take advantage of this by [link:generateDraftUrl]generating a new draft[/link].",
407408
"error_applying_draft": "Failed to add the draft to the project. Try again later.",
409+
"formatting": "Formatting",
408410
"format_draft": "Formatting options",
411+
"format_draft_before": "Select formatting options before adding it to your project.",
409412
"format_draft_can": "Customize formatting options for the draft",
410413
"format_draft_cannot": "You can only change formatting for books from the latest draft",
411414
"no_draft_notice": "{{ bookChapterName }} has no draft.",

0 commit comments

Comments
 (0)