Skip to content

Commit 2d146ce

Browse files
committed
SF-3613 Allow old drafts to open draft tab without formatting options
1 parent 000607b commit 2d146ce

File tree

10 files changed

+141
-95
lines changed

10 files changed

+141
-95
lines changed

src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-history-list/draft-history-entry/draft-history-entry.component.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ describe('DraftHistoryEntryComponent', () => {
8383
when(mockedTrainingDataService.queryTrainingDataAsync(anything(), anything())).thenResolve(
8484
instance(trainingDataQuery)
8585
);
86-
when(mockedDraftOptionsService.areFormattingOptionsAvailableButUnselected()).thenReturn(true);
86+
when(mockedDraftOptionsService.areFormattingOptionsAvailableButUnselected(anything())).thenReturn(true);
8787
fixture = TestBed.createComponent(DraftHistoryEntryComponent);
8888
component = fixture.componentInstance;
8989
fixture.detectChanges();
@@ -168,7 +168,7 @@ describe('DraftHistoryEntryComponent', () => {
168168
}));
169169

170170
it('should show the USFM format option when the project is the latest draft', fakeAsync(() => {
171-
when(mockedDraftOptionsService.areFormattingOptionsAvailableButUnselected()).thenReturn(false);
171+
when(mockedDraftOptionsService.areFormattingOptionsAvailableButUnselected(anything())).thenReturn(false);
172172
when(mockedDraftOptionsService.areFormattingOptionsSupportedForBuild(anything())).thenReturn(true);
173173
const user = 'user-display-name';
174174
const date = dateAfterFormattingSupported;
@@ -241,7 +241,7 @@ describe('DraftHistoryEntryComponent', () => {
241241
}));
242242

243243
it('should handle builds with additional info referencing a deleted user', fakeAsync(() => {
244-
when(mockedDraftOptionsService.areFormattingOptionsAvailableButUnselected()).thenReturn(false);
244+
when(mockedDraftOptionsService.areFormattingOptionsAvailableButUnselected(anything())).thenReturn(false);
245245
when(mockedDraftOptionsService.areFormattingOptionsSupportedForBuild(anything())).thenReturn(true);
246246
when(mockedI18nService.formatDate(anything())).thenReturn('formatted-date');
247247
when(mockedI18nService.formatAndLocalizeScriptureRange('GEN')).thenReturn('Genesis');
@@ -353,7 +353,7 @@ describe('DraftHistoryEntryComponent', () => {
353353
});
354354

355355
it('should show set draft format UI', fakeAsync(() => {
356-
when(mockedDraftOptionsService.areFormattingOptionsAvailableButUnselected()).thenReturn(false);
356+
when(mockedDraftOptionsService.areFormattingOptionsAvailableButUnselected(anything())).thenReturn(false);
357357
when(mockedDraftOptionsService.areFormattingOptionsSupportedForBuild(anything())).thenReturn(true);
358358
const date = dateAfterFormattingSupported;
359359
component.entry = {

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

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ describe('DraftOptionsService', () => {
4545
return doc;
4646
}
4747

48+
function buildDtoWithDate(date: Date): BuildDto {
49+
return {
50+
additionalInfo: {
51+
dateFinished: date.toJSON()
52+
}
53+
} as BuildDto;
54+
}
55+
56+
const SUPPORTED_BUILD_ENTRY: BuildDto = buildDtoWithDate(new Date(FORMATTING_OPTIONS_SUPPORTED_DATE.getTime() + 1));
57+
4858
const PROJECT_DOC_BOTH_FORMATS: SFProjectProfileDoc = buildProjectDoc({
4959
paragraphFormat: ParagraphBreakFormat.BestGuess,
5060
quoteFormat: QuoteFormat.Normalized
@@ -83,23 +93,28 @@ describe('DraftOptionsService', () => {
8393
describe('areFormattingOptionsAvailableButUnselected', () => {
8494
it('returns true when flag enabled and both options missing', () => {
8595
when(mockedActivatedProject.projectDoc).thenReturn(PROJECT_DOC_EMPTY_USFM);
86-
expect(service.areFormattingOptionsAvailableButUnselected()).toBe(true);
96+
expect(service.areFormattingOptionsAvailableButUnselected(SUPPORTED_BUILD_ENTRY)).toBe(true);
8797
});
8898

8999
it('returns true when flag enabled and one option missing', () => {
90100
when(mockedActivatedProject.projectDoc).thenReturn(PROJECT_DOC_QUOTE_ONLY);
91-
expect(service.areFormattingOptionsAvailableButUnselected()).toBe(true);
101+
expect(service.areFormattingOptionsAvailableButUnselected(SUPPORTED_BUILD_ENTRY)).toBe(true);
92102
});
93103

94104
it('returns false when flag enabled and both options set', () => {
95105
when(mockedActivatedProject.projectDoc).thenReturn(PROJECT_DOC_BOTH_FORMATS);
96-
expect(service.areFormattingOptionsAvailableButUnselected()).toBe(false);
106+
expect(service.areFormattingOptionsAvailableButUnselected(SUPPORTED_BUILD_ENTRY)).toBe(false);
97107
});
98108

99109
it('returns false when flag disabled', () => {
100110
when(mockedFeatureFlagService.usfmFormat).thenReturn(createTestFeatureFlag(false));
101111
when(mockedActivatedProject.projectDoc).thenReturn(PROJECT_DOC_EMPTY_USFM);
102-
expect(service.areFormattingOptionsAvailableButUnselected()).toBe(false);
112+
expect(service.areFormattingOptionsAvailableButUnselected(SUPPORTED_BUILD_ENTRY)).toBe(false);
113+
});
114+
115+
it('returns false when build entry unavailable', () => {
116+
when(mockedActivatedProject.projectDoc).thenReturn(PROJECT_DOC_EMPTY_USFM);
117+
expect(service.areFormattingOptionsAvailableButUnselected(undefined)).toBe(false);
103118
});
104119
});
105120

@@ -109,7 +124,7 @@ describe('DraftOptionsService', () => {
109124
if (date == null) {
110125
return { additionalInfo: {} } as BuildDto;
111126
}
112-
return { additionalInfo: { dateFinished: date.toJSON() } } as BuildDto;
127+
return buildDtoWithDate(date);
113128
}
114129

115130
it('returns true when flag enabled and date after supported date', () => {

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ export class DraftOptionsService {
2323
);
2424
}
2525

26-
areFormattingOptionsAvailableButUnselected(): boolean {
27-
return (
28-
this.featureFlags.usfmFormat.enabled &&
29-
(this.activatedProjectService.projectDoc?.data?.translateConfig.draftConfig.usfmConfig?.paragraphFormat == null ||
30-
this.activatedProjectService.projectDoc?.data?.translateConfig.draftConfig.usfmConfig?.quoteFormat == null)
31-
);
26+
areFormattingOptionsAvailableButUnselected(draftBuild: BuildDto | undefined): boolean {
27+
const usfmConfig = this.activatedProjectService.projectDoc?.data?.translateConfig.draftConfig.usfmConfig;
28+
const optionsSelected = usfmConfig?.paragraphFormat != null && usfmConfig?.quoteFormat != null;
29+
30+
const available = this.featureFlags.usfmFormat.enabled && this.areFormattingOptionsSupportedForBuild(draftBuild);
31+
return available && !optionsSelected;
3232
}
3333

3434
areFormattingOptionsSupportedForBuild(entry: BuildDto | undefined): boolean {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
</mat-form-field>
4444
}
4545
<div class="apply-draft-button-container">
46-
@if (featureFlags.usfmFormat.enabled) {
46+
@if (showDraftOptionsButton$ | async) {
4747
<span
4848
[matTooltip]="t(doesLatestHaveDraft ? 'format_draft_can' : 'format_draft_cannot')"
4949
[style.cursor]="doesLatestHaveDraft ? 'pointer' : 'not-allowed'"

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ describe('EditorDraftComponent', () => {
8383
when(mockFeatureFlagService.usfmFormat).thenReturn(createTestFeatureFlag(true));
8484
when(mockDraftGenerationService.pollBuildProgress(anything())).thenReturn(buildProgress$.asObservable());
8585
buildProgress$.next({ state: BuildStates.Completed } as BuildDto);
86+
when(mockActivatedProjectService.projectId$).thenReturn(of('targetProjectId'));
87+
when(mockDraftGenerationService.getLastCompletedBuild(anything())).thenReturn(of(undefined));
8688

8789
fixture = TestBed.createComponent(EditorDraftComponent);
8890
component = fixture.componentInstance;

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import { BuildStates } from '../../../machine-api/build-states';
4242
import { TextComponent } from '../../../shared/text/text.component';
4343
import { DraftGenerationService } from '../../draft-generation/draft-generation.service';
4444
import { DraftHandlingService } from '../../draft-generation/draft-handling.service';
45+
import { DraftOptionsService } from '../../draft-generation/draft-options.service';
4546
@Component({
4647
selector: 'app-editor-draft',
4748
templateUrl: './editor-draft.component.html',
@@ -82,6 +83,12 @@ export class EditorDraftComponent implements AfterViewInit, OnChanges {
8283
this.onlineStatusService.onlineStatus$
8384
]).pipe(map(([isLoading, isOnline]) => isLoading || !isOnline));
8485

86+
showDraftOptionsButton$: Observable<boolean> = this.activatedProjectService.projectId$.pipe(
87+
filterNullish(),
88+
switchMap(projectId => this.draftGenerationService.getLastCompletedBuild(projectId)),
89+
map(build => this.draftOptionsService.areFormattingOptionsSupportedForBuild(build))
90+
);
91+
8592
private draftDelta?: Delta;
8693
private targetDelta?: Delta;
8794

@@ -98,7 +105,8 @@ export class EditorDraftComponent implements AfterViewInit, OnChanges {
98105
readonly onlineStatusService: OnlineStatusService,
99106
private readonly noticeService: NoticeService,
100107
private errorReportingService: ErrorReportingService,
101-
private readonly router: Router
108+
private readonly router: Router,
109+
private readonly draftOptionsService: DraftOptionsService
102110
) {}
103111

104112
get bookId(): string {

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4111,8 +4111,8 @@ describe('EditorComponent', () => {
41114111
Object.defineProperty(env.component, 'showSource', { get: () => true });
41124112
});
41134113
env.setupProject({ translateConfig: { draftConfig: {} } });
4114-
// Formatting options not selected, so draft tab should not be shown
4115-
when(mockedDraftOptionsService.areFormattingOptionsAvailableButUnselected()).thenReturn(true);
4114+
// Formatting options not selected, so draft tab should be blocked
4115+
when(mockedDraftOptionsService.areFormattingOptionsAvailableButUnselected(anything())).thenReturn(true);
41164116
when(mockedPermissionsService.canAccessDrafts(anything(), anything())).thenReturn(true);
41174117
env.wait();
41184118
env.routeWithParams({ projectId: 'project01', bookId: 'LUK', chapter: '1' });
@@ -4903,6 +4903,8 @@ class TestEnvironment {
49034903
).thenReturn(of([]));
49044904
when(mockedDraftGenerationService.getGeneratedDraftHistory(anything(), anything(), anything())).thenReturn(of([]));
49054905
when(mockedDraftGenerationService.draftExists(anything(), anything(), anything())).thenReturn(of(true));
4906+
when(mockedDraftGenerationService.getLastCompletedBuild(anything())).thenReturn(of({} as BuildDto));
4907+
when(mockedDraftOptionsService.areFormattingOptionsAvailableButUnselected(anything())).thenReturn(false);
49064908
when(mockedPermissionsService.isUserOnProject(anything())).thenResolve(true);
49074909
when(mockedFeatureFlagService.newDraftHistory).thenReturn(createTestFeatureFlag(false));
49084910
when(mockedLynxWorkspaceService.rawInsightSource$).thenReturn(of([]));

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

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,20 +1491,25 @@ export class EditorComponent extends DataLoadingComponent implements OnDestroy,
14911491
this.projectDoc,
14921492
this.userService.currentUserId
14931493
);
1494-
if (
1495-
((hasDraft && !draftApplied) || urlDraftActive) &&
1496-
canViewDrafts &&
1497-
!this.draftOptionsService.areFormattingOptionsAvailableButUnselected()
1498-
) {
1494+
1495+
const hasUnappliedDraft: boolean = hasDraft && !draftApplied;
1496+
const draftShouldBeVisible: boolean = hasUnappliedDraft || urlDraftActive;
1497+
1498+
let draftBuild: BuildDto | undefined;
1499+
// Only try to fetch the draft build if existing information indicates we should show the draft
1500+
if (draftShouldBeVisible && canViewDrafts && this.projectId != null) {
1501+
draftBuild = await firstValueFrom(this.draftGenerationService.getLastCompletedBuild(this.projectId));
1502+
}
1503+
1504+
const isBlockedByFormattingOptions: boolean =
1505+
this.draftOptionsService.areFormattingOptionsAvailableButUnselected(draftBuild);
1506+
1507+
if (draftShouldBeVisible && canViewDrafts && draftBuild != null && !isBlockedByFormattingOptions) {
14991508
// URL may indicate to select the 'draft' tab (such as when coming from generate draft page)
15001509
const groupIdToAddTo: EditorTabGroupType = this.showSource ? 'source' : 'target';
15011510

15021511
// Add to 'source' (or 'target' if showSource is false) tab group if no existing draft tab
15031512
if (existingDraftTab == null) {
1504-
const draftBuild: BuildDto | undefined = await firstValueFrom(
1505-
this.draftGenerationService.getLastCompletedBuild(this.projectId!)
1506-
);
1507-
15081513
this.tabState.addTab(
15091514
groupIdToAddTo,
15101515
this.editorTabFactory.createTab('draft', {

0 commit comments

Comments
 (0)