Skip to content

Commit

Permalink
Merge branch 'master' into improvement/show-logo-on-mobile
Browse files Browse the repository at this point in the history
  • Loading branch information
nigel-wells authored Dec 20, 2024
2 parents 6aaa027 + 5202070 commit 827b99b
Show file tree
Hide file tree
Showing 57 changed files with 931 additions and 315 deletions.
18 changes: 18 additions & 0 deletions src/RealtimeServer/common/migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,21 @@ export abstract class DocMigration implements Migration {
// do nothing
}
}

/**
* Verifies that the specified migrations are have version numbers monotonically increasing by 1 and that the class
* names include the version number. Throws an error if any of the migrations violate this rule. Otherwise, returns the
* migrations.
*/
export function monotonicallyIncreasingMigrationList(migrations: MigrationConstructor[]): MigrationConstructor[] {
for (const [index, migration] of migrations.entries()) {
const expectedVersion = index + 1;
if (migration.VERSION !== expectedVersion) {
throw new Error(`Migration version mismatch: expected ${expectedVersion}, got ${migration.VERSION}`);
}
if (!migration.name.includes(migration.VERSION.toString())) {
throw new Error(`Migration class name must include the version number: ${migration.name}`);
}
}
return migrations;
}
4 changes: 2 additions & 2 deletions src/RealtimeServer/common/services/user-migrations.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Doc, Op } from 'sharedb/lib/client';
import { submitMigrationOp } from '../../common/realtime-server';
import { DocMigration, MigrationConstructor } from '../migration';
import { DocMigration, MigrationConstructor, monotonicallyIncreasingMigrationList } from '../migration';

class UserMigration1 extends DocMigration {
static readonly VERSION = 1;
Expand All @@ -21,4 +21,4 @@ class UserMigration1 extends DocMigration {
}
}

export const USER_MIGRATIONS: MigrationConstructor[] = [UserMigration1];
export const USER_MIGRATIONS: MigrationConstructor[] = monotonicallyIncreasingMigrationList([UserMigration1]);
9 changes: 9 additions & 0 deletions src/RealtimeServer/scriptureforge/models/translate-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ export interface BaseProject {
shortName: string;
}

/**
* A per-project scripture range.
*/
export interface ProjectScriptureRange {
projectId: string;
scriptureRange: string;
}

export interface DraftConfig {
additionalTrainingData: boolean;
additionalTrainingSourceEnabled: boolean;
Expand All @@ -38,6 +46,7 @@ export interface DraftConfig {
lastSelectedTrainingBooks: number[];
lastSelectedTrainingDataFiles: string[];
lastSelectedTrainingScriptureRange?: string;
lastSelectedTrainingScriptureRanges?: ProjectScriptureRange[];
lastSelectedTranslationBooks: number[];
lastSelectedTranslationScriptureRange?: string;
servalConfig?: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { MigrationConstructor } from '../../common/migration';
import { MigrationConstructor, monotonicallyIncreasingMigrationList } from '../../common/migration';

export const BIBLICAL_TERM_MIGRATIONS: MigrationConstructor[] = [];
export const BIBLICAL_TERM_MIGRATIONS: MigrationConstructor[] = monotonicallyIncreasingMigrationList([]);
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Doc, Op } from 'sharedb/lib/client';
import { DocMigration, MigrationConstructor } from '../../common/migration';
import { DocMigration, MigrationConstructor, monotonicallyIncreasingMigrationList } from '../../common/migration';
import { submitMigrationOp } from '../../common/realtime-server';

class NoteThreadMigration1 extends DocMigration {
Expand Down Expand Up @@ -69,9 +69,9 @@ class NoteThreadMigration4 extends DocMigration {
}
}

export const NOTE_THREAD_MIGRATIONS: MigrationConstructor[] = [
export const NOTE_THREAD_MIGRATIONS: MigrationConstructor[] = monotonicallyIncreasingMigrationList([
NoteThreadMigration1,
NoteThreadMigration2,
NoteThreadMigration3,
NoteThreadMigration4
];
]);
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Doc, Op } from 'sharedb/lib/client';
import { DocMigration, MigrationConstructor } from '../../common/migration';
import { DocMigration, MigrationConstructor, monotonicallyIncreasingMigrationList } from '../../common/migration';
import { submitMigrationOp } from '../../common/realtime-server';

class QuestionMigration1 extends DocMigration {
Expand All @@ -24,4 +24,4 @@ class QuestionMigration1 extends DocMigration {
}
}

export const QUESTION_MIGRATIONS: MigrationConstructor[] = [QuestionMigration1];
export const QUESTION_MIGRATIONS: MigrationConstructor[] = monotonicallyIncreasingMigrationList([QuestionMigration1]);
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,28 @@ describe('SFProjectMigrations', () => {
expect(projectDoc.data.translateConfig.shareEnabled).not.toBeDefined();
});
});

describe('version 22', () => {
it('copies selected training and translation books to scripture ranges', async () => {
const env = new TestEnvironment(21);
const conn = env.server.connect();

await createDoc(conn, SF_PROJECTS_COLLECTION, 'project01', {
translateConfig: { draftConfig: { lastSelectedTrainingBooks: [1, 2, 3], lastSelectedTranslationBooks: [4, 5] } }
});
let projectDoc = await fetchDoc(conn, SF_PROJECTS_COLLECTION, 'project01');
expect(projectDoc.data.translateConfig.draftConfig.lastSelectedTrainingBooks).toEqual([1, 2, 3]);
expect(projectDoc.data.translateConfig.draftConfig.lastSelectedTranslationBooks).toEqual([4, 5]);

await env.server.migrateIfNecessary();

projectDoc = await fetchDoc(conn, SF_PROJECTS_COLLECTION, 'project01');
expect(projectDoc.data.translateConfig.draftConfig.lastSelectedTrainingBooks).toEqual([1, 2, 3]);
expect(projectDoc.data.translateConfig.draftConfig.lastSelectedTranslationBooks).toEqual([4, 5]);
expect(projectDoc.data.translateConfig.draftConfig.lastSelectedTrainingScriptureRange).toEqual('GEN;EXO;LEV');
expect(projectDoc.data.translateConfig.draftConfig.lastSelectedTranslationScriptureRange).toEqual('NUM;DEU');
});
});
});

class TestEnvironment {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Canon } from '@sillsdev/scripture';
import { Doc, Op } from 'sharedb/lib/client';
import { DocMigration, MigrationConstructor } from '../../common/migration';
import { DocMigration, MigrationConstructor, monotonicallyIncreasingMigrationList } from '../../common/migration';
import { Operation } from '../../common/models/project-rights';
import { submitMigrationOp } from '../../common/realtime-server';
import { NoteTag } from '../models/note-tag';
Expand Down Expand Up @@ -387,7 +388,39 @@ class SFProjectMigration21 extends DocMigration {
}
}

export const SF_PROJECT_MIGRATIONS: MigrationConstructor[] = [
class SFProjectMigration22 extends DocMigration {
static readonly VERSION = 22;

async migrateDoc(doc: Doc): Promise<void> {
const ops: Op[] = [];
if (doc.data.translateConfig.draftConfig.lastSelectedTrainingScriptureRange == null) {
const trainingRangeFromBooks: string[] = doc.data.translateConfig.draftConfig.lastSelectedTrainingBooks.map(
(b: number) => Canon.bookNumberToId(b)
);
if (trainingRangeFromBooks.length > 0) {
ops.push({
p: ['translateConfig', 'draftConfig', 'lastSelectedTrainingScriptureRange'],
oi: trainingRangeFromBooks.join(';')
});
}
}
if (doc.data.translateConfig.draftConfig.lastSelectedTranslationScriptureRange == null) {
const translationRangeFromBooks: string[] = doc.data.translateConfig.draftConfig.lastSelectedTranslationBooks.map(
(b: number) => Canon.bookNumberToId(b)
);
if (translationRangeFromBooks.length > 0) {
ops.push({
p: ['translateConfig', 'draftConfig', 'lastSelectedTranslationScriptureRange'],
oi: translationRangeFromBooks.join(';')
});
}
}

await submitMigrationOp(SFProjectMigration22.VERSION, doc, ops);
}
}

export const SF_PROJECT_MIGRATIONS: MigrationConstructor[] = monotonicallyIncreasingMigrationList([
SFProjectMigration1,
SFProjectMigration2,
SFProjectMigration3,
Expand All @@ -408,5 +441,6 @@ export const SF_PROJECT_MIGRATIONS: MigrationConstructor[] = [
SFProjectMigration18,
SFProjectMigration19,
SFProjectMigration20,
SFProjectMigration21
];
SFProjectMigration21,
SFProjectMigration22
]);
15 changes: 15 additions & 0 deletions src/RealtimeServer/scriptureforge/services/sf-project-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,21 @@ export class SFProjectService extends ProjectService<SFProject> {
lastSelectedTrainingScriptureRange: {
bsonType: 'string'
},
lastSelectedTrainingScriptureRanges: {
bsonType: 'array',
items: {
bsonType: 'object',
properties: {
projectId: {
bsonType: 'string'
},
scriptureRange: {
bsonType: 'string'
}
},
additionalProperties: false
}
},
lastSelectedTranslationBooks: {
bsonType: 'array',
items: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Doc, ObjectDeleteOp, ObjectInsertOp } from 'sharedb/lib/client';
import { DocMigration, MigrationConstructor } from '../../common/migration';
import { DocMigration, MigrationConstructor, monotonicallyIncreasingMigrationList } from '../../common/migration';
import { submitMigrationOp } from '../../common/realtime-server';

class SFProjectUserConfigMigration1 extends DocMigration {
Expand Down Expand Up @@ -85,12 +85,12 @@ class SFProjectUserConfigMigration7 extends DocMigration {
}
}

export const SF_PROJECT_USER_CONFIG_MIGRATIONS: MigrationConstructor[] = [
export const SF_PROJECT_USER_CONFIG_MIGRATIONS: MigrationConstructor[] = monotonicallyIncreasingMigrationList([
SFProjectUserConfigMigration1,
SFProjectUserConfigMigration2,
SFProjectUserConfigMigration3,
SFProjectUserConfigMigration4,
SFProjectUserConfigMigration5,
SFProjectUserConfigMigration6,
SFProjectUserConfigMigration7
];
]);
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { MigrationConstructor } from '../../common/migration';
import { MigrationConstructor, monotonicallyIncreasingMigrationList } from '../../common/migration';

export const TEXT_AUDIO_MIGRATIONS: MigrationConstructor[] = [];
export const TEXT_AUDIO_MIGRATIONS: MigrationConstructor[] = monotonicallyIncreasingMigrationList([]);
4 changes: 2 additions & 2 deletions src/RealtimeServer/scriptureforge/services/text-migrations.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { MigrationConstructor } from '../../common/migration';
import { MigrationConstructor, monotonicallyIncreasingMigrationList } from '../../common/migration';

export const TEXT_MIGRATIONS: MigrationConstructor[] = [];
export const TEXT_MIGRATIONS: MigrationConstructor[] = monotonicallyIncreasingMigrationList([]);
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { MigrationConstructor } from '../../common/migration';
import { MigrationConstructor, monotonicallyIncreasingMigrationList } from '../../common/migration';

export const TRAINING_DATA_MIGRATIONS: MigrationConstructor[] = [];
export const TRAINING_DATA_MIGRATIONS: MigrationConstructor[] = monotonicallyIncreasingMigrationList([]);
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ <h2 matSubheader>{{ t("filter_questions") }}</h2>
</div>
</div>
@if (projectDoc && totalVisibleQuestions() > 0) {
<div id="question-nav" [ngClass]="{ hide: (textHasFocus && isScreenSmall) || showScriptureAudioPlayer }">
<div id="question-nav" [ngClass]="{ hide: textboxIsShownMobile || userOpenedChapterAudio }">
@if (!isQuestionListPermanent) {
<button mat-button type="button" (click)="setQuestionsOverlayVisibility(true)">
{{ t("view_questions") }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,20 @@ export class CheckingComponent extends DataLoadingComponent implements OnInit, A
return this.projectDoc?.data?.checkingConfig.hideCommunityCheckingText ?? false;
}

get userOpenedChapterAudio(): boolean {
return this.showScriptureAudioPlayer && !this.hideChapterText;
}

get textboxIsShown(): boolean {
const isAnswering = this.answersPanel?.answerInput != null;
const isCommenting = this.answersPanel?.allComments?.find(c => c.inputComponent != null) != null;
return isAnswering || isCommenting;
}

get textboxIsShownMobile(): boolean {
return this.textboxIsShown && this.isScreenSmall;
}

get isRightToLeft(): boolean {
if (this.projectDoc?.data?.isRightToLeft != null) {
return this.projectDoc.data.isRightToLeft;
Expand Down Expand Up @@ -1082,12 +1096,6 @@ export class CheckingComponent extends DataLoadingComponent implements OnInit, A
}
}

get textHasFocus(): boolean {
const isAnswering = this.answersPanel?.answerInput != null;
const isCommenting = this.answersPanel?.allComments?.find(c => c.inputComponent != null) != null;
return isAnswering || isCommenting;
}

/**
* Retrieves the adjacent question based on the active question and the direction.
* Adjacent question might be outside the current filtered scope.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { TranslocoService } from '@ngneat/transloco';
import { Canon, VerseRef } from '@sillsdev/scripture';
import { Question } from 'realtime-server/lib/esm/scriptureforge/models/question';
import { fromVerseRef, toVerseRef } from 'realtime-server/lib/esm/scriptureforge/models/verse-ref-data';
import { lastValueFrom } from 'rxjs';
import { CsvService } from 'xforge-common/csv-service.service';
import { DialogService } from 'xforge-common/dialog.service';
import { ExternalUrlService } from 'xforge-common/external-url.service';
Expand Down Expand Up @@ -475,7 +476,7 @@ export class ImportQuestionsDialogComponent extends SubscriptionDisposable imple
ImportQuestionsConfirmationDialogComponent,
data
) as MatDialogRef<ImportQuestionsConfirmationDialogComponent, ImportQuestionsConfirmationDialogResult>;
(await dialogRef.afterClosed().toPromise())!.forEach(
(await lastValueFrom(dialogRef.afterClosed())).forEach(
(checked, index) => (changesToConfirm[index].checked = checked)
);
this.updateSelectAllCheckbox();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { MatDialogConfig, MatDialogRef } from '@angular/material/dialog';
import { TranslocoService } from '@ngneat/transloco';
import { Operation } from 'realtime-server/lib/esm/common/models/project-rights';
import { Question } from 'realtime-server/lib/esm/scriptureforge/models/question';
import { SFProjectDomain, SF_PROJECT_RIGHTS } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-rights';
import { SF_PROJECT_RIGHTS, SFProjectDomain } from 'realtime-server/lib/esm/scriptureforge/models/sf-project-rights';
import { fromVerseRef } from 'realtime-server/lib/esm/scriptureforge/models/verse-ref-data';
import { lastValueFrom } from 'rxjs';
import { DialogService } from 'xforge-common/dialog.service';
import { FileType } from 'xforge-common/models/file-offline-data';
import { NoticeService } from 'xforge-common/notice.service';
Expand Down Expand Up @@ -38,7 +39,7 @@ export class QuestionDialogService {
>;
// ENHANCE: Put the audio upload logic into QuestionDialogComponent so we can detect if the upload
// fails and notify the user without discarding the question. For example, see chapter-audio-dialog.component.ts.
const result: QuestionDialogResult | 'close' | undefined = await dialogRef.afterClosed().toPromise();
const result: QuestionDialogResult | 'close' | undefined = await lastValueFrom(dialogRef.afterClosed());
if (result == null || result === 'close') {
return questionDoc;
}
Expand Down
Loading

0 comments on commit 827b99b

Please sign in to comment.