diff --git a/lib/src/proto-to-firestore.ts b/lib/src/proto-to-firestore.ts index af2bcaa2b..805853fe5 100644 --- a/lib/src/proto-to-firestore.ts +++ b/lib/src/proto-to-firestore.ts @@ -23,7 +23,10 @@ import {DocumentData, DocumentFieldValue} from '@google-cloud/firestore'; * The map is keyed by message field numbers represented as strings, while field values are * converted to corresponding Firestore data types. */ -export function toDocumentData(message: object): DocumentData { +export function toDocumentData(message: object): DocumentData | DocumentData[] { + if (Array.isArray(message)) { + return message.map(messageEl => toDocumentData(messageEl)); + } if (Object.keys(message).length === 0) { return {}; } @@ -110,4 +113,4 @@ function toObjectValue(fieldType: string, value: any) { } else { return toDocumentData(value); } -} \ No newline at end of file +} diff --git a/lib/src/testing/firestore/firestore.ts b/lib/src/testing/firestore/firestore.ts index 66ad17fe1..9ebec663e 100644 --- a/lib/src/testing/firestore/firestore.ts +++ b/lib/src/testing/firestore/firestore.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Firestore } from "@google-cloud/firestore"; +import {Firestore} from '@google-cloud/firestore'; const MockFirebase = require('mock-cloud-firestore'); @@ -30,9 +30,8 @@ export function createMockFirestore(): Firestore { * in tests to work around lack of support in MockFirebase lib. */ export function TestGeoPoint(_latitude: number, _longitude: number) { - return { - _latitude, - _longitude, - }; - } - \ No newline at end of file + return { + _latitude, + _longitude, + }; +} diff --git a/lib/src/testing/firestore/index.ts b/lib/src/testing/firestore/index.ts index 2cd0ae374..adcdea944 100644 --- a/lib/src/testing/firestore/index.ts +++ b/lib/src/testing/firestore/index.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -export * from "./firestore"; -export * from "./event-context"; -export * from "./document-snapshot"; -export * from "./query"; -export * from "./setup"; +export * from './firestore'; +export * from './event-context'; +export * from './document-snapshot'; +export * from './query'; +export * from './setup'; diff --git a/lib/src/testing/reporter.js b/lib/src/testing/reporter.js index ce0e03ae5..fe23d086e 100644 --- a/lib/src/testing/reporter.js +++ b/lib/src/testing/reporter.js @@ -19,7 +19,7 @@ import {SpecReporter, StacktraceOption} from 'jasmine-spec-reporter'; // Show references to TypeScript code in stacktraces. require('source-map-support').install(); -jasmine.getEnv().clearReporters() +jasmine.getEnv().clearReporters(); jasmine.getEnv().addReporter( new SpecReporter({ spec: { @@ -27,4 +27,4 @@ jasmine.getEnv().addReporter( displayStacktrace: StacktraceOption.RAW, }, }) -) +); diff --git a/web/src/app/converters/proto-model-converter.ts b/web/src/app/converters/proto-model-converter.ts index 9e5be9b30..0a6d9f585 100644 --- a/web/src/app/converters/proto-model-converter.ts +++ b/web/src/app/converters/proto-model-converter.ts @@ -96,22 +96,23 @@ export function aclToDocument(acl: Map): DocumentData | Error { /** * Returns the proto representation of a Job model object. */ -export function jobToDocument(job: Job): DocumentData { +export function jobToDocument( + job: Job, + taskOverride: List | null = null +): DocumentData { return toDocumentData( new Pb.Job({ id: job.id, index: job.index, name: job.name, style: new Pb.Style({color: job.color}), - tasks: job.tasks?.toList().map(toTaskMessage).toArray(), + tasks: (taskOverride ?? job.tasks?.toList() ?? List()) + .map((task: Task) => toTaskMessage(task)) + .toArray(), }) ); } -export function tasksToDocument(tasks: List): DocumentData { - return toDocumentData(tasks.toList().map(toTaskMessage).toArray()); -} - /** * Returns a Protobuf message representing a partial Task model. */ @@ -192,7 +193,7 @@ function toTaskTypeMessage( case TaskType.CAPTURE_LOCATION: return { captureLocation: new Pb.Task.CaptureLocation({ - minAccuracyMeters: null, + minAccuracyMeters: 0, }), }; default: @@ -222,7 +223,7 @@ function toTaskConditionMessage( } /** - * Returns a Protobuf messager epresenting a Task model. + * Returns a Protobuf message representing a Task model. */ function toTaskMessage(task: Task): Pb.ITask { return new Pb.Task({ @@ -232,8 +233,8 @@ function toTaskMessage(task: Task): Pb.ITask { prompt: task.label, required: task.required, level: task.addLoiTask - ? Pb.Task.DataCollectionLevel.LOI_DATA - : Pb.Task.DataCollectionLevel.LOI_METADATA, + ? Pb.Task.DataCollectionLevel.LOI_METADATA + : Pb.Task.DataCollectionLevel.LOI_DATA, conditions: toTaskConditionMessage(task.condition), }); } diff --git a/web/src/app/pages/create-survey/create-survey.component.ts b/web/src/app/pages/create-survey/create-survey.component.ts index a3ebe880e..318974bc3 100644 --- a/web/src/app/pages/create-survey/create-survey.component.ts +++ b/web/src/app/pages/create-survey/create-survey.component.ts @@ -268,7 +268,7 @@ export class CreateSurveyComponent implements OnInit { await this.taskService.addOrUpdateTasks( survey.id, // Assume there is at least one job. - survey.jobs.first()!.id, + survey.jobs.first(), tasks! ); } diff --git a/web/src/app/services/data-store/data-store.service.ts b/web/src/app/services/data-store/data-store.service.ts index e239395a5..63d10f3d5 100644 --- a/web/src/app/services/data-store/data-store.service.ts +++ b/web/src/app/services/data-store/data-store.service.ts @@ -37,7 +37,6 @@ import { jobToDocument, newSurveyToDocument, partialSurveyToDocument, - tasksToDocument, } from 'app/converters/proto-model-converter'; import {Job} from 'app/models/job.model'; import {LocationOfInterest} from 'app/models/loi.model'; @@ -242,11 +241,15 @@ export class DataStoreService { ]); } - updateJob(surveyId: string, job: Job): Promise { + updateJob( + surveyId: string, + job: Job, + tasks: List | null = null + ): Promise { return this.db .collection(`${SURVEYS_COLLECTION_NAME}/${surveyId}/jobs`) .doc(job.id) - .set(jobToDocument(job)); + .set(jobToDocument(job, tasks)); } async deleteSurvey(survey: Survey) { @@ -530,18 +533,22 @@ export class DataStoreService { addOrUpdateTasks( surveyId: string, - jobId: string, + job: Job, tasks: List - ): Promise { - return this.db - .collection(SURVEYS_COLLECTION_NAME) - .doc(surveyId) - .update({ - [`jobs.${jobId}.tasks`]: { - ...FirebaseDataConverter.tasksToJS(this.convertTasksListToMap(tasks)), - ...tasksToDocument(tasks), - }, - }); + ): Promise<[void, void]> { + return Promise.all([ + this.db + .collection(SURVEYS_COLLECTION_NAME) + .doc(surveyId) + .update({ + [`jobs.${job.id}.tasks`]: { + ...FirebaseDataConverter.tasksToJS( + this.convertTasksListToMap(tasks) + ), + }, + }), + this.updateJob(surveyId, job, tasks), + ]); } /** diff --git a/web/src/app/services/task/task.service.ts b/web/src/app/services/task/task.service.ts index 32e649dd7..9587aa4fe 100644 --- a/web/src/app/services/task/task.service.ts +++ b/web/src/app/services/task/task.service.ts @@ -18,7 +18,7 @@ import {Injectable} from '@angular/core'; import {List, Map} from 'immutable'; import {Observable, switchMap} from 'rxjs'; -import {DataCollectionStrategy} from 'app/models/job.model'; +import {DataCollectionStrategy, Job} from 'app/models/job.model'; import {MultipleChoice} from 'app/models/task/multiple-choice.model'; import {Task, TaskType} from 'app/models/task/task.model'; import {DataStoreService} from 'app/services/data-store/data-store.service'; @@ -101,10 +101,10 @@ export class TaskService { addOrUpdateTasks( surveyId: string, - jobId: string, + job: Job, tasks: List - ): Promise { - return this.dataStoreService.addOrUpdateTasks(surveyId, jobId, tasks); + ): Promise<[void, void]> { + return this.dataStoreService.addOrUpdateTasks(surveyId, job, tasks); } /**