Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into feature/book-toggle…
Browse files Browse the repository at this point in the history
…-no-border
  • Loading branch information
Nateowami committed Aug 22, 2024
2 parents dad95d3 + 7e91fbc commit 216d4f3
Show file tree
Hide file tree
Showing 21 changed files with 790 additions and 274 deletions.
51 changes: 51 additions & 0 deletions scripts/extract-project.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
@ECHO OFF
REM Extract Scripture Forge Project Data
REM
REM Usage:
REM extract-project {server_name}:{server_port} {project_id}
REM
REM Example:
REM extract-project localhost:27017 66bb989d961308bb2652ac15
REM
REM Notes:
REM - User associations to projects will not be extracted. This must be done manually.
REM - Flat files need to be restored manually.
REM - To restore the project to a MongoDB server, run the following command:
REM mongorestore -h {server_name}:{server_port} {project_id}

SETLOCAL
IF %1.==. GOTO NO_SERVER
IF %2.==. GOTO NO_PROJECTID
SET SERVER=%1
SET PROJECTID=%2
SET OUTPUT_PATH=%PROJECTID%

ECHO Extracting %PROJECTID% from %SERVER%...
mongodump -h %SERVER% -d xforge -c sf_projects -o %OUTPUT_PATH% -q "{\"_id\":\"%PROJECTID%\"}"
mongodump -h %SERVER% -d xforge -c o_sf_projects -o %OUTPUT_PATH% -q "{\"d\":\"%PROJECTID%\"}"
mongodump -h %SERVER% -d xforge -c sf_project_secrets -o %OUTPUT_PATH% -q "{\"_id\":\"%PROJECTID%\"}"
mongodump -h %SERVER% -d xforge -c sf_project_user_configs -o %OUTPUT_PATH% -q "{\"_id\":{\"$regex\":\"^%PROJECTID%:\"}}"
mongodump -h %SERVER% -d xforge -c o_sf_project_user_configs -o %OUTPUT_PATH% -q "{\"d\":{\"$regex\":\"^%PROJECTID%:\"}}"
mongodump -h %SERVER% -d xforge -c texts -o %OUTPUT_PATH% -q "{\"_id\":{\"$regex\":\"^%PROJECTID%:\"}}"
mongodump -h %SERVER% -d xforge -c o_texts -o %OUTPUT_PATH% -q "{\"d\":{\"$regex\":\"^%PROJECTID%:\"}}"
mongodump -h %SERVER% -d xforge -c m_texts -o %OUTPUT_PATH% -q "{\"d\":{\"$regex\":\"^%PROJECTID%:\"}}"
mongodump -h %SERVER% -d xforge -c questions -o %OUTPUT_PATH% -q "{\"_id\":{\"$regex\":\"^%PROJECTID%:\"}}"
mongodump -h %SERVER% -d xforge -c o_questions -o %OUTPUT_PATH% -q "{\"d\":{\"$regex\":\"^%PROJECTID%:\"}}"
mongodump -h %SERVER% -d xforge -c note_threads -o %OUTPUT_PATH% -q "{\"_id\":{\"$regex\":\"^%PROJECTID%:\"}}"
mongodump -h %SERVER% -d xforge -c o_note_threads -o %OUTPUT_PATH% -q "{\"d\":{\"$regex\":\"^%PROJECTID%:\"}}"
mongodump -h %SERVER% -d xforge -c text_audio -o %OUTPUT_PATH% -q "{\"_id\":{\"$regex\":\"^%PROJECTID%:\"}}"
mongodump -h %SERVER% -d xforge -c o_text_audio -o %OUTPUT_PATH% -q "{\"d\":{\"$regex\":\"^%PROJECTID%:\"}}"
mongodump -h %SERVER% -d xforge -c biblical_terms -o %OUTPUT_PATH% -q "{\"_id\":{\"$regex\":\"^%PROJECTID%:\"}}"
mongodump -h %SERVER% -d xforge -c o_biblical_terms -o %OUTPUT_PATH% -q "{\"d\":{\"$regex\":\"^%PROJECTID%:\"}}"
mongodump -h %SERVER% -d xforge -c training_data -o %OUTPUT_PATH% -q "{\"_id\":{\"$regex\":\"^%PROJECTID%:\"}}"
mongodump -h %SERVER% -d xforge -c o_training_data -o %OUTPUT_PATH% -q "{\"d\":{\"$regex\":\"^%PROJECTID%:\"}}"
GOTO END

:NO_SERVER
ECHO Please specify the server and port as the first argument
GOTO END

:NO_PROJECTID
ECHO Please specify a project id as the second argument
GOTO END
:END
48 changes: 48 additions & 0 deletions scripts/extract-project.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/bash
# Extract Scripture Forge Project Data
#
# Usage:
# extract-project.sh {server_name}:{server_port} {project_id}
#
# Example:
# ./extract-project.sh localhost:27017 66bb989d961308bb2652ac15
#
# Notes:
# - User associations to projects will not be extracted. This must be done manually.
# - Flat files need to be restored manually.
# - To restore the project to a MongoDB server, run the following command:
# mongorestore -h {server_name}:{server_port} {project_id}

if [ -z "$1" ]; then
echo "Please specify the server and port as the first argument"
exit 1
fi

if [ -z "$2" ]; then
echo "Please specify a project id as the second argument"
exit 1
fi

SERVER=$1
PROJECTID=$2
OUTPUT_PATH=$PROJECTID

echo "Extracting $PROJECTID from $SERVER..."
mongodump -h "$SERVER" -d xforge -c sf_projects -o "$OUTPUT_PATH" -q "{\"_id\":\"$PROJECTID\"}"
mongodump -h "$SERVER" -d xforge -c o_sf_projects -o "$OUTPUT_PATH" -q "{\"d\":\"$PROJECTID\"}"
mongodump -h "$SERVER" -d xforge -c sf_project_secrets -o "$OUTPUT_PATH" -q "{\"_id\":\"$PROJECTID\"}"
mongodump -h "$SERVER" -d xforge -c sf_project_user_configs -o "$OUTPUT_PATH" -q "{\"_id\":{\"\$regex\":\"^$PROJECTID:\"}}"
mongodump -h "$SERVER" -d xforge -c o_sf_project_user_configs -o "$OUTPUT_PATH" -q "{\"d\":{\"\$regex\":\"^$PROJECTID:\"}}"
mongodump -h "$SERVER" -d xforge -c texts -o "$OUTPUT_PATH" -q "{\"_id\":{\"\$regex\":\"^$PROJECTID:\"}}"
mongodump -h "$SERVER" -d xforge -c o_texts -o "$OUTPUT_PATH" -q "{\"d\":{\"\$regex\":\"^$PROJECTID:\"}}"
mongodump -h "$SERVER" -d xforge -c m_texts -o "$OUTPUT_PATH" -q "{\"d\":{\"\$regex\":\"^$PROJECTID:\"}}"
mongodump -h "$SERVER" -d xforge -c questions -o "$OUTPUT_PATH" -q "{\"_id\":{\"\$regex\":\"^$PROJECTID:\"}}"
mongodump -h "$SERVER" -d xforge -c o_questions -o "$OUTPUT_PATH" -q "{\"d\":{\"\$regex\":\"^$PROJECTID:\"}}"
mongodump -h "$SERVER" -d xforge -c note_threads -o "$OUTPUT_PATH" -q "{\"_id\":{\"\$regex\":\"^$PROJECTID:\"}}"
mongodump -h "$SERVER" -d xforge -c o_note_threads -o "$OUTPUT_PATH" -q "{\"d\":{\"\$regex\":\"^$PROJECTID:\"}}"
mongodump -h "$SERVER" -d xforge -c text_audio -o "$OUTPUT_PATH" -q "{\"_id\":{\"\$regex\":\"^$PROJECTID:\"}}"
mongodump -h "$SERVER" -d xforge -c o_text_audio -o "$OUTPUT_PATH" -q "{\"d\":{\"\$regex\":\"^$PROJECTID:\"}}"
mongodump -h "$SERVER" -d xforge -c biblical_terms -o "$OUTPUT_PATH" -q "{\"_id\":{\"\$regex\":\"^$PROJECTID:\"}}"
mongodump -h "$SERVER" -d xforge -c o_biblical_terms -o "$OUTPUT_PATH" -q "{\"d\":{\"\$regex\":\"^$PROJECTID:\"}}"
mongodump -h "$SERVER" -d xforge -c training_data -o "$OUTPUT_PATH" -q "{\"_id\":{\"\$regex\":\"^$PROJECTID:\"}}"
mongodump -h "$SERVER" -d xforge -c o_training_data -o "$OUTPUT_PATH" -q "{\"d\":{\"\$regex\":\"^$PROJECTID:\"}}"
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,17 @@ <h2>Downloads</h2>
<tr mat-row *matRowDef="let myRowData; columns: columnsToDisplay"></tr>
</table>
</div>

<h2>Last Draft settings</h2>
<h3>Training books</h3>
{{ trainingBooks.join(", ") || "None" }}
<h3>Training data files</h3>
{{ trainingFiles.join(", ") || "None" }}
<h3>Translation books</h3>
{{ translationBooks.join(", ") || "None" }}

<h2>Raw draft config</h2>
<pre class="raw-draft-config">
@for (key of keys(draftConfig ?? {}); track key) {{{ key }}: <strong>{{ stringify(draftConfig![key]) }}</strong>
}
</pre>
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@
column-gap: 10px;
}
}

.raw-draft-config {
font-family: monospace;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CommonModule } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { Canon } from '@sillsdev/scripture';
import { saveAs } from 'file-saver';
import { SFProjectProfile } from 'realtime-server/lib/esm/scriptureforge/models/sf-project';
import { catchError, lastValueFrom, of, tap, throwError } from 'rxjs';
Expand Down Expand Up @@ -37,6 +38,12 @@ export class ServalProjectComponent extends DataLoadingComponent implements OnIn
columnsToDisplay = ['category', 'name', 'id'];
rows: Row[] = [];

trainingBooks: string[] = [];
trainingFiles: string[] = [];
translationBooks: string[] = [];

draftConfig: Object | undefined;

constructor(
private readonly activatedProjectService: ActivatedProjectService,
noticeService: NoticeService,
Expand Down Expand Up @@ -119,6 +126,17 @@ export class ServalProjectComponent extends DataLoadingComponent implements OnIn

// We have to set the rows this way to trigger the update
this.rows = rows;

// Setup the books
this.trainingBooks = project.translateConfig.draftConfig.lastSelectedTrainingBooks.map(bookNum =>
Canon.bookNumberToEnglishName(bookNum)
);
this.trainingFiles = project.translateConfig.draftConfig.lastSelectedTrainingDataFiles;
this.translationBooks = project.translateConfig.draftConfig.lastSelectedTranslationBooks.map(bookNum =>
Canon.bookNumberToEnglishName(bookNum)
);

this.draftConfig = project.translateConfig.draftConfig;
})
)
);
Expand Down Expand Up @@ -162,4 +180,19 @@ export class ServalProjectComponent extends DataLoadingComponent implements OnIn
await this.servalAdministrationService.onlineRetrievePreTranslationStatus(this.activatedProjectService.projectId!);
await this.noticeService.show('Webhook job started.');
}

keys(obj: Object): string[] {
return Object.keys(obj);
}

stringify(value: any): string {
if (Array.isArray(value)) {
return this.arrayToString(value);
}
return JSON.stringify(value, (_key, value) => (Array.isArray(value) ? this.arrayToString(value) : value), 2);
}

arrayToString(value: any): string {
return '[' + value.join(', ') + ']';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
[selected]="book.selected"
(selected)="onChipListChange(book)"
[disabled]="readonly"
[progress]="book.progressPercentage / 100"
(change)="onChipListChange(book)"
></app-toggle-book>
}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
@use 'src/variables';

.book-multi-select {
.mat-mdc-standard-chip {
position: relative;
display: inline-block;
overflow: hidden;
border-radius: 4px;
}

.mat-mdc-standard-chip {
&.mat-mdc-chip-selected,
&.mat-mdc-chip-highlighted {
--mdc-chip-elevated-selected-container-color: #4a79c9;
}
}

.border-fill {
position: absolute;
bottom: 0;
left: 0;
height: 3px;
background: black;
}
}

.bulk-select {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatChipsModule } from '@angular/material/chips';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
import { mock, when } from 'ts-mockito';
import { configureTestingModule, TestTranslocoModule } from 'xforge-common/test-utils';
import { BookMultiSelectComponent, BookOption } from './book-multi-select.component';
import { ProgressService, TextProgress } from '../progress-service/progress-service';
import { BookMultiSelectComponent } from './book-multi-select.component';

const mockedActivatedRoute = mock(ActivatedRoute);
const mockedProgressService = mock(ProgressService);

describe('BookMultiSelectComponent', () => {
let component: BookMultiSelectComponent;
Expand All @@ -11,61 +18,73 @@ describe('BookMultiSelectComponent', () => {
let mockSelectedBooks: number[];

configureTestingModule(() => ({
imports: [MatChipsModule, TestTranslocoModule]
imports: [MatChipsModule, TestTranslocoModule],
providers: [
{ provide: ActivatedRoute, useMock: mockedActivatedRoute },
{ provide: ProgressService, useMock: mockedProgressService }
]
}));

beforeEach(() => {
mockBooks = [1, 2, 3, 42, 70];
mockSelectedBooks = [1, 3];
when(mockedActivatedRoute.params).thenReturn(of({ projectId: 'project01' }));
when(mockedProgressService.isLoaded$).thenReturn(of(true));
when(mockedProgressService.texts).thenReturn([
{ text: { bookNum: 1 }, percentage: 0 } as TextProgress,
{ text: { bookNum: 2 }, percentage: 20 } as TextProgress,
{ text: { bookNum: 3 }, percentage: 40 } as TextProgress,
{ text: { bookNum: 42 }, percentage: 70 } as TextProgress,
{ text: { bookNum: 70 }, percentage: 100 } as TextProgress
]);

fixture = TestBed.createComponent(BookMultiSelectComponent);
component = fixture.componentInstance;
component.availableBooks = mockBooks;
component.selectedBooks = mockSelectedBooks;
fixture.detectChanges();
});

it('should initialize book options on ngOnChanges', () => {
const mockBookOptions: BookOption[] = [
{ bookNum: 1, bookId: 'GEN', selected: true },
{ bookNum: 2, bookId: 'EXO', selected: false },
{ bookNum: 3, bookId: 'LEV', selected: true },
{ bookNum: 42, bookId: 'LUK', selected: false },
{ bookNum: 70, bookId: 'WIS', selected: false }
];

component.ngOnChanges();
it('should initialize book options on ngOnChanges', async () => {
await component.ngOnChanges();

expect(component.bookOptions).toEqual(mockBookOptions);
expect(component.bookOptions).toEqual([
{ bookNum: 1, bookId: 'GEN', selected: true, progressPercentage: 0 },
{ bookNum: 2, bookId: 'EXO', selected: false, progressPercentage: 20 },
{ bookNum: 3, bookId: 'LEV', selected: true, progressPercentage: 40 },
{ bookNum: 42, bookId: 'LUK', selected: false, progressPercentage: 70 },
{ bookNum: 70, bookId: 'WIS', selected: false, progressPercentage: 100 }
]);
});

it('can select all OT books', () => {
it('can select all OT books', async () => {
expect(component.selectedBooks.length).toEqual(2);

component.select('OT');
await component.select('OT');

expect(component.selectedBooks.length).toEqual(3);
});

it('can select all NT books', () => {
it('can select all NT books', async () => {
expect(component.selectedBooks.length).toEqual(2);

component.select('NT');
await component.select('NT');

expect(component.selectedBooks.length).toEqual(3);
});

it('can select all DC books', () => {
it('can select all DC books', async () => {
expect(component.selectedBooks.length).toEqual(2);

component.select('DC');
await component.select('DC');

expect(component.selectedBooks.length).toEqual(3);
});

it('can reset book selection', () => {
it('can reset book selection', async () => {
expect(component.selectedBooks.length).toEqual(2);

component.clear();
await component.clear();

expect(component.selectedBooks.length).toEqual(0);
});
Expand Down
Loading

0 comments on commit 216d4f3

Please sign in to comment.