Skip to content

Commit 0d17bbc

Browse files
committed
SF-3757 Simplify draft sources configuration page
1 parent 50ffeaf commit 0d17bbc

22 files changed

Lines changed: 380 additions & 1123 deletions

scripts/db_tools/parse-version.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,17 @@ class ParseVersion {
3333
'Stillness (non-distracting progress indicators)',
3434
'Use In-Process Machine for Suggestions',
3535
'Use Serval for Suggestions',
36-
'Use Echo for Pre-Translation Drafting',
36+
'Allow Echo for Pre-Translation Drafting',
3737
'Allow Fast Pre-Translation Training',
3838
'Upload Paratext Zip Files for Pre-Translation Drafting',
3939
'Allow mixing in an additional training source',
4040
'Updated Learning Rate For Serval',
41-
'Dark Mode',
41+
'Dark mode',
4242
'Enable Lynx insights',
4343
'Preview new draft history interface',
4444
'USFM Format',
45-
'Show in-app draft signup form instead of external link'
45+
'Show in-app draft signup form instead of external link',
46+
'Show new configure sources page'
4647
];
4748

4849
constructor() {

src/SIL.XForge.Scripture/ClientApp/e2e/workflows/generate-draft.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,22 @@ export async function generateDraft(
4949
await user.click(page.getByRole('button', { name: 'Configure sources' }));
5050
await screenshot(page, { pageName: 'configure_sources_initial', ...context });
5151

52+
const trainingDataSection = page.locator('mat-card').nth(0);
53+
const translationDataSection = page.locator('mat-card').nth(1);
54+
5255
// Step 1: Reference projects
53-
await user.click(page.getByRole('combobox').first());
56+
await user.click(trainingDataSection.getByRole('combobox').first());
5457
await user.type('ntv');
5558
await user.click(page.getByRole('option', { name: 'NTV - Nueva Traducción' }));
5659
await user.click(page.getByRole('button', { name: 'Add another reference project' }));
57-
await user.click(page.getByRole('combobox').last());
60+
await user.click(trainingDataSection.getByRole('combobox').nth(1));
5861
await user.type('dhh94');
5962
await user.click(page.getByRole('option', { name: 'DHH94 - Spanish: Dios Habla' }));
60-
await user.click(page.getByRole('button', { name: 'Next' }));
6163

6264
// Step 2: Source project
63-
await user.click(page.getByRole('combobox'));
65+
await user.click(translationDataSection.getByRole('combobox'));
6466
await user.type('ntv');
6567
await user.click(page.getByRole('option', { name: 'NTV - Nueva Traducción' }));
66-
await user.click(page.getByRole('button', { name: 'Next' }));
6768

6869
// Step 3: Main project and other training data
6970
await user.check(page.getByRole('checkbox', { name: 'All the language codes are correct' }));

src/SIL.XForge.Scripture/ClientApp/e2e/workflows/localized-screenshots.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -214,49 +214,48 @@ export async function localizedScreenshots(
214214
// Increase the height of the viewport to ensure all elements are visible
215215
await page.setViewportSize({ width: originalViewportSize.width, height: 1200 });
216216

217-
await page.getByRole('combobox').fill('ntv');
217+
const trainingDataSection = page.locator('mat-card').nth(0);
218+
const translationDataSection = page.locator('mat-card').nth(1);
219+
220+
await trainingDataSection.getByRole('combobox').first().fill('ntv');
218221
await page.getByRole('option', { name: 'NTV - Nueva Traducción' }).click();
219222

220223
const addReference = page.locator('.add-another-project');
221-
const nextButton = page.locator('.step-button-wrapper').getByRole('button').last();
222224

223225
await forEachLocale(async locale => {
224226
await user.hover(addReference, defaultArrowLocation);
225227
await screenshotElements(
226228
page,
227-
[page.locator('app-draft-sources > .draft-sources-stepper'), page.locator('app-draft-sources > .overview')],
229+
[trainingDataSection, translationDataSection],
228230
{ ...context, pageName: 'configure_sources_draft_reference', locale },
229231
{ margin: 8 }
230232
);
231233
});
232-
await page.getByRole('combobox').fill('ntv');
233-
await page.getByRole('option', { name: 'NTV - Nueva Traducción' }).click();
234+
234235
await user.click(addReference);
235-
await page.getByRole('combobox').last().fill('dhh94');
236+
await trainingDataSection.getByRole('combobox').nth(1).fill('dhh94');
236237
await page.getByRole('option', { name: 'DHH94 - Spanish: Dios Habla' }).click();
237-
await nextButton.click();
238238

239239
await forEachLocale(async locale => {
240-
await page.getByRole('combobox').fill('ntv');
240+
await translationDataSection.getByRole('combobox').fill('ntv');
241241
await page.getByRole('option', { name: 'NTV - Nueva Traducción' }).click();
242-
await user.hover(nextButton, defaultArrowLocation);
242+
await user.hover(translationDataSection.getByRole('combobox'), defaultArrowLocation);
243243
await screenshotElements(
244244
page,
245-
[page.locator('app-draft-sources > .draft-sources-stepper'), page.locator('app-draft-sources > .overview')],
245+
[trainingDataSection, translationDataSection],
246246
{ ...context, pageName: 'configure_sources_draft_source', locale },
247247
{ margin: 8 }
248248
);
249249
});
250250

251-
await page.getByRole('combobox').fill('ntv');
251+
await translationDataSection.getByRole('combobox').fill('ntv');
252252
await page.getByRole('option', { name: 'NTV - Nueva Traducción' }).click();
253-
await nextButton.click();
254253

255254
await forEachLocale(async locale => {
256255
await user.hover(await page.getByRole('checkbox'));
257256
await screenshotElements(
258257
page,
259-
[page.locator('app-draft-sources')],
258+
[page.locator('app-configure-sources')],
260259
{ ...context, pageName: 'configure_sources_confirm_languages', locale },
261260
{ margin: 8 }
262261
);

src/SIL.XForge.Scripture/ClientApp/src/app/app.routes.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ import {
2727
UsersAuthGuard
2828
} from './shared/project-router.guard';
2929
import { SyncComponent } from './sync/sync.component';
30+
import { ConfigureSourcesComponent } from './translate/draft-generation/configure-sources/configure-sources.component';
3031
import { DraftGenerationComponent } from './translate/draft-generation/draft-generation.component';
3132
import { DraftOnboardingFormComponent } from './translate/draft-generation/draft-signup-form/draft-onboarding-form.component';
32-
import { DraftSourcesComponent } from './translate/draft-generation/draft-sources/draft-sources.component';
3333
import { DraftUsfmFormatComponent } from './translate/draft-generation/draft-usfm-format/draft-usfm-format.component';
3434
import { EditorComponent } from './translate/editor/editor.component';
3535
import { TranslateOverviewComponent } from './translate/translate-overview/translate-overview.component';
@@ -67,8 +67,8 @@ export const APP_ROUTES: Routes = [
6767
canDeactivate: [DraftNavigationAuthGuard]
6868
},
6969
{
70-
path: 'projects/:projectId/draft-generation/sources',
71-
component: DraftSourcesComponent,
70+
path: 'projects/:projectId/draft-generation/configure-sources',
71+
component: ConfigureSourcesComponent,
7272
canActivate: [NmtDraftAuthGuard],
7373
canDeactivate: [DraftNavigationAuthGuard]
7474
},
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
<ng-container *transloco="let t; read: 'draft_sources'">
2+
<h1>{{ t("configure_draft_sources") }}</h1>
3+
4+
<mat-card>
5+
<mat-card-header>
6+
<mat-card-title>{{ t("train_language_model") }}</mat-card-title>
7+
</mat-card-header>
8+
<mat-card-content class="training-data-card-content">
9+
<h3 class="heading-left">{{ t("overview_reference") }} {{ parentheses(referenceLanguageDisplayName) }}</h3>
10+
11+
<div class="description-left">{{ t("select_primary_reference") }}</div>
12+
<div class="inputs-left">
13+
@for (source of trainingSources; track $index) {
14+
<app-project-select
15+
[isDisabled]="loading || !appOnline"
16+
[projects]="projects"
17+
[resources]="resources"
18+
[nonSelectableProjects]="nonSelectableProjects"
19+
[value]="source?.paratextId"
20+
[hiddenParatextIds]="getHiddenParatextIds(trainingSources, source?.paratextId)"
21+
(valueChange)="sourceSelected(trainingSources, $index, $event)"
22+
[placeholder]="projectPlaceholder(source)"
23+
></app-project-select>
24+
}
25+
26+
@if (allowAddingATrainingSource) {
27+
<div>{{ t("some_projects_use_back_translation") }}</div>
28+
<button
29+
mat-button
30+
(click)="trainingSources.push(undefined); $event.preventDefault()"
31+
class="add-another-project"
32+
>
33+
<mat-icon>add</mat-icon> {{ t("add_another_reference_project") }}
34+
</button>
35+
}
36+
</div>
37+
38+
<span class="arrow mirror-rtl"><mat-icon>arrow_right_alt</mat-icon></span>
39+
<h3 class="heading-right">{{ t("overview_translated_project") }} {{ parentheses(targetLanguageDisplayName) }}</h3>
40+
<div class="description-right">
41+
@for (portion of i18n.interpolateVariables("draft_sources.project_always_used"); track $index) {
42+
@if (portion.id === "currentProjectShortName") {
43+
<strong>{{ currentProjectShortName }}</strong>
44+
}
45+
<!-- prettier-ignore -->
46+
@else {{{ portion.text }}}
47+
}
48+
<!-- Select here any other projects to be used on the target side. All of these should be in the language of the target (<strong>{{ targetLanguageDisplayName }}</strong>). -->
49+
</div>
50+
<div class="inputs-right">
51+
@for (source of trainingTargets; track $index) {
52+
<app-project-select
53+
[isDisabled]="true"
54+
[projects]="projects"
55+
[resources]="resources"
56+
[nonSelectableProjects]="nonSelectableProjects"
57+
[value]="source?.paratextId"
58+
[hiddenParatextIds]="getHiddenParatextIds(trainingTargets, source?.paratextId)"
59+
[placeholder]="projectPlaceholder(source)"
60+
></app-project-select>
61+
}
62+
</div>
63+
<div class="training-files">
64+
<mat-divider></mat-divider>
65+
<h3>{{ t("additional_training_data_optional") }}</h3>
66+
<div>{{ t("training_files_description", { sourceLanguageDisplayName, targetLanguageDisplayName }) }}</div>
67+
<app-training-data-multi-select
68+
[availableTrainingData]="availableTrainingFiles"
69+
(trainingDataSelect)="onTrainingDataSelect($event)"
70+
></app-training-data-multi-select>
71+
</div>
72+
</mat-card-content>
73+
</mat-card>
74+
75+
<mat-card>
76+
<mat-card-header>
77+
<mat-card-title> {{ t("generate_a_draft_from_the_language_model") }} </mat-card-title>
78+
</mat-card-header>
79+
<mat-card-content class="translation-data-card-content">
80+
<h3 class="heading-left">{{ t("overview_source") }} {{ parentheses(sourceLanguageDisplayName) }}</h3>
81+
<div class="description-left">{{ t("select_project_to_translate") }}</div>
82+
<div class="inputs-left">
83+
@for (source of draftingSources; track $index) {
84+
<app-project-select
85+
[isDisabled]="loading || !appOnline"
86+
[projects]="projects"
87+
[resources]="resources"
88+
[nonSelectableProjects]="nonSelectableProjects"
89+
[value]="source?.paratextId"
90+
[hiddenParatextIds]="getHiddenParatextIds(draftingSources, source?.paratextId)"
91+
(valueChange)="sourceSelected(draftingSources, $index, $event)"
92+
[placeholder]="projectPlaceholder(source)"
93+
></app-project-select>
94+
}
95+
</div>
96+
</mat-card-content>
97+
</mat-card>
98+
99+
<app-language-codes-confirmation
100+
class="confirm-language-codes"
101+
[sources]="draftSourcesAsArray"
102+
[clearCheckbox]="clearLanguageCodeConfirmationCheckbox"
103+
(messageIfUserTriesToContinue)="languageCodeConfirmationMessageIfUserTriesToContinue = $event"
104+
></app-language-codes-confirmation>
105+
106+
<div class="component-footer">
107+
@if (!appOnline) {
108+
<mat-error id="offline-message">
109+
{{ t("offline_message") }}
110+
</mat-error>
111+
}
112+
<div class="page-actions">
113+
<button mat-button (click)="cancel()"><mat-icon>close</mat-icon>{{ t("cancel") }}</button>
114+
<button id="save_button" mat-flat-button color="primary" (click)="save()" [disabled]="!appOnline">
115+
<mat-icon>check</mat-icon>{{ t("save_and_sync") }}
116+
</button>
117+
</div>
118+
</div>
119+
120+
@if (getControlState("projectSettings") != null) {
121+
<mat-card class="saving">
122+
<mat-card-header>
123+
<mat-card-title>{{ t("saving_draft_sources") }}</mat-card-title>
124+
</mat-card-header>
125+
<mat-card-content>
126+
<div class="saving-indicator">
127+
@if (getControlState("projectSettings") === ElementState.Submitting) {
128+
<mat-spinner [diameter]="24" color="primary"></mat-spinner> {{ t("saving") }}
129+
} @else if (getControlState("projectSettings") === ElementState.Submitted) {
130+
<mat-icon class="success">checkmark</mat-icon> {{ t("all_changes_saved") }}
131+
} @else {
132+
<mat-icon class="failure">error</mat-icon> {{ t("failed_to_save_changes") }}
133+
}
134+
</div>
135+
@for (entry of syncStatus | keyvalue; track entry.key) {
136+
<div>
137+
@if (entry.value.knownToBeOnSF) {
138+
@if (entry.value.isSyncing) {
139+
<mat-spinner [diameter]="24"></mat-spinner> {{ entry.value.shortName }} - {{ t("state_syncing") }}
140+
} @else {
141+
@if (entry.value.lastSyncSuccessful) {
142+
<mat-icon class="success">check</mat-icon> {{ entry.value.shortName }} -
143+
{{ t("state_sync_successful") }}
144+
} @else {
145+
<mat-icon class="failure">error</mat-icon> {{ entry.value.shortName }} -
146+
{{ t("state_sync_failed") }}
147+
}
148+
}
149+
} @else {
150+
<mat-spinner [diameter]="24"></mat-spinner> {{ entry.value.shortName }} - {{ t("state_connecting") }}
151+
}
152+
</div>
153+
}
154+
</mat-card-content>
155+
@if (allProjectsSavedAndSynced || getControlState("projectSettings") === ElementState.Error) {
156+
<mat-card-actions align="end">
157+
<button mat-button (click)="navigateToDrafting()"><mat-icon>close</mat-icon> {{ t("close") }}</button>
158+
</mat-card-actions>
159+
}
160+
</mat-card>
161+
}
162+
</ng-container>

0 commit comments

Comments
 (0)