Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds "Map a new site" task type #2061

Draft
wants to merge 18 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
a098a85
Small style changes
rfontanarosa Oct 9, 2024
aa04d54
Added "Map a new site" task type option
rfontanarosa Oct 9, 2024
d758f62
changed allowedTypes into a controlled input
rfontanarosa Oct 9, 2024
e6f65be
fixed a possible bug
rfontanarosa Oct 9, 2024
2feaf88
added allowedTypes and Model <-> Pb conversions
rfontanarosa Oct 9, 2024
c88299f
added allowedTypes to form
rfontanarosa Oct 9, 2024
25505b9
Merge branch 'master' into rfontanarosa/1744/createedit-survey-allow-…
rfontanarosa Oct 9, 2024
0751e75
fixed duplicated line
rfontanarosa Oct 9, 2024
1d1d5fa
Merge branch 'rfontanarosa/1744/createedit-survey-allow-data-collecto…
rfontanarosa Oct 9, 2024
71cd77d
fixed Free-form data collection toggle compatibility with Map a new site
rfontanarosa Oct 9, 2024
5547524
Merge branch 'master' into rfontanarosa/1744/createedit-survey-allow-…
rfontanarosa Oct 11, 2024
7eefb0c
Merge branch 'master' into rfontanarosa/1744/createedit-survey-allow-…
rfontanarosa Oct 23, 2024
b206299
Merge branch 'master' into rfontanarosa/1744/createedit-survey-allow-…
gino-m Nov 4, 2024
6ab5dd1
Merge branch 'master' into rfontanarosa/1744/createedit-survey-allow-…
rfontanarosa Nov 6, 2024
fa28bac
Merge branch 'master' into rfontanarosa/1744/createedit-survey-allow-…
rfontanarosa Nov 8, 2024
2bf68d0
Merge branch 'master' into rfontanarosa/1744/createedit-survey-allow-…
rfontanarosa Nov 12, 2024
330f052
small cleanups and improvements
rfontanarosa Nov 29, 2024
0d3524a
introduced conditional allowed type control is task is map_a_site
rfontanarosa Nov 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
</div>

<div class="task-form">
<mat-form-field class="question" appearance="fill">
<mat-form-field>
<mat-label>{{ Tasks[taskGroup].placeholder }}</mat-label>

<input
Expand All @@ -90,7 +90,7 @@
</mat-error>
</mat-form-field>

<mat-form-field class="task-type" appearance="fill" *ngIf="taskGroup === TaskGroup.QUESTION">
<mat-form-field *ngIf="taskGroup === TaskGroup.QUESTION">
<mat-select
class="task-type-select"
[value]="taskTypeOption"
Expand All @@ -108,6 +108,19 @@
</mat-option>
</mat-select>
</mat-form-field>

<mat-form-field *ngIf="taskGroup === TaskGroup.MAP_A_NEW_SITE">
<mat-select
class="task-type-select"
formControlName="allowedTypes"
(openedChange)="onTaskFocus()"
multiple
>
<mat-option *ngFor="let taskAllowedType of TaskAllowedTypes" [value]="taskAllowedType.type">
<span>{{ taskAllowedType.label }}</span>
</mat-option>
</mat-select>
</mat-form-field>
</div>

<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
display: flex;
gap: 16px;

.question {
:first-child {
flex: 1;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ export interface TaskTypeOption {
cardinality?: Cardinality;
}

export interface TaskAllowedType {
label: string;
type: TaskType;
}

export const TaskTypeOptions: Array<TaskTypeOption> = [
{
icon: 'notes',
Expand Down Expand Up @@ -94,13 +99,25 @@ export const TaskTypeOptions: Array<TaskTypeOption> = [
},
];

export const TaskAllowedTypes: Array<TaskAllowedType> = [
{
label: 'Drop a pin',
type: TaskType.DROP_PIN,
},
{
label: 'Draw/Walk perimiter',
type: TaskType.DRAW_AREA,
},
];

export const Tasks: {
[key in TaskGroup]: {
icon: string;
label: string;
placeholder: string;
requiredMessage: string;
isGeometry?: boolean;
isAddLoiTask?: boolean;
};
} = {
[TaskGroup.QUESTION]: {
Expand Down Expand Up @@ -136,6 +153,13 @@ export const Tasks: {
requiredMessage: 'Instructions are required',
isGeometry: true,
},
[TaskGroup.MAP_A_NEW_SITE]: {
icon: 'add_location_alt',
label: 'Map a new site',
placeholder: 'Instructions',
requiredMessage: 'Instructions are required',
isAddLoiTask: true,
},
};

const GeometryTasks = List([TaskGroup.DROP_PIN, TaskGroup.DRAW_AREA]);
Expand Down Expand Up @@ -179,6 +203,8 @@ export class TaskFormComponent {

TaskTypeOptions = TaskTypeOptions;

TaskAllowedTypes = TaskAllowedTypes;

Tasks = Tasks;

GeometryTasks = GeometryTasks;
Expand Down Expand Up @@ -224,6 +250,10 @@ export class TaskFormComponent {
return this.formGroup.get('type')!;
}

get allowedTypesControl(): AbstractControl {
return this.formGroup.get('allowedTypes')!;
}

get labelControl(): AbstractControl {
return this.formGroup.get('label')!;
}
Expand Down
40 changes: 30 additions & 10 deletions web/src/app/components/tasks-editor/tasks-editor.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
FormGroup,
Validators,
} from '@angular/forms';
import {List} from 'immutable';
import {List, Map} from 'immutable';

import {
Cardinality,
Expand All @@ -47,9 +47,10 @@ export enum TaskGroup {
DROP_PIN = 3,
DRAW_AREA = 4,
CAPTURE_LOCATION = 5,
MAP_A_NEW_SITE = 6,
}

export const taskGroupToTypes = new Map([
export const taskGroupToTypes = Map([
[
TaskGroup.QUESTION,
List([
Expand All @@ -65,9 +66,10 @@ export const taskGroupToTypes = new Map([
[TaskGroup.DROP_PIN, List([TaskType.DROP_PIN])],
[TaskGroup.DRAW_AREA, List([TaskType.DRAW_AREA])],
[TaskGroup.CAPTURE_LOCATION, List([TaskType.CAPTURE_LOCATION])],
[TaskGroup.MAP_A_NEW_SITE, List([TaskType.MAP_A_NEW_SITE])],
]);

export const taskTypeToGroup = new Map([
export const taskTypeToGroup = Map([
[TaskType.TEXT, TaskGroup.QUESTION],
[TaskType.MULTIPLE_CHOICE, TaskGroup.QUESTION],
[TaskType.NUMBER, TaskGroup.QUESTION],
Expand All @@ -78,6 +80,7 @@ export const taskTypeToGroup = new Map([
[TaskType.DROP_PIN, TaskGroup.DROP_PIN],
[TaskType.DRAW_AREA, TaskGroup.DRAW_AREA],
[TaskType.CAPTURE_LOCATION, TaskGroup.CAPTURE_LOCATION],
[TaskType.MAP_A_NEW_SITE, TaskGroup.MAP_A_NEW_SITE],
]);

@Component({
Expand All @@ -96,7 +99,7 @@ export class TasksEditorComponent {
addableTaskGroups: Array<TaskGroup> = [
TaskGroup.QUESTION,
TaskGroup.PHOTO,
TaskGroup.CAPTURE_LOCATION,
TaskGroup.MAP_A_NEW_SITE,
];

constructor(
Expand Down Expand Up @@ -136,18 +139,25 @@ export class TasksEditorComponent {
}

onTaskAdd(group: TaskGroup) {
const types = taskGroupToTypes.get(group);
const type = taskGroupToTypes.get(group)?.first();

const formGroup = this.formBuilder.group({
id: this.dataStoreService.generateId(),
type: types?.first(),
type,
required: false,
label: ['', Validators.required],
cardinality: null,
options: this.formBuilder.array([]),
hasOtherOption: false,
addLoiTask: false,
});
addLoiTask: type === TaskType.MAP_A_NEW_SITE,
}) as FormGroup;

if (type === TaskType.MAP_A_NEW_SITE) {
formGroup.addControl(
'allowedTypes',
this.formBuilder.control([], Validators.required)
);
}

this.formArray.push(formGroup);
}
Expand Down Expand Up @@ -215,6 +225,13 @@ export class TasksEditorComponent {
addLoiTask: task.addLoiTask,
}) as FormGroup;

if (task.type === TaskType.MAP_A_NEW_SITE) {
control.addControl(
'allowedTypes',
this.formBuilder.control(task.allowedTypes, Validators.required)
);
}

if (task.condition) {
control.addControl(
'condition',
Expand All @@ -225,8 +242,10 @@ export class TasksEditorComponent {
this.formBuilder.group({
expressionType: expression.expressionType,
taskId: [expression.taskId, Validators.required],
optionIds:
[expression.optionIds?.toArray(), Validators.required] || [],
optionIds: [
expression.optionIds?.toArray() || [],
Validators.required,
],
})
) || []
),
Expand Down Expand Up @@ -270,6 +289,7 @@ export class TasksEditorComponent {
} as MultipleChoice)
: undefined,
addLoiTask: task.get('addLoiTask')?.value as boolean,
allowedTypes: task.get('allowedTypes')?.value as TaskType[],
condition: condition?.value
? ({
matchType: condition.get('matchType')?.value,
Expand Down
21 changes: 19 additions & 2 deletions web/src/app/converters/proto-model-converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ const PB_STATES = Map([
[SurveyState.READY, Pb.Survey.State.READY],
]);

const PB_METHODS = Map([
[TaskType.DROP_PIN, Pb.Task.DrawGeometry.Method.DROP_PIN],
[TaskType.DRAW_AREA, Pb.Task.DrawGeometry.Method.DRAW_AREA],
]);

/**
* Converts Role instance to its proto message type.
*/
Expand Down Expand Up @@ -127,7 +132,8 @@ export function jobToDocument(job: Job): DocumentData {
*/
function toTaskTypeMessage(
taskType: TaskType,
taskMultipleChoice?: MultipleChoice
taskMultipleChoice?: MultipleChoice,
taskAllowedTypes?: TaskType[]
): Pb.ITask {
switch (taskType) {
case TaskType.TEXT:
Expand Down Expand Up @@ -199,6 +205,17 @@ function toTaskTypeMessage(
allowedMethods: [Pb.Task.DrawGeometry.Method.DROP_PIN],
}),
};
case TaskType.MAP_A_NEW_SITE:
return {
drawGeometry: new Pb.Task.DrawGeometry({
allowedMethods:
taskAllowedTypes?.map(
allowedType =>
PB_METHODS.get(allowedType) ||
Pb.Task.DrawGeometry.Method.METHOD_UNSPECIFIED
) || [],
}),
};
case TaskType.CAPTURE_LOCATION:
return {
captureLocation: new Pb.Task.CaptureLocation({
Expand Down Expand Up @@ -236,7 +253,7 @@ function toTaskConditionMessage(
*/
function toTaskMessage(task: Task): Pb.ITask {
return new Pb.Task({
...toTaskTypeMessage(task.type, task.multipleChoice),
...toTaskTypeMessage(task.type, task.multipleChoice, task.allowedTypes),
id: task.id,
index: task.index,
prompt: task.label,
Expand Down
17 changes: 10 additions & 7 deletions web/src/app/converters/survey-data-converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import {Task, TaskType} from 'app/models/task/task.model';
import Pb = GroundProtos.ground.v1beta1;

const DateTimeQuestionType = Pb.Task.DateTimeQuestion.Type;
const DrawGeometryMethod = Pb.Task.DrawGeometry.Method;
const MultipleChoiceQuestionType = Pb.Task.MultipleChoiceQuestion.Type;
const DataCollectionLevel = Pb.Task.DataCollectionLevel;

Expand All @@ -58,6 +57,11 @@ const MODEL_STATES = Map([
[Pb.Survey.State.READY, SurveyState.READY],
]);

const METHOD_TO_TASK_TYPE = Map([
[Pb.Task.DrawGeometry.Method.DROP_PIN, TaskType.DROP_PIN],
[Pb.Task.DrawGeometry.Method.DRAW_AREA, TaskType.DRAW_AREA],
]);

function dataSharingTypeFromProto(
protoType?: Pb.Survey.DataSharingTerms.Type | null
) {
Expand Down Expand Up @@ -126,11 +130,7 @@ function taskPbToModelTaskType(pb: Pb.ITask): TaskType {
else throw new Error('Error converting to Task: invalid task data');
} else if (multipleChoiceQuestion) return TaskType.MULTIPLE_CHOICE;
else if (drawGeometry) {
if (drawGeometry.allowedMethods!.includes(DrawGeometryMethod.DRAW_AREA))
return TaskType.DRAW_AREA;
else if (drawGeometry.allowedMethods!.includes(DrawGeometryMethod.DROP_PIN))
return TaskType.DROP_PIN;
else throw new Error('Error converting to Task: invalid task data');
return TaskType.MAP_A_NEW_SITE;
} else if (captureLocation) return TaskType.CAPTURE_LOCATION;
else if (takePhoto) return TaskType.PHOTO;
else throw new Error('Error converting to Task: invalid task data');
Expand Down Expand Up @@ -184,7 +184,10 @@ function taskPbToModel(pb: Pb.ITask): Task {
pb.index!,
taskMultipleChoicePbToModel(pb),
taskConditionPbToModel(pb),
pb.level! === DataCollectionLevel.LOI_METADATA
pb.level! === DataCollectionLevel.LOI_METADATA,
(pb.drawGeometry?.allowedMethods
?.map(method => METHOD_TO_TASK_TYPE.get(method))
.filter(type => !!type) as TaskType[]) || []
);
}

Expand Down
4 changes: 3 additions & 1 deletion web/src/app/models/task/task.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export enum TaskType {
DRAW_AREA = 8,
DROP_PIN = 9,
CAPTURE_LOCATION = 10,
MAP_A_NEW_SITE = 11,
}

// TODO: add a subclass of Task for each task type.
Expand All @@ -69,7 +70,8 @@ export class Task extends Copiable {
* `null` or when it evaluates to `true`.
*/
readonly condition?: TaskCondition,
readonly addLoiTask?: boolean
readonly addLoiTask?: boolean,
readonly allowedTypes?: TaskType[]
) {
super();
}
Expand Down
5 changes: 3 additions & 2 deletions web/src/app/services/task/task.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,14 @@ export class TaskService {

const loiTask = new Task(
addLoiTaskId || this.dataStoreService.generateId(),
TaskType.DRAW_AREA,
TaskType.MAP_A_NEW_SITE,
'',
true,
-1,
undefined,
undefined,
true
true,
[TaskType.DRAW_AREA]
);

const newTasks = tasks.map((task: Task) =>
Expand Down