Skip to content

Commit 2206c63

Browse files
committed
Merge branch 'gino-m/1779/export-csv-from-pb-data' of https://github.com/google/ground-platform into gino-m/1779/export-csv-from-pb-data
2 parents 3537692 + ca8e429 commit 2206c63

File tree

9 files changed

+71
-49
lines changed

9 files changed

+71
-49
lines changed

web/src/app/converters/firebase-data-converter.ts

+4-6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {AuditInfo} from 'app/models/audit-info.model';
2121
import {MultiPolygon} from 'app/models/geometry/multi-polygon';
2222
import {DataCollectionStrategy, Job} from 'app/models/job.model';
2323
import {Role} from 'app/models/role.model';
24+
import {MultipleSelection} from 'app/models/submission/multiple-selection';
2425
import {Result} from 'app/models/submission/result.model';
2526
import {
2627
Submission,
@@ -403,14 +404,11 @@ export class FirebaseDataConverter {
403404
}
404405

405406
private static resultToJS(result: Result): {} {
406-
if (typeof result.value === 'string') {
407+
if (typeof result.value === 'string' || typeof result.value === 'number') {
407408
return result.value;
408409
}
409-
if (typeof result.value === 'number') {
410-
return result.value;
411-
}
412-
if (result.value instanceof List) {
413-
return (result.value as List<Option>).map(option => option.id).toArray();
410+
if (result.value instanceof MultipleSelection) {
411+
return result.value.values.map(option => option.id).toArray();
414412
}
415413
if (result.value instanceof Date) {
416414
return Timestamp.fromDate(result.value);

web/src/app/converters/submission-data-converter.ts

+19-29
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {MultiPolygon} from 'app/models/geometry/multi-polygon';
2525
import {Point} from 'app/models/geometry/point';
2626
import {Polygon} from 'app/models/geometry/polygon';
2727
import {Job} from 'app/models/job.model';
28+
import {MultipleSelection} from 'app/models/submission/multiple-selection';
2829
import {Result} from 'app/models/submission/result.model';
2930
import {
3031
Submission,
@@ -122,22 +123,12 @@ function taskDataPbToModel(pb: Pb.ITaskData[], job: Job): SubmissionData {
122123
else if (dateTimeResponse)
123124
value = new Date(timestampToInt(dateTimeResponse.dateTime));
124125
else if (multipleChoiceResponses) {
125-
value =
126+
value = new MultipleSelection(
126127
task.multipleChoice?.options.filter(({id: optionId}) =>
127128
multipleChoiceResponses!.selectedOptionIds?.includes(optionId)
128-
) || List([]);
129-
130-
if (
131-
task.multipleChoice?.hasOtherOption &&
132-
multipleChoiceResponses!.otherText
133-
) {
134-
value = value.push(
135-
createOtherOption(
136-
multipleChoiceResponses!.otherText,
137-
task.multipleChoice?.options.size
138-
)
139-
);
140-
}
129+
) || List([]),
130+
multipleChoiceResponses.otherText
131+
);
141132
} else if (drawGeometryResult)
142133
value = geometryPbToModel(drawGeometryResult.geometry!) as Polygon;
143134
else if (captureLocationResult)
@@ -266,22 +257,21 @@ export class LegacySubmissionDataConverter {
266257
task?: Task
267258
): Result | Error {
268259
try {
269-
if (typeof resultValue === 'number') {
270-
return new Result(resultValue as number);
271-
} else if (typeof resultValue === 'string') {
272-
return new Result(resultValue as string);
273-
} else if (resultValue instanceof Array) {
260+
if (typeof resultValue === 'number' || typeof resultValue === 'string') {
261+
return new Result(resultValue);
262+
} else if (Array.isArray(resultValue)) {
274263
return new Result(
275-
List(
276-
resultValue.map(optionId => {
277-
if (optionId.startsWith('['))
278-
return createOtherOption(optionId, resultValue.length);
279-
else
280-
return (
281-
task?.getMultipleChoiceOption(optionId) ||
282-
new Option(optionId, optionId, optionId, -1)
283-
);
284-
})
264+
new MultipleSelection(
265+
List(
266+
resultValue
267+
.filter(optionId => !optionId.startsWith('['))
268+
.map(
269+
optionId =>
270+
task?.getMultipleChoiceOption(optionId) ||
271+
new Option(optionId, optionId, optionId, -1)
272+
)
273+
),
274+
resultValue.find(optionId => optionId.startsWith('['))
285275
)
286276
);
287277
} else if (resultValue instanceof Timestamp) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Copyright 2024 The Ground Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the 'License');
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an 'AS IS' BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import {List} from 'immutable';
18+
19+
import {Option} from 'app/models/task/option.model';
20+
21+
export class MultipleSelection {
22+
constructor(
23+
readonly values: List<Option>,
24+
readonly otherValue?: string | null
25+
) {}
26+
}

web/src/app/models/submission/result.model.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,9 @@
1414
* limitations under the License.
1515
*/
1616

17-
import {List} from 'immutable';
18-
1917
import {MultiPolygon} from 'app/models/geometry/multi-polygon';
20-
import {Option} from 'app/models/task/option.model';
2118

19+
import {MultipleSelection} from './multiple-selection';
2220
import {Point} from '../geometry/point';
2321
import {Polygon} from '../geometry/polygon';
2422

@@ -27,7 +25,7 @@ export class Result {
2725
readonly value:
2826
| number
2927
| string
30-
| List<Option>
28+
| MultipleSelection
3129
| Date
3230
| Point
3331
| Polygon

web/src/app/pages/main-page-container/main-page/secondary-side-panel/submission-panel/submission-panel.component.html

+5-1
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,13 @@
4141
<div *ngIf="getTaskSubmissionResult(task) !== undefined">
4242
<!-- Multiple choice task types -->
4343
<div *ngIf="task.type === taskType.MULTIPLE_CHOICE" class="submission-response-multiple-choice">
44-
<mat-checkbox disabled="true" checked="true" *ngFor="let option of getTaskMultipleChoiceSelections(task)">
44+
<mat-checkbox disabled="true" checked="true" *ngFor="let option of getTaskMultipleChoiceSelections(task).values">
4545
{{option.label}}
4646
</mat-checkbox>
47+
48+
<mat-checkbox disabled="true" checked="true" *ngIf="getTaskMultipleChoiceSelections(task).otherOption">
49+
Other: {{option.label}}
50+
</mat-checkbox>
4751
</div>
4852
<!-- Photo task types -->
4953
<div *ngIf="task.type === taskType.PHOTO">

web/src/app/pages/main-page-container/main-page/secondary-side-panel/submission-panel/submission-panel.component.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {List} from 'immutable';
2020
import {Subscription, firstValueFrom} from 'rxjs';
2121

2222
import {Point} from 'app/models/geometry/point';
23+
import {MultipleSelection} from 'app/models/submission/multiple-selection';
2324
import {Result} from 'app/models/submission/result.model';
2425
import {Submission} from 'app/models/submission/submission.model';
2526
import {Option} from 'app/models/task/option.model';
@@ -97,8 +98,8 @@ export class SubmissionPanelComponent implements OnInit, OnDestroy {
9798
return this.submission?.data.get(taskId);
9899
}
99100

100-
getTaskMultipleChoiceSelections(task: Task): List<Option> {
101-
return this.getTaskSubmissionResult(task)!.value as List<Option>;
101+
getTaskMultipleChoiceSelections(task: Task): MultipleSelection {
102+
return this.getTaskSubmissionResult(task)!.value as MultipleSelection;
102103
}
103104

104105
getCaptureLocationCoord(task: Task): string {

web/src/app/pages/main-page-container/main-page/side-panel/loi-panel/loi-panel.component.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {Observable, Subscription, combineLatest} from 'rxjs';
2020
import {switchMap} from 'rxjs/operators';
2121

2222
import {Job} from 'app/models/job.model';
23+
import {MultipleSelection} from 'app/models/submission/multiple-selection';
2324
import {Submission} from 'app/models/submission/submission.model';
2425
import {Option} from 'app/models/task/option.model';
2526
import {Task, TaskType} from 'app/models/task/task.model';
@@ -121,7 +122,7 @@ export class LocationOfInterestPanelComponent implements OnInit, OnDestroy {
121122
getOptions(task: Task, submission: Submission): List<Option> {
122123
const result = submission.data?.get(task.id);
123124
if (result && result instanceof List) {
124-
return result.value as List<Option>;
125+
return (result.value as MultipleSelection).values;
125126
} else {
126127
return List.of();
127128
}

web/src/app/pages/main-page-container/main-page/side-panel/submission-form/submission-form.component.spec.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {Coordinate} from 'app/models/geometry/coordinate';
3636
import {Point} from 'app/models/geometry/point';
3737
import {Job} from 'app/models/job.model';
3838
import {LocationOfInterest} from 'app/models/loi.model';
39+
import {MultipleSelection} from 'app/models/submission/multiple-selection';
3940
import {Result} from 'app/models/submission/result.model';
4041
import {Submission} from 'app/models/submission/submission.model';
4142
import {Survey} from 'app/models/survey.model';
@@ -128,7 +129,7 @@ class MockModel {
128129
new AuditInfo(MockModel.user001, new Date(), new Date()),
129130
Map({
130131
task001: new Result('result'),
131-
task003: new Result(List([MockModel.option001])),
132+
task003: new Result(new MultipleSelection(List([MockModel.option001]))),
132133
})
133134
);
134135
}

web/src/app/pages/main-page-container/main-page/side-panel/submission-form/submission-form.component.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {first, map, switchMap} from 'rxjs/operators';
2323
import {JobListItemActionsType} from 'app/components/job-list-item/job-list-item.component';
2424
import {AuditInfo} from 'app/models/audit-info.model';
2525
import {Job} from 'app/models/job.model';
26+
import {MultipleSelection} from 'app/models/submission/multiple-selection';
2627
import {Result} from 'app/models/submission/result.model';
2728
import {
2829
Submission,
@@ -267,7 +268,7 @@ export class SubmissionFormComponent {
267268
result?: Result
268269
): void {
269270
const selectedOptionId = (
270-
(result?.value as List<Option>)?.first() as Option
271+
(result?.value as MultipleSelection)?.values.first() as Option
271272
)?.id;
272273
group[task.id] = task.required
273274
? new FormControl(selectedOptionId, Validators.required)
@@ -278,23 +279,25 @@ export class SubmissionFormComponent {
278279
const selectedOption: Option = task.getMultipleChoiceOption(
279280
this.submissionForm?.value[task.id]
280281
);
281-
return new Result(List([selectedOption]));
282+
return new Result(new MultipleSelection(List([selectedOption])));
282283
}
283284

284285
private addControlsForSelectMultipleTask(
285286
group: {[taskId: string]: FormControl},
286287
task: Task,
287288
result?: Result
288289
): void {
289-
const selectedOptions = result?.value as List<Option>;
290+
const {values: selectedOptions} = result?.value as MultipleSelection;
290291
for (const option of task.multipleChoice!.options) {
291292
group[option.id] = new FormControl(selectedOptions?.contains(option));
292293
}
293294
}
294295

295296
private extractDataForSelectMultipleTask(task: Task): Result {
296-
const selectedOptions: List<Option> = task.multipleChoice!.options!.filter(
297-
(option: Option) => this.submissionForm?.value[option.id]
297+
const selectedOptions: MultipleSelection = new MultipleSelection(
298+
task.multipleChoice!.options!.filter(
299+
(option: Option) => this.submissionForm?.value[option.id]
300+
)
298301
);
299302
return new Result(selectedOptions);
300303
}

0 commit comments

Comments
 (0)