From bb0389d52a2ba3689906376b3930c06c75fdf0c5 Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Wed, 29 Jun 2022 09:47:06 -0700 Subject: [PATCH 01/25] Added date selector for street imagery - Date picker added to imagery page in settings - Database migrated with new column for the date --- backend/models/dtos/project_dto.py | 2 ++ backend/models/postgis/project.py | 5 +++ frontend/src/assets/styles/_extra.scss | 4 +++ .../src/components/projectEdit/imageryForm.js | 24 +++++++++++++- migrations/versions/b805df721885_.py | 32 +++++++++++++++++++ requirements.txt | 2 +- 6 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 migrations/versions/b805df721885_.py diff --git a/backend/models/dtos/project_dto.py b/backend/models/dtos/project_dto.py index ca22f5ddd..2d2219388 100644 --- a/backend/models/dtos/project_dto.py +++ b/backend/models/dtos/project_dto.py @@ -199,6 +199,7 @@ class ProjectDTO(Model): enforce_random_task_selection = BooleanType( required=False, default=False, serialized_name="enforceRandomTaskSelection" ) + earliestStreetImagery = UTCDateTimeType(serialized_name="earliestStreetImagery") private = BooleanType(required=True) changeset_comment = StringType(serialized_name="changesetComment") @@ -461,6 +462,7 @@ class ProjectSummary(Model): author = StringType() created = UTCDateTimeType() due_date = UTCDateTimeType(serialized_name="dueDate") + earliestStreetImagery = UTCDateTimeType(serialized_name="earliestStreetImagery") last_updated = UTCDateTimeType(serialized_name="lastUpdated") priority = StringType(serialized_name="projectPriority") campaigns = ListType(ModelType(CampaignDTO), default=[]) diff --git a/backend/models/postgis/project.py b/backend/models/postgis/project.py index 9d77b8d2e..9d9f2c4e5 100644 --- a/backend/models/postgis/project.py +++ b/backend/models/postgis/project.py @@ -146,6 +146,7 @@ class Project(db.Model): db.String ) # Optional custom filter id for filtering on OSMCha due_date = db.Column(db.DateTime) + earliestStreetImagery = db.Column(db.DateTime) imagery = db.Column(db.String) josm_preset = db.Column(db.String) id_presets = db.Column(ARRAY(db.String)) @@ -375,6 +376,7 @@ def update(self, project_dto: ProjectDTO): self.mapper_level = MappingLevel[project_dto.mapper_level.upper()].value self.changeset_comment = project_dto.changeset_comment self.due_date = project_dto.due_date + self.earliestStreetImagery = project_dto.earliestStreetImagery self.imagery = project_dto.imagery self.josm_preset = project_dto.josm_preset self.id_presets = project_dto.id_presets @@ -832,6 +834,8 @@ def get_project_summary(self, preferred_locale) -> ProjectSummary: summary.country_tag = self.country summary.changeset_comment = self.changeset_comment summary.due_date = self.due_date + summary.earliestStreetImagery = self.earliestStreetImagery + summary.created = self.created summary.last_updated = self.last_updated summary.osmcha_filter_id = self.osmcha_filter_id @@ -1006,6 +1010,7 @@ def _get_project_and_base_dto(self): base_dto.changeset_comment = self.changeset_comment base_dto.osmcha_filter_id = self.osmcha_filter_id base_dto.due_date = self.due_date + base_dto.earliestStreetImagery = self.earliestStreetImagery base_dto.imagery = self.imagery base_dto.josm_preset = self.josm_preset base_dto.id_presets = self.id_presets diff --git a/frontend/src/assets/styles/_extra.scss b/frontend/src/assets/styles/_extra.scss index 84d938e97..6c591ee98 100644 --- a/frontend/src/assets/styles/_extra.scss +++ b/frontend/src/assets/styles/_extra.scss @@ -330,3 +330,7 @@ div.messageBodyLinks { vertical-align: middle; } } + +div.react-datepicker-popper { + z-index: 5; +} \ No newline at end of file diff --git a/frontend/src/components/projectEdit/imageryForm.js b/frontend/src/components/projectEdit/imageryForm.js index 1bd3d34a9..fae7373d9 100644 --- a/frontend/src/components/projectEdit/imageryForm.js +++ b/frontend/src/components/projectEdit/imageryForm.js @@ -1,7 +1,7 @@ import React, { useContext, useState, useLayoutEffect } from 'react'; import Select from 'react-select'; import { FormattedMessage } from 'react-intl'; - +import DatePicker from 'react-datepicker'; import messages from './messages'; import { StateContext, styleClasses } from '../../views/projectEdit'; import { fetchLocalJSONAPI } from '../../network/genericJSONRequest'; @@ -32,7 +32,9 @@ export const ImageryForm = () => { + +
+ +
+ + + setProjectInfo({ + ...projectInfo, + earliestStreetImagery: date, + }) + } + dateFormat="dd/MM/yyyy" + className={styleClasses.inputClass} + showYearDropdown + scrollableYearDropdown + /> +
+ ); }; diff --git a/migrations/versions/b805df721885_.py b/migrations/versions/b805df721885_.py new file mode 100644 index 000000000..465ae1eb2 --- /dev/null +++ b/migrations/versions/b805df721885_.py @@ -0,0 +1,32 @@ +"""empty message + +Revision ID: b805df721885 +Revises: 8a6419f289aa +Create Date: 2022-06-23 12:18:09.218580 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'b805df721885' +down_revision = '8a6419f289aa' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('projects', sa.Column('earliestStreetImagery', sa.DateTime(), nullable=True)) + op.drop_index('idx_task_validation_mapper_status_composite', table_name='task_invalidation_history') + op.create_index('idx_task_validation_mapper_status_composite', 'task_invalidation_history', ['invalidator_id', 'is_closed'], unique=False) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index('idx_task_validation_mapper_status_composite', table_name='task_invalidation_history') + op.create_index('idx_task_validation_mapper_status_composite', 'task_invalidation_history', ['mapper_id', 'is_closed'], unique=False) + op.drop_column('projects', 'earliestStreetImagery') + # ### end Alembic commands ### diff --git a/requirements.txt b/requirements.txt index 05f2cadcc..0bad00516 100644 --- a/requirements.txt +++ b/requirements.txt @@ -37,7 +37,7 @@ mccabe==0.6.1 newrelic==5.22.1.152 nose==1.3.7 oauthlib==2.0.2 -psycopg2==2.8.6 +psycopg2-binary==2.9.3 pycodestyle==2.6.0 pyflakes==2.2.0 pyparsing==2.4.7 From 12951a79d8fbe645d1c4b9fea9c4d5c73c6ef6c8 Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Thu, 30 Jun 2022 11:00:38 -0700 Subject: [PATCH 02/25] Frontend legend visuals 2 new trim toggles + image capture on legend --- .../src/components/projectCreate/messages.js | 8 ++++++++ .../components/projectCreate/trimProject.js | 19 +++++++++++++++++++ .../src/components/taskSelection/legend.js | 9 +++++++++ .../src/components/taskSelection/messages.js | 12 ++++++++++++ frontend/src/config/index.js | 3 +++ 5 files changed, 51 insertions(+) diff --git a/frontend/src/components/projectCreate/messages.js b/frontend/src/components/projectCreate/messages.js index 6da745b85..0b6531090 100644 --- a/frontend/src/components/projectCreate/messages.js +++ b/frontend/src/components/projectCreate/messages.js @@ -85,6 +85,14 @@ export default defineMessages({ id: 'management.projects.create.trim_tasks.trim_to_aoi', defaultMessage: 'Trim the tasks to define the exact Area of Interest for mapping.', }, + trimExcludeWater: { + id: 'management.projects.create.trim_tasks.trim_exclude_water', + defaultMessage: 'Trim the tasks to exclude water areas.', + }, + trimCoverPathsRoads: { + id: 'management.projects.create.trim_tasks.trim_cover_paths_roads', + defaultMessage: 'Trim the tasks to only cover paths and roads.', + }, tinyTasks: { id: 'management.projects.create.trim_tasks.tiny_tasks', defaultMessage: diff --git a/frontend/src/components/projectCreate/trimProject.js b/frontend/src/components/projectCreate/trimProject.js index 5fcaec0b9..6191da1ea 100644 --- a/frontend/src/components/projectCreate/trimProject.js +++ b/frontend/src/components/projectCreate/trimProject.js @@ -72,6 +72,25 @@ export default function TrimProject({ metadata, mapObj, updateMetadata }) { onChange={() => setClipStatus(!clipStatus)} label={} /> + +
+ {}} + label={} + /> +
+
+ {}} + label={} + /> +
+ +
diff --git a/frontend/src/components/taskSelection/legend.js b/frontend/src/components/taskSelection/legend.js index 98b9a60e1..7a69d7762 100644 --- a/frontend/src/components/taskSelection/legend.js +++ b/frontend/src/components/taskSelection/legend.js @@ -19,6 +19,15 @@ export function TasksMapLegend() { {expand && (
+

+ +

+

+ +

+

+ +

diff --git a/frontend/src/components/taskSelection/messages.js b/frontend/src/components/taskSelection/messages.js index 65ccfe470..3cc7098d7 100644 --- a/frontend/src/components/taskSelection/messages.js +++ b/frontend/src/components/taskSelection/messages.js @@ -309,6 +309,18 @@ export default defineMessages({ id: 'project.tasks.list.linkCopied', defaultMessage: 'Task link copied to the clipboard', }, + taskStatus_PENDING_IMAGE_CAPTURE: { + id: 'project.tasks.pending_image_capture', + defaultMessage: 'Pending image capture', + }, + taskStatus_MORE_IMAGES_NEEDED: { + id: 'project.tasks.more_images_needed', + defaultMessage: 'More images needed', + }, + taskStatus_IMAGE_CAPTURE_DONE: { + id: 'project.tasks.image_capture_done', + defaultMessage: 'Image capture done', + }, taskStatus_PRIORITY_AREAS: { id: 'project.tasks.priority_areas', defaultMessage: 'Priority areas', diff --git a/frontend/src/config/index.js b/frontend/src/config/index.js index ed035e3d5..1f9ff269b 100644 --- a/frontend/src/config/index.js +++ b/frontend/src/config/index.js @@ -69,6 +69,9 @@ export const TASK_COLOURS = { INVALIDATED: '#fceca4', BADIMAGERY: '#d8dae4', PRIORITY_AREAS: '#efd1d1', + PENDING_IMAGE_CAPTURE: '#f8e8fb', + MORE_IMAGES_NEEDED: '#d497e2', + IMAGE_CAPTURE_DONE: '#7fc874', }; export const CHART_COLOURS = { From 660563fb2f14862d5dd1e30720a486d1f420f726 Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Wed, 6 Jul 2022 01:13:31 -0700 Subject: [PATCH 03/25] Set date filters as default - Mapillary photo overlay now open by default in iD editor - fromDate filter set from project settings in iD editor --- frontend/src/components/editor.js | 5 ++++- frontend/src/components/taskSelection/action.js | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/editor.js b/frontend/src/components/editor.js index 82606344c..ed9111f26 100644 --- a/frontend/src/components/editor.js +++ b/frontend/src/components/editor.js @@ -5,7 +5,7 @@ import '@hotosm/id/dist/iD.css'; import { OSM_CONSUMER_KEY, OSM_CONSUMER_SECRET, OSM_SERVER_URL } from '../config'; -export default function Editor({ setDisable, comment, presets, imagery, gpxUrl }) { +export default function Editor({ setDisable, comment, presets, imagery, gpxUrl, earliestStreetImagery }) { const dispatch = useDispatch(); const session = useSelector((state) => state.auth.get('session')); const iDContext = useSelector((state) => state.editor.context); @@ -105,6 +105,9 @@ export default function Editor({ setDisable, comment, presets, imagery, gpxUrl } setDisable(false); } }); + + iDContext.photos().setDateFilter("fromDate", earliestStreetImagery.substr(0, 10), false); + window.location.href = window.location.href + "&photo_overlay=mapillary,mapillary-map-features,mapillary-signs"; } }, [session, iDContext, setDisable, presets, locale, gpxUrl]); diff --git a/frontend/src/components/taskSelection/action.js b/frontend/src/components/taskSelection/action.js index 50281276f..0204f3bef 100644 --- a/frontend/src/components/taskSelection/action.js +++ b/frontend/src/components/taskSelection/action.js @@ -189,6 +189,7 @@ export function TaskMapAction({ project, projectIsReady, tasks, activeTasks, act setDisable={setDisable} comment={project.changesetComment} presets={project.idPresets} + earliestStreetImagery={project.earliestStreetImagery} imagery={formatImageryUrlCallback(project.imagery)} gpxUrl={getTaskGpxUrlCallback(project.projectId, tasksIds)} /> From 904e61f0b7669b14b92239a29e017d7a3bfd2666 Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Wed, 6 Jul 2022 22:09:28 -0700 Subject: [PATCH 04/25] Frontend imagery form revamp - Added image capture mode toggle - Settings related to image capture mode only appear if this toggle is enabled - Added all connected UI prompts to messages - "Earliest imagery capture date" shortened to "After:" positioned before date picker - Added mapillary organization id filter input --- .../src/components/projectEdit/imageryForm.js | 70 +++++++++++++++---- .../src/components/projectEdit/messages.js | 30 ++++++++ 2 files changed, 87 insertions(+), 13 deletions(-) diff --git a/frontend/src/components/projectEdit/imageryForm.js b/frontend/src/components/projectEdit/imageryForm.js index fae7373d9..467980315 100644 --- a/frontend/src/components/projectEdit/imageryForm.js +++ b/frontend/src/components/projectEdit/imageryForm.js @@ -2,6 +2,7 @@ import React, { useContext, useState, useLayoutEffect } from 'react'; import Select from 'react-select'; import { FormattedMessage } from 'react-intl'; import DatePicker from 'react-datepicker'; +import { SwitchToggle } from '../formInputs'; import messages from './messages'; import { StateContext, styleClasses } from '../../views/projectEdit'; import { fetchLocalJSONAPI } from '../../network/genericJSONRequest'; @@ -58,23 +59,66 @@ export const ImageryForm = () => {
- - setProjectInfo({ - ...projectInfo, - earliestStreetImagery: date, - }) - } - dateFormat="dd/MM/yyyy" - className={styleClasses.inputClass} - showYearDropdown - scrollableYearDropdown +

+ +

+ } + labelPosition="right" + isChecked={projectInfo.imageCaptureMode} + onChange={() => setProjectInfo({ ...projectInfo, imageCaptureMode: !projectInfo.imageCaptureMode })} />
+ {projectInfo.imageCaptureMode && ( + <> +
+ + +    + + setProjectInfo({ + ...projectInfo, + earliestStreetImagery: date, + }) + } + placeholderText="DD/MM/YYYY" + dateFormat="dd/MM/yyyy" + className={styleClasses.inputClass} + showYearDropdown + scrollableYearDropdown + /> +
+ +
+ +

+ +

+ { + setProjectInfo({ + ...projectInfo, + mapillaryOrganizationId: e.target.value, + }); + }} + /> +
+ + ) + }
); }; diff --git a/frontend/src/components/projectEdit/messages.js b/frontend/src/components/projectEdit/messages.js index dd62744bd..54a899bab 100644 --- a/frontend/src/components/projectEdit/messages.js +++ b/frontend/src/components/projectEdit/messages.js @@ -588,4 +588,34 @@ export default defineMessages({ defaultMessage: 'This will remove the custom editor from the project. Are you sure you don\'t want to disable the custom editor by toggling the "Enabled" checkbox above?', }, + imageCaptureMode: { + id: 'projects.formInputs.imageCaptureMode', + defaultMessage: + 'Image capture mode', + }, + imageCaptureModeInfo: { + id: 'projects.formInputs.imageCaptureMode.info', + defaultMessage: + 'Adapts Tasking Manager to street imagery capture workflow.', + }, + imageryCaptureDate: { + id: 'projects.formInputs.imageryCaptureDate', + defaultMessage: + 'Imagery capture date' + }, + imageryCaptureDateAfter: { + id: 'projects.formInputs.imageryCaptureDate.after', + defaultMessage: + 'After:' + }, + mapillaryOrganizationId: { + id: "projects.formInputs.mapillaryOrganizationId", + defaultMessage: + 'Mapillary organization ID' + }, + mapillaryOrganizationIdInfo: { + id: "projects.formInputs.mapillaryOrganizationId.info", + defaultMessage: + '15-digit identifier to filter Mapillary contributions.' + }, }); From 9c1db8868bd1013e506480de811d84334890f21b Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Wed, 6 Jul 2022 22:11:04 -0700 Subject: [PATCH 05/25] iD/RapiD editor fromdate filter added earliestStreetImagery as a dependency, wrapped filter in if statement --- frontend/src/components/editor.js | 6 ++++-- frontend/src/components/rapidEditor.js | 11 +++++++++-- frontend/src/components/taskSelection/action.js | 1 + 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/editor.js b/frontend/src/components/editor.js index ed9111f26..aed2bfe92 100644 --- a/frontend/src/components/editor.js +++ b/frontend/src/components/editor.js @@ -106,10 +106,12 @@ export default function Editor({ setDisable, comment, presets, imagery, gpxUrl, } }); - iDContext.photos().setDateFilter("fromDate", earliestStreetImagery.substr(0, 10), false); + if (earliestStreetImagery) { + iDContext.photos().setDateFilter("fromDate", earliestStreetImagery.substr(0, 10), false); + } window.location.href = window.location.href + "&photo_overlay=mapillary,mapillary-map-features,mapillary-signs"; } - }, [session, iDContext, setDisable, presets, locale, gpxUrl]); + }, [session, iDContext, setDisable, presets, locale, gpxUrl, earliestStreetImagery]); return
; } diff --git a/frontend/src/components/rapidEditor.js b/frontend/src/components/rapidEditor.js index b89e3fbb6..8b977d809 100644 --- a/frontend/src/components/rapidEditor.js +++ b/frontend/src/components/rapidEditor.js @@ -5,7 +5,7 @@ import 'RapiD/dist/RapiD.css'; import { OSM_CONSUMER_KEY, OSM_CONSUMER_SECRET, OSM_SERVER_URL } from '../config'; -export default function RapidEditor({ setDisable, comment, presets, imagery, gpxUrl, powerUser = false }) { +export default function RapidEditor({ setDisable, comment, presets, imagery, gpxUrl, powerUser = false, earliestStreetImagery }) { const dispatch = useDispatch(); const session = useSelector((state) => state.auth.get('session')); const RapiDContext = useSelector((state) => state.editor.rapidContext); @@ -108,8 +108,15 @@ export default function RapidEditor({ setDisable, comment, presets, imagery, gpx setDisable(false); } }); + + if (earliestStreetImagery) { + RapiDContext.photos().setDateFilter("fromDate", earliestStreetImagery.substr(0, 10), false); + } + + window.location.href = window.location.href + "&photo_overlay=mapillary,mapillary-map-features,mapillary-signs"; + } - }, [session, RapiDContext, setDisable, presets, locale, gpxUrl, powerUser]); + }, [session, RapiDContext, setDisable, presets, locale, gpxUrl, powerUser, earliestStreetImagery]); return
; } diff --git a/frontend/src/components/taskSelection/action.js b/frontend/src/components/taskSelection/action.js index 0204f3bef..e6f1d6bf5 100644 --- a/frontend/src/components/taskSelection/action.js +++ b/frontend/src/components/taskSelection/action.js @@ -198,6 +198,7 @@ export function TaskMapAction({ project, projectIsReady, tasks, activeTasks, act setDisable={setDisable} comment={project.changesetComment} presets={project.idPresets} + earliestStreetImagery={project.earliestStreetImagery} imagery={formatImageryUrlCallback(project.imagery)} gpxUrl={getTaskGpxUrlCallback(project.projectId, tasksIds)} powerUser={project.rapidPowerUser} From 2056c8e1b88e7dbeabcf8bf83e8367ce46a37164 Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Wed, 6 Jul 2022 22:35:58 -0700 Subject: [PATCH 06/25] Backend add fields of imageCaptureMode and mapillaryOrganizationId Updates DTOs to make the new project settings persistent --- backend/models/dtos/project_dto.py | 5 +++- backend/models/postgis/project.py | 8 +++++++ migrations/versions/e03826800ba9_.py | 34 ++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 migrations/versions/e03826800ba9_.py diff --git a/backend/models/dtos/project_dto.py b/backend/models/dtos/project_dto.py index 2d2219388..2aef324e6 100644 --- a/backend/models/dtos/project_dto.py +++ b/backend/models/dtos/project_dto.py @@ -200,7 +200,8 @@ class ProjectDTO(Model): required=False, default=False, serialized_name="enforceRandomTaskSelection" ) earliestStreetImagery = UTCDateTimeType(serialized_name="earliestStreetImagery") - + imageCaptureMode=BooleanType(required=False, default=False, serialized_name="imageCaptureMode") + mapillaryOrganizationId=StringType(serialized_name="mapillaryOrganizationId") private = BooleanType(required=True) changeset_comment = StringType(serialized_name="changesetComment") osmcha_filter_id = StringType(serialized_name="osmchaFilterId") @@ -463,6 +464,8 @@ class ProjectSummary(Model): created = UTCDateTimeType() due_date = UTCDateTimeType(serialized_name="dueDate") earliestStreetImagery = UTCDateTimeType(serialized_name="earliestStreetImagery") + imageCaptureMode=BooleanType(required=False, default=False, serialized_name="imageCaptureMode") + mapillaryOrganizationId=StringType(serialized_name="mapillaryOrganizationId") last_updated = UTCDateTimeType(serialized_name="lastUpdated") priority = StringType(serialized_name="projectPriority") campaigns = ListType(ModelType(CampaignDTO), default=[]) diff --git a/backend/models/postgis/project.py b/backend/models/postgis/project.py index 9d9f2c4e5..0bf5aba00 100644 --- a/backend/models/postgis/project.py +++ b/backend/models/postgis/project.py @@ -148,6 +148,8 @@ class Project(db.Model): due_date = db.Column(db.DateTime) earliestStreetImagery = db.Column(db.DateTime) imagery = db.Column(db.String) + imageCaptureMode = db.Column(db.Boolean, default=False) + mapillaryOrganizationId = db.Column(db.String) josm_preset = db.Column(db.String) id_presets = db.Column(ARRAY(db.String)) rapid_power_user = db.Column(db.Boolean, default=False) @@ -377,6 +379,8 @@ def update(self, project_dto: ProjectDTO): self.changeset_comment = project_dto.changeset_comment self.due_date = project_dto.due_date self.earliestStreetImagery = project_dto.earliestStreetImagery + self.imageCaptureMode = project_dto.imageCaptureMode + self.mapillaryOrganizationId = project_dto.mapillaryOrganizationId self.imagery = project_dto.imagery self.josm_preset = project_dto.josm_preset self.id_presets = project_dto.id_presets @@ -835,6 +839,8 @@ def get_project_summary(self, preferred_locale) -> ProjectSummary: summary.changeset_comment = self.changeset_comment summary.due_date = self.due_date summary.earliestStreetImagery = self.earliestStreetImagery + summary.imageCaptureMode = self.imageCaptureMode + summary.mapillaryOrganizationId = self.mapillaryOrganizationId summary.created = self.created summary.last_updated = self.last_updated @@ -1011,6 +1017,8 @@ def _get_project_and_base_dto(self): base_dto.osmcha_filter_id = self.osmcha_filter_id base_dto.due_date = self.due_date base_dto.earliestStreetImagery = self.earliestStreetImagery + base_dto.imageCaptureMode = self.imageCaptureMode + base_dto.mapillaryOrganizationId = self.mapillaryOrganizationId base_dto.imagery = self.imagery base_dto.josm_preset = self.josm_preset base_dto.id_presets = self.id_presets diff --git a/migrations/versions/e03826800ba9_.py b/migrations/versions/e03826800ba9_.py new file mode 100644 index 000000000..3be4ee10f --- /dev/null +++ b/migrations/versions/e03826800ba9_.py @@ -0,0 +1,34 @@ +"""empty message + +Revision ID: e03826800ba9 +Revises: b805df721885 +Create Date: 2022-07-06 22:22:15.065202 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'e03826800ba9' +down_revision = 'b805df721885' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('projects', sa.Column('imageCaptureMode', sa.Boolean(), nullable=True)) + op.add_column('projects', sa.Column('mapillaryOrganizationId', sa.String(), nullable=True)) + op.drop_index('idx_task_validation_mapper_status_composite', table_name='task_invalidation_history') + op.create_index('idx_task_validation_mapper_status_composite', 'task_invalidation_history', ['mapper_id', 'is_closed'], unique=False) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index('idx_task_validation_mapper_status_composite', table_name='task_invalidation_history') + op.create_index('idx_task_validation_mapper_status_composite', 'task_invalidation_history', ['invalidator_id', 'is_closed'], unique=False) + op.drop_column('projects', 'mapillaryOrganizationId') + op.drop_column('projects', 'imageCaptureMode') + # ### end Alembic commands ### From 0af3cd3c4f1fdb33bb24ade7f09a1c02ee71f6ad Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Thu, 7 Jul 2022 00:10:02 -0700 Subject: [PATCH 07/25] Mapillary API organization get call --- frontend/src/components/projectEdit/imageryForm.js | 14 ++++++++++++++ frontend/src/components/projectEdit/messages.js | 5 +++++ frontend/src/config/index.js | 1 + 3 files changed, 20 insertions(+) diff --git a/frontend/src/components/projectEdit/imageryForm.js b/frontend/src/components/projectEdit/imageryForm.js index 467980315..24ac2eb58 100644 --- a/frontend/src/components/projectEdit/imageryForm.js +++ b/frontend/src/components/projectEdit/imageryForm.js @@ -7,11 +7,15 @@ import messages from './messages'; import { StateContext, styleClasses } from '../../views/projectEdit'; import { fetchLocalJSONAPI } from '../../network/genericJSONRequest'; import { useImageryOption, IMAGERY_OPTIONS } from '../../hooks/UseImageryOption'; +import { MAPILLARY_TOKEN } from '../../config'; +import axios from 'axios'; export const ImageryForm = () => { const { projectInfo, setProjectInfo } = useContext(StateContext); const [licenses, setLicenses] = useState(null); + const [organization, setOrganization] = useState(null); + useLayoutEffect(() => { const fetchLicenses = async () => { fetchLocalJSONAPI('licenses/') @@ -21,6 +25,12 @@ export const ImageryForm = () => { fetchLicenses(); }, [setLicenses]); + if (projectInfo.mapillaryOrganizationId) { + axios.get(`https://graph.mapillary.com/${projectInfo.mapillaryOrganizationId}?access_token=${MAPILLARY_TOKEN}&fields=name`) + .then(resp => setOrganization(resp.data.name)) + .catch(() => setOrganization(null)) + } + let defaultValue = null; if (licenses !== null && projectInfo.licenseId !== null) { defaultValue = licenses.filter((l) => l.licenseId === projectInfo.licenseId)[0]; @@ -103,6 +113,10 @@ export const ImageryForm = () => {

+ + + {organization} + Date: Thu, 7 Jul 2022 00:11:49 -0700 Subject: [PATCH 08/25] Map legend update Now updates based on whether user selects image capture mode --- .../src/components/taskSelection/index.js | 2 +- .../src/components/taskSelection/legend.js | 56 ++++++++++--------- frontend/src/components/taskSelection/map.js | 7 +++ 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/frontend/src/components/taskSelection/index.js b/frontend/src/components/taskSelection/index.js index 633e0289b..b3db8d51a 100644 --- a/frontend/src/components/taskSelection/index.js +++ b/frontend/src/components/taskSelection/index.js @@ -358,7 +358,7 @@ export function TaskSelection({ project, type, loading }: Object) { priorityAreas={priorityAreas} animateZoom={false} /> - +
diff --git a/frontend/src/components/taskSelection/legend.js b/frontend/src/components/taskSelection/legend.js index 7a69d7762..f441095c1 100644 --- a/frontend/src/components/taskSelection/legend.js +++ b/frontend/src/components/taskSelection/legend.js @@ -5,7 +5,7 @@ import messages from './messages'; import { TaskStatus } from './taskList'; import { LockIcon, ChevronDownIcon, ChevronUpIcon } from '../svgIcons'; -export function TasksMapLegend() { +export function TasksMapLegend({ imageCaptureMode }) { const lineClasses = 'mv2 blue-dark f5'; const [expand, setExpand] = useState(true); return ( @@ -19,30 +19,36 @@ export function TasksMapLegend() { {expand && (
-

- -

-

- -

-

- -

-

- -

-

- -

-

- -

-

- -

-

- -

+ {imageCaptureMode && <> +

+ +

+

+ +

+

+ +

+ + } + {!imageCaptureMode && (<> +

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+ ) + }

diff --git a/frontend/src/components/taskSelection/map.js b/frontend/src/components/taskSelection/map.js index 7bfd1b6a1..65af42ff9 100644 --- a/frontend/src/components/taskSelection/map.js +++ b/frontend/src/components/taskSelection/map.js @@ -168,8 +168,15 @@ export const TasksMap = ({ TASK_COLOURS.INVALIDATED, 'BADIMAGERY', TASK_COLOURS.BADIMAGERY, + 'PENDING_IMAGE_CAPTURE', + TASK_COLOURS.PENDING_IMAGE_CAPTURE, + 'MORE_IMAGES_NEEDED', + TASK_COLOURS.MORE_IMAGES_NEEDED, + 'IMAGE_CAPTURE_DONE', + TASK_COLOURS.IMAGE_CAPTURE_DONE, 'rgba(0,0,0,0)', ], + //'fill-opacity': ["/", ["*", 2, ["get", "taskId"]], 100], // Temporary.... creates a gradient 'fill-opacity': 0.8, }, }, From c5986ddab4d39eb76deaad2824b39c62071974be Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Thu, 7 Jul 2022 00:24:27 -0700 Subject: [PATCH 09/25] Update editor/rapideditor Now only enables mapillary and date filter by default if image capture mode is enabled --- frontend/src/components/editor.js | 14 ++++++++------ frontend/src/components/rapidEditor.js | 15 ++++++++------- frontend/src/components/taskSelection/action.js | 2 ++ 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/frontend/src/components/editor.js b/frontend/src/components/editor.js index aed2bfe92..5a35964f3 100644 --- a/frontend/src/components/editor.js +++ b/frontend/src/components/editor.js @@ -5,7 +5,7 @@ import '@hotosm/id/dist/iD.css'; import { OSM_CONSUMER_KEY, OSM_CONSUMER_SECRET, OSM_SERVER_URL } from '../config'; -export default function Editor({ setDisable, comment, presets, imagery, gpxUrl, earliestStreetImagery }) { +export default function Editor({ setDisable, comment, presets, imagery, gpxUrl, earliestStreetImagery, imageCaptureMode}) { const dispatch = useDispatch(); const session = useSelector((state) => state.auth.get('session')); const iDContext = useSelector((state) => state.editor.context); @@ -106,12 +106,14 @@ export default function Editor({ setDisable, comment, presets, imagery, gpxUrl, } }); - if (earliestStreetImagery) { - iDContext.photos().setDateFilter("fromDate", earliestStreetImagery.substr(0, 10), false); - } - window.location.href = window.location.href + "&photo_overlay=mapillary,mapillary-map-features,mapillary-signs"; + if (imageCaptureMode) { + if (earliestStreetImagery) { + iDContext.photos().setDateFilter("fromDate", earliestStreetImagery.substr(0, 10), false); + } + window.location.href = window.location.href + "&photo_overlay=mapillary,mapillary-map-features,mapillary-signs"; + } } - }, [session, iDContext, setDisable, presets, locale, gpxUrl, earliestStreetImagery]); + }, [session, iDContext, setDisable, presets, locale, gpxUrl, earliestStreetImagery, imageCaptureMode]); return
; } diff --git a/frontend/src/components/rapidEditor.js b/frontend/src/components/rapidEditor.js index 8b977d809..71774d8b2 100644 --- a/frontend/src/components/rapidEditor.js +++ b/frontend/src/components/rapidEditor.js @@ -5,7 +5,7 @@ import 'RapiD/dist/RapiD.css'; import { OSM_CONSUMER_KEY, OSM_CONSUMER_SECRET, OSM_SERVER_URL } from '../config'; -export default function RapidEditor({ setDisable, comment, presets, imagery, gpxUrl, powerUser = false, earliestStreetImagery }) { +export default function RapidEditor({ setDisable, comment, presets, imagery, gpxUrl, powerUser = false, earliestStreetImagery, imageCaptureMode}) { const dispatch = useDispatch(); const session = useSelector((state) => state.auth.get('session')); const RapiDContext = useSelector((state) => state.editor.rapidContext); @@ -109,14 +109,15 @@ export default function RapidEditor({ setDisable, comment, presets, imagery, gpx } }); - if (earliestStreetImagery) { - RapiDContext.photos().setDateFilter("fromDate", earliestStreetImagery.substr(0, 10), false); - } - - window.location.href = window.location.href + "&photo_overlay=mapillary,mapillary-map-features,mapillary-signs"; + if (imageCaptureMode) { + if (earliestStreetImagery) { + RapiDContext.photos().setDateFilter("fromDate", earliestStreetImagery.substr(0, 10), false); + } + window.location.href = window.location.href + "&photo_overlay=mapillary,mapillary-map-features,mapillary-signs"; + } } - }, [session, RapiDContext, setDisable, presets, locale, gpxUrl, powerUser, earliestStreetImagery]); + }, [session, RapiDContext, setDisable, presets, locale, gpxUrl, powerUser, earliestStreetImagery, imageCaptureMode]); return
; } diff --git a/frontend/src/components/taskSelection/action.js b/frontend/src/components/taskSelection/action.js index e6f1d6bf5..65eb9d810 100644 --- a/frontend/src/components/taskSelection/action.js +++ b/frontend/src/components/taskSelection/action.js @@ -190,6 +190,7 @@ export function TaskMapAction({ project, projectIsReady, tasks, activeTasks, act comment={project.changesetComment} presets={project.idPresets} earliestStreetImagery={project.earliestStreetImagery} + imageCaptureMode={project.imageCaptureMode} imagery={formatImageryUrlCallback(project.imagery)} gpxUrl={getTaskGpxUrlCallback(project.projectId, tasksIds)} /> @@ -199,6 +200,7 @@ export function TaskMapAction({ project, projectIsReady, tasks, activeTasks, act comment={project.changesetComment} presets={project.idPresets} earliestStreetImagery={project.earliestStreetImagery} + imageCaptureMode={project.imageCaptureMode} imagery={formatImageryUrlCallback(project.imagery)} gpxUrl={getTaskGpxUrlCallback(project.projectId, tasksIds)} powerUser={project.rapidPowerUser} From 18cf0d843fc3470e95485248cbc18f1fe753f9cb Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Mon, 11 Jul 2022 11:23:31 -0700 Subject: [PATCH 10/25] Update map.js --- frontend/src/components/taskSelection/map.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/taskSelection/map.js b/frontend/src/components/taskSelection/map.js index 65af42ff9..900bdb755 100644 --- a/frontend/src/components/taskSelection/map.js +++ b/frontend/src/components/taskSelection/map.js @@ -176,8 +176,8 @@ export const TasksMap = ({ TASK_COLOURS.IMAGE_CAPTURE_DONE, 'rgba(0,0,0,0)', ], - //'fill-opacity': ["/", ["*", 2, ["get", "taskId"]], 100], // Temporary.... creates a gradient - 'fill-opacity': 0.8, + 'fill-opacity': ["/", ["*", 2, ["get", "taskId"]], 1000], // Temporary.... creates a gradient + //'fill-opacity': 0.8, }, }, 'tasks-icon', From 8cfe6a148d88b236ce7f31807e2012016934a47e Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Thu, 4 Aug 2022 12:02:42 -0700 Subject: [PATCH 11/25] Update action.js Fixed missing brackets --- .../src/components/taskSelection/action.js | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/frontend/src/components/taskSelection/action.js b/frontend/src/components/taskSelection/action.js index c9905ea4c..43696e49b 100644 --- a/frontend/src/components/taskSelection/action.js +++ b/frontend/src/components/taskSelection/action.js @@ -49,11 +49,11 @@ export function TaskMapAction({ project, projectIsReady, tasks, activeTasks, act () => activeTasks ? activeTasks - .map((task) => task.taskId) - .sort((n1, n2) => { - // in ascending order - return n1 - n2; - }) + .map((task) => task.taskId) + .sort((n1, n2) => { + // in ascending order + return n1 - n2; + }) : [], [activeTasks], ); @@ -195,27 +195,27 @@ export function TaskMapAction({ project, projectIsReady, tasks, activeTasks, act } > {editor === 'ID' ? ( - - - ) : ( - + ) : ( + )} ) : ( From e38d9c03f6b315a0269af63b39e7e2838fadd132 Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Mon, 8 Aug 2022 13:20:11 -0700 Subject: [PATCH 12/25] Addressing comments Renamed new columns to use underscores Project states --- backend/models/dtos/project_dto.py | 12 +++---- backend/models/postgis/project.py | 25 +++++++------- .../components/projectCreate/trimProject.js | 11 +++--- migrations/versions/7aba630f4265_.py | 32 +++++++++++++++++ migrations/versions/b805df721885_.py | 32 ----------------- migrations/versions/e03826800ba9_.py | 34 ------------------- requirements.txt | 2 +- 7 files changed, 58 insertions(+), 90 deletions(-) create mode 100644 migrations/versions/7aba630f4265_.py delete mode 100644 migrations/versions/b805df721885_.py delete mode 100644 migrations/versions/e03826800ba9_.py diff --git a/backend/models/dtos/project_dto.py b/backend/models/dtos/project_dto.py index 6c18177f4..b7bbdcf70 100644 --- a/backend/models/dtos/project_dto.py +++ b/backend/models/dtos/project_dto.py @@ -199,9 +199,9 @@ class ProjectDTO(Model): enforce_random_task_selection = BooleanType( required=False, default=False, serialized_name="enforceRandomTaskSelection" ) - earliestStreetImagery = UTCDateTimeType(serialized_name="earliestStreetImagery") - imageCaptureMode=BooleanType(required=False, default=False, serialized_name="imageCaptureMode") - mapillaryOrganizationId=StringType(serialized_name="mapillaryOrganizationId") + earliest_street_imagery = UTCDateTimeType(serialized_name="earliestStreetImagery") + image_capture_mode=BooleanType(required=False, default=False, serialized_name="imageCaptureMode") + mapillary_organization_id=StringType(serialized_name="mapillaryOrganizationId") private = BooleanType(required=True) changeset_comment = StringType(serialized_name="changesetComment") osmcha_filter_id = StringType(serialized_name="osmchaFilterId") @@ -464,9 +464,9 @@ class ProjectSummary(Model): author = StringType() created = UTCDateTimeType() due_date = UTCDateTimeType(serialized_name="dueDate") - earliestStreetImagery = UTCDateTimeType(serialized_name="earliestStreetImagery") - imageCaptureMode=BooleanType(required=False, default=False, serialized_name="imageCaptureMode") - mapillaryOrganizationId=StringType(serialized_name="mapillaryOrganizationId") + earliest_street_imagery = UTCDateTimeType(serialized_name="earliestStreetImagery") + image_capture_mode=BooleanType(required=False, default=False, serialized_name="imageCaptureMode") + mapillary_organization_id=StringType(serialized_name="mapillaryOrganizationId") last_updated = UTCDateTimeType(serialized_name="lastUpdated") priority = StringType(serialized_name="projectPriority") campaigns = ListType(ModelType(CampaignDTO), default=[]) diff --git a/backend/models/postgis/project.py b/backend/models/postgis/project.py index ba45f526f..6575f1b6e 100644 --- a/backend/models/postgis/project.py +++ b/backend/models/postgis/project.py @@ -146,10 +146,10 @@ class Project(db.Model): db.String ) # Optional custom filter id for filtering on OSMCha due_date = db.Column(db.DateTime) - earliestStreetImagery = db.Column(db.DateTime) + earliest_street_imagery = db.Column(db.DateTime) imagery = db.Column(db.String) - imageCaptureMode = db.Column(db.Boolean, default=False) - mapillaryOrganizationId = db.Column(db.String) + image_capture_mode = db.Column(db.Boolean, default=False) + mapillary_organization_id = db.Column(db.String) josm_preset = db.Column(db.String) id_presets = db.Column(ARRAY(db.String)) extra_id_params = db.Column(db.String) @@ -381,9 +381,9 @@ def update(self, project_dto: ProjectDTO): self.mapper_level = MappingLevel[project_dto.mapper_level.upper()].value self.changeset_comment = project_dto.changeset_comment self.due_date = project_dto.due_date - self.earliestStreetImagery = project_dto.earliestStreetImagery - self.imageCaptureMode = project_dto.imageCaptureMode - self.mapillaryOrganizationId = project_dto.mapillaryOrganizationId + self.earliest_street_imagery = project_dto.earliest_street_imagery + self.image_capture_mode = project_dto.image_capture_mode + self.mapillary_organization_id = project_dto.mapillary_organization_id self.imagery = project_dto.imagery self.josm_preset = project_dto.josm_preset self.id_presets = project_dto.id_presets @@ -842,10 +842,9 @@ def get_project_summary(self, preferred_locale) -> ProjectSummary: summary.country_tag = self.country summary.changeset_comment = self.changeset_comment summary.due_date = self.due_date - summary.earliestStreetImagery = self.earliestStreetImagery - summary.imageCaptureMode = self.imageCaptureMode - summary.mapillaryOrganizationId = self.mapillaryOrganizationId - + summary.earliest_street_imagery = self.earliest_street_imagery + summary.image_capture_mode = self.image_capture_mode + summary.mapillary_organization_id = self.mapillary_organization_id summary.created = self.created summary.last_updated = self.last_updated summary.osmcha_filter_id = self.osmcha_filter_id @@ -1021,9 +1020,9 @@ def _get_project_and_base_dto(self): base_dto.changeset_comment = self.changeset_comment base_dto.osmcha_filter_id = self.osmcha_filter_id base_dto.due_date = self.due_date - base_dto.earliestStreetImagery = self.earliestStreetImagery - base_dto.imageCaptureMode = self.imageCaptureMode - base_dto.mapillaryOrganizationId = self.mapillaryOrganizationId + base_dto.earliest_street_imagery = self.earliest_street_imagery + base_dto.image_capture_mode = self.image_capture_mode + base_dto.mapillary_organization_id = self.mapillary_organization_id base_dto.imagery = self.imagery base_dto.josm_preset = self.josm_preset base_dto.id_presets = self.id_presets diff --git a/frontend/src/components/projectCreate/trimProject.js b/frontend/src/components/projectCreate/trimProject.js index 6191da1ea..a8e616fcd 100644 --- a/frontend/src/components/projectCreate/trimProject.js +++ b/frontend/src/components/projectCreate/trimProject.js @@ -39,6 +39,9 @@ const removeTinyTasks = (metadata, updateMetadata) => { export default function TrimProject({ metadata, mapObj, updateMetadata }) { const token = useSelector((state) => state.auth.get('token')); const [clipStatus, setClipStatus] = useState(false); + const [roadStatus, setRoadStatus] = useState(false); + const [waterStatus, setWaterStatus] = useState(false); + const [tinyTasksNumber, setTinyTasksNumber] = useState(0); const trimTaskGridAsync = useAsync(trimTaskGrid); @@ -75,17 +78,17 @@ export default function TrimProject({ metadata, mapObj, updateMetadata }) {
{}} + onChange={() => {setClipStatus(!waterStatus)}} label={} />
{}} + onChange={() => {setClipStatus(!roadStatus)}} label={} />
diff --git a/migrations/versions/7aba630f4265_.py b/migrations/versions/7aba630f4265_.py new file mode 100644 index 000000000..6193e68f2 --- /dev/null +++ b/migrations/versions/7aba630f4265_.py @@ -0,0 +1,32 @@ +"""empty message + +Revision ID: 7aba630f4265 +Revises: 8a6419f289aa +Create Date: 2022-08-08 12:54:31.656978 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = '7aba630f4265' +down_revision = '8a6419f289aa' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('projects', sa.Column('earliest_street_imagery', sa.DateTime(), nullable=True)) + op.add_column('projects', sa.Column('image_capture_mode', sa.Boolean(), nullable=True)) + op.add_column('projects', sa.Column('mapillary_organization_id', sa.String(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('projects', 'mapillary_organization_id') + op.drop_column('projects', 'image_capture_mode') + op.drop_column('projects', 'earliest_street_imagery') + # ### end Alembic commands ### diff --git a/migrations/versions/b805df721885_.py b/migrations/versions/b805df721885_.py deleted file mode 100644 index 465ae1eb2..000000000 --- a/migrations/versions/b805df721885_.py +++ /dev/null @@ -1,32 +0,0 @@ -"""empty message - -Revision ID: b805df721885 -Revises: 8a6419f289aa -Create Date: 2022-06-23 12:18:09.218580 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'b805df721885' -down_revision = '8a6419f289aa' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('projects', sa.Column('earliestStreetImagery', sa.DateTime(), nullable=True)) - op.drop_index('idx_task_validation_mapper_status_composite', table_name='task_invalidation_history') - op.create_index('idx_task_validation_mapper_status_composite', 'task_invalidation_history', ['invalidator_id', 'is_closed'], unique=False) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_index('idx_task_validation_mapper_status_composite', table_name='task_invalidation_history') - op.create_index('idx_task_validation_mapper_status_composite', 'task_invalidation_history', ['mapper_id', 'is_closed'], unique=False) - op.drop_column('projects', 'earliestStreetImagery') - # ### end Alembic commands ### diff --git a/migrations/versions/e03826800ba9_.py b/migrations/versions/e03826800ba9_.py deleted file mode 100644 index 3be4ee10f..000000000 --- a/migrations/versions/e03826800ba9_.py +++ /dev/null @@ -1,34 +0,0 @@ -"""empty message - -Revision ID: e03826800ba9 -Revises: b805df721885 -Create Date: 2022-07-06 22:22:15.065202 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'e03826800ba9' -down_revision = 'b805df721885' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('projects', sa.Column('imageCaptureMode', sa.Boolean(), nullable=True)) - op.add_column('projects', sa.Column('mapillaryOrganizationId', sa.String(), nullable=True)) - op.drop_index('idx_task_validation_mapper_status_composite', table_name='task_invalidation_history') - op.create_index('idx_task_validation_mapper_status_composite', 'task_invalidation_history', ['mapper_id', 'is_closed'], unique=False) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_index('idx_task_validation_mapper_status_composite', table_name='task_invalidation_history') - op.create_index('idx_task_validation_mapper_status_composite', 'task_invalidation_history', ['invalidator_id', 'is_closed'], unique=False) - op.drop_column('projects', 'mapillaryOrganizationId') - op.drop_column('projects', 'imageCaptureMode') - # ### end Alembic commands ### diff --git a/requirements.txt b/requirements.txt index 01bf9d9d0..df3c30387 100644 --- a/requirements.txt +++ b/requirements.txt @@ -38,7 +38,7 @@ mccabe==0.6.1 newrelic==5.22.1.152 nose==1.3.7 oauthlib==2.0.2 -psycopg2-binary==2.9.3 +psycopg2==2.8.6 pycodestyle==2.6.0 pyflakes==2.2.0 pyparsing==2.4.7 From 15b4b2a2bb39c174c8cbe8735d9ba0c7517229ad Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Mon, 8 Aug 2022 13:26:08 -0700 Subject: [PATCH 13/25] Removed mapillary token --- frontend/src/config/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/config/index.js b/frontend/src/config/index.js index ce6ec91dc..7e0958f1f 100644 --- a/frontend/src/config/index.js +++ b/frontend/src/config/index.js @@ -21,7 +21,7 @@ export const ADVANCED_LEVEL_COUNT = Number(process.env.REACT_APP_TM_MAPPER_LEVEL export const MAPBOX_TOKEN = process.env.REACT_APP_MAPBOX_TOKEN || ''; export const ENABLE_SERVICEWORKER = process.env.REACT_APP_ENABLE_SERVICEWORKER || 0; export const MAX_AOI_AREA = Number(process.env.REACT_APP_MAX_AOI_AREA) || 5000; -export const MAPILLARY_TOKEN = process.env.REACT_APP_MAPILLARY_TOKEN || 'MLY|5494923973921616|75ede84ae518fed4232a6e7eb7d53688'; +export const MAPILLARY_TOKEN = process.env.REACT_APP_MAPILLARY_TOKEN || ''; export const MAX_FILESIZE = parseInt(process.env.REACT_APP_MAX_FILESIZE) || 5000000; // bytes // ORGANISATIONAL INFORMATION From b5eca8225494fb100dce3e5fa6283c19f71ed161 Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Mon, 8 Aug 2022 14:43:21 -0700 Subject: [PATCH 14/25] Ran linter commands & addressed comments --- backend/models/dtos/project_dto.py | 12 ++++--- frontend/src/components/editor.js | 28 +++++++++++++--- .../components/projectCreate/trimProject.js | 33 ++++++++++--------- .../src/components/projectEdit/imageryForm.js | 25 ++++++++------ .../src/components/projectEdit/messages.js | 29 +++++++--------- frontend/src/components/rapidEditor.js | 32 +++++++++++++++--- .../src/components/taskSelection/action.js | 11 +++---- .../src/components/taskSelection/index.js | 2 +- .../src/components/taskSelection/legend.js | 31 ++++++++--------- frontend/src/components/taskSelection/map.js | 4 +-- frontend/src/components/teamsAndOrgs/teams.js | 4 +-- migrations/versions/7aba630f4265_.py | 23 ++++++++----- 12 files changed, 143 insertions(+), 91 deletions(-) diff --git a/backend/models/dtos/project_dto.py b/backend/models/dtos/project_dto.py index b7bbdcf70..74803113a 100644 --- a/backend/models/dtos/project_dto.py +++ b/backend/models/dtos/project_dto.py @@ -200,8 +200,10 @@ class ProjectDTO(Model): required=False, default=False, serialized_name="enforceRandomTaskSelection" ) earliest_street_imagery = UTCDateTimeType(serialized_name="earliestStreetImagery") - image_capture_mode=BooleanType(required=False, default=False, serialized_name="imageCaptureMode") - mapillary_organization_id=StringType(serialized_name="mapillaryOrganizationId") + image_capture_mode = BooleanType( + required=False, default=False, serialized_name="imageCaptureMode" + ) + mapillary_organization_id = StringType(serialized_name="mapillaryOrganizationId") private = BooleanType(required=True) changeset_comment = StringType(serialized_name="changesetComment") osmcha_filter_id = StringType(serialized_name="osmchaFilterId") @@ -465,8 +467,10 @@ class ProjectSummary(Model): created = UTCDateTimeType() due_date = UTCDateTimeType(serialized_name="dueDate") earliest_street_imagery = UTCDateTimeType(serialized_name="earliestStreetImagery") - image_capture_mode=BooleanType(required=False, default=False, serialized_name="imageCaptureMode") - mapillary_organization_id=StringType(serialized_name="mapillaryOrganizationId") + image_capture_mode = BooleanType( + required=False, default=False, serialized_name="imageCaptureMode" + ) + mapillary_organization_id = StringType(serialized_name="mapillaryOrganizationId") last_updated = UTCDateTimeType(serialized_name="lastUpdated") priority = StringType(serialized_name="projectPriority") campaigns = ListType(ModelType(CampaignDTO), default=[]) diff --git a/frontend/src/components/editor.js b/frontend/src/components/editor.js index 5a35964f3..b9337e5e5 100644 --- a/frontend/src/components/editor.js +++ b/frontend/src/components/editor.js @@ -5,7 +5,15 @@ import '@hotosm/id/dist/iD.css'; import { OSM_CONSUMER_KEY, OSM_CONSUMER_SECRET, OSM_SERVER_URL } from '../config'; -export default function Editor({ setDisable, comment, presets, imagery, gpxUrl, earliestStreetImagery, imageCaptureMode}) { +export default function Editor({ + setDisable, + comment, + presets, + imagery, + gpxUrl, + earliestStreetImagery, + imageCaptureMode, +}) { const dispatch = useDispatch(); const session = useSelector((state) => state.auth.get('session')); const iDContext = useSelector((state) => state.editor.context); @@ -108,12 +116,22 @@ export default function Editor({ setDisable, comment, presets, imagery, gpxUrl, if (imageCaptureMode) { if (earliestStreetImagery) { - iDContext.photos().setDateFilter("fromDate", earliestStreetImagery.substr(0, 10), false); + iDContext.photos().setDateFilter('fromDate', earliestStreetImagery.substr(0, 10), false); } - window.location.href = window.location.href + "&photo_overlay=mapillary,mapillary-map-features,mapillary-signs"; - } + window.location.href = + window.location.href + '&photo_overlay=mapillary,mapillary-map-features,mapillary-signs'; + } } - }, [session, iDContext, setDisable, presets, locale, gpxUrl, earliestStreetImagery, imageCaptureMode]); + }, [ + session, + iDContext, + setDisable, + presets, + locale, + gpxUrl, + earliestStreetImagery, + imageCaptureMode, + ]); return
; } diff --git a/frontend/src/components/projectCreate/trimProject.js b/frontend/src/components/projectCreate/trimProject.js index a8e616fcd..841d2b4aa 100644 --- a/frontend/src/components/projectCreate/trimProject.js +++ b/frontend/src/components/projectCreate/trimProject.js @@ -76,24 +76,27 @@ export default function TrimProject({ metadata, mapObj, updateMetadata }) { label={} /> -
- {setClipStatus(!waterStatus)}} - label={} - /> -
-
- {setClipStatus(!roadStatus)}} +
+ { + setWaterStatus(!waterStatus); + }} + label={} + /> +
+
+ { + setRoadStatus(!roadStatus); + }} label={} />
- - +
diff --git a/frontend/src/components/projectEdit/imageryForm.js b/frontend/src/components/projectEdit/imageryForm.js index 54414689c..0661628af 100644 --- a/frontend/src/components/projectEdit/imageryForm.js +++ b/frontend/src/components/projectEdit/imageryForm.js @@ -27,9 +27,12 @@ export const ImageryForm = () => { }, [setLicenses]); if (projectInfo.mapillaryOrganizationId) { - axios.get(`https://graph.mapillary.com/${projectInfo.mapillaryOrganizationId}?access_token=${MAPILLARY_TOKEN}&fields=name`) - .then(resp => setOrganization(resp.data.name)) - .catch(() => setOrganization(null)) + axios + .get( + `https://graph.mapillary.com/${projectInfo.mapillaryOrganizationId}?access_token=${MAPILLARY_TOKEN}&fields=name`, + ) + .then((resp) => setOrganization(resp.data.name)) + .catch(() => setOrganization(null)); } let defaultValue = null; @@ -44,7 +47,6 @@ export const ImageryForm = () => { -
@@ -79,7 +81,9 @@ export const ImageryForm = () => { label={} labelPosition="right" isChecked={projectInfo.imageCaptureMode} - onChange={() => setProjectInfo({ ...projectInfo, imageCaptureMode: !projectInfo.imageCaptureMode })} + onChange={() => + setProjectInfo({ ...projectInfo, imageCaptureMode: !projectInfo.imageCaptureMode }) + } />
@@ -90,7 +94,7 @@ export const ImageryForm = () => { -    + :    @@ -115,8 +119,10 @@ export const ImageryForm = () => {

- - {organization} + + + + : {organization} { />
- ) - } + )}
); }; diff --git a/frontend/src/components/projectEdit/messages.js b/frontend/src/components/projectEdit/messages.js index 8a123a958..7444c247f 100644 --- a/frontend/src/components/projectEdit/messages.js +++ b/frontend/src/components/projectEdit/messages.js @@ -595,38 +595,31 @@ export default defineMessages({ }, imageCaptureMode: { id: 'projects.formInputs.imageCaptureMode', - defaultMessage: - 'Image capture mode', + defaultMessage: 'Image capture mode', }, imageCaptureModeInfo: { id: 'projects.formInputs.imageCaptureMode.info', - defaultMessage: - 'Adapts Tasking Manager to street imagery capture workflow.', + defaultMessage: 'Adapts Tasking Manager to street imagery capture workflow.', }, imageryCaptureDate: { id: 'projects.formInputs.imageryCaptureDate', - defaultMessage: - 'Imagery capture date' + defaultMessage: 'Imagery capture date', }, imageryCaptureDateAfter: { id: 'projects.formInputs.imageryCaptureDate.after', - defaultMessage: - 'After:' + defaultMessage: 'After', }, mapillaryOrganizationId: { - id: "projects.formInputs.mapillaryOrganizationId", - defaultMessage: - 'Mapillary organization ID' + id: 'projects.formInputs.mapillaryOrganizationId', + defaultMessage: 'Mapillary organization ID', }, mapillaryOrganizationIdInfo: { - id: "projects.formInputs.mapillaryOrganizationId.info", - defaultMessage: - '15-digit identifier to filter Mapillary contributions.' + id: 'projects.formInputs.mapillaryOrganizationId.info', + defaultMessage: '15-digit identifier to filter Mapillary contributions.', }, mapillaryOrganizationSelected: { - id: "projects.formInputs.mapillaryOrganizationId.selected", - defaultMessage: - 'Organization: ' + id: 'projects.formInputs.mapillaryOrganizationId.selected', + defaultMessage: 'Organization', }, noMappingEditor: { id: 'projects.formInputs.noMappingEditor', @@ -652,5 +645,5 @@ export default defineMessages({ iDAPIDocs: { id: 'projects.formInputs.extraIdParams.iDAPIDocs', defaultMessage: 'iD editor documentation', - } + }, }); diff --git a/frontend/src/components/rapidEditor.js b/frontend/src/components/rapidEditor.js index 8fca3ef83..d492550a9 100644 --- a/frontend/src/components/rapidEditor.js +++ b/frontend/src/components/rapidEditor.js @@ -5,7 +5,16 @@ import 'RapiD/dist/RapiD.css'; import { OSM_CONSUMER_KEY, OSM_CONSUMER_SECRET, OSM_SERVER_URL } from '../config'; -export default function RapidEditor({ setDisable, comment, presets, imagery, gpxUrl, powerUser = false, earliestStreetImagery, imageCaptureMode}) { +export default function RapidEditor({ + setDisable, + comment, + presets, + imagery, + gpxUrl, + powerUser = false, + earliestStreetImagery, + imageCaptureMode, +}) { const dispatch = useDispatch(); const session = useSelector((state) => state.auth.get('session')); const RapiDContext = useSelector((state) => state.editor.rapidContext); @@ -109,13 +118,28 @@ export default function RapidEditor({ setDisable, comment, presets, imagery, gpx if (imageCaptureMode) { if (earliestStreetImagery) { - RapiDContext.photos().setDateFilter("fromDate", earliestStreetImagery.substr(0, 10), false); + RapiDContext.photos().setDateFilter( + 'fromDate', + earliestStreetImagery.substr(0, 10), + false, + ); } - window.location.href = window.location.href + "&photo_overlay=mapillary,mapillary-map-features,mapillary-signs"; + window.location.href = + window.location.href + '&photo_overlay=mapillary,mapillary-map-features,mapillary-signs'; } } - }, [session, RapiDContext, setDisable, presets, locale, gpxUrl, powerUser, earliestStreetImagery, imageCaptureMode]); + }, [ + session, + RapiDContext, + setDisable, + presets, + locale, + gpxUrl, + powerUser, + earliestStreetImagery, + imageCaptureMode, + ]); return
; } diff --git a/frontend/src/components/taskSelection/action.js b/frontend/src/components/taskSelection/action.js index 43696e49b..e315439c3 100644 --- a/frontend/src/components/taskSelection/action.js +++ b/frontend/src/components/taskSelection/action.js @@ -49,11 +49,11 @@ export function TaskMapAction({ project, projectIsReady, tasks, activeTasks, act () => activeTasks ? activeTasks - .map((task) => task.taskId) - .sort((n1, n2) => { - // in ascending order - return n1 - n2; - }) + .map((task) => task.taskId) + .sort((n1, n2) => { + // in ascending order + return n1 - n2; + }) : [], [activeTasks], ); @@ -195,7 +195,6 @@ export function TaskMapAction({ project, projectIsReady, tasks, activeTasks, act } > {editor === 'ID' ? ( - - + diff --git a/frontend/src/components/taskSelection/legend.js b/frontend/src/components/taskSelection/legend.js index f441095c1..e37108509 100644 --- a/frontend/src/components/taskSelection/legend.js +++ b/frontend/src/components/taskSelection/legend.js @@ -19,19 +19,7 @@ export function TasksMapLegend({ imageCaptureMode }) { {expand && (
- {imageCaptureMode && <> -

- -

-

- -

-

- -

- - } - {!imageCaptureMode && (<> + <>

@@ -47,8 +35,21 @@ export function TasksMapLegend({ imageCaptureMode }) {

- ) - } + {imageCaptureMode && ( + <> +

+ +

+

+ +

+

+ +

+ + )} + +

diff --git a/frontend/src/components/taskSelection/map.js b/frontend/src/components/taskSelection/map.js index f65fa4fe1..b0054d284 100644 --- a/frontend/src/components/taskSelection/map.js +++ b/frontend/src/components/taskSelection/map.js @@ -205,8 +205,8 @@ export const TasksMap = ({ TASK_COLOURS.IMAGE_CAPTURE_DONE, 'rgba(0,0,0,0)', ], - 'fill-opacity': ["/", ["*", 2, ["get", "taskId"]], 1000], // Temporary.... creates a gradient - //'fill-opacity': 0.8, + // 'fill-opacity': ['/', ['*', 2, ['get', 'taskId']], 1000], // Temporary.... creates a gradient + 'fill-opacity': 0.8, }, }, 'tasks-icon', diff --git a/frontend/src/components/teamsAndOrgs/teams.js b/frontend/src/components/teamsAndOrgs/teams.js index c1f06dcfa..896037076 100644 --- a/frontend/src/components/teamsAndOrgs/teams.js +++ b/frontend/src/components/teamsAndOrgs/teams.js @@ -57,8 +57,8 @@ export function TeamsManagement({
)} - - + + ); } diff --git a/migrations/versions/7aba630f4265_.py b/migrations/versions/7aba630f4265_.py index 6193e68f2..74fb7c3d8 100644 --- a/migrations/versions/7aba630f4265_.py +++ b/migrations/versions/7aba630f4265_.py @@ -7,26 +7,31 @@ """ from alembic import op import sqlalchemy as sa -from sqlalchemy.dialects import postgresql # revision identifiers, used by Alembic. -revision = '7aba630f4265' -down_revision = '8a6419f289aa' +revision = "7aba630f4265" +down_revision = "8a6419f289aa" branch_labels = None depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.add_column('projects', sa.Column('earliest_street_imagery', sa.DateTime(), nullable=True)) - op.add_column('projects', sa.Column('image_capture_mode', sa.Boolean(), nullable=True)) - op.add_column('projects', sa.Column('mapillary_organization_id', sa.String(), nullable=True)) + op.add_column( + "projects", sa.Column("earliest_street_imagery", sa.DateTime(), nullable=True) + ) + op.add_column( + "projects", sa.Column("image_capture_mode", sa.Boolean(), nullable=True) + ) + op.add_column( + "projects", sa.Column("mapillary_organization_id", sa.String(), nullable=True) + ) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('projects', 'mapillary_organization_id') - op.drop_column('projects', 'image_capture_mode') - op.drop_column('projects', 'earliest_street_imagery') + op.drop_column("projects", "mapillary_organization_id") + op.drop_column("projects", "image_capture_mode") + op.drop_column("projects", "earliest_street_imagery") # ### end Alembic commands ### From e68b1c7a185b425b964434c41cc5a3571f155881 Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Thu, 4 Aug 2022 09:56:45 -0700 Subject: [PATCH 15/25] Mapillary overlay on task map --- frontend/src/assets/img/mapillary-compass.png | Bin 0 -> 2580 bytes .../taskSelection/actionSidebars.js | 8 +- .../taskSelection/filterControls.js | 16 ++ .../src/components/taskSelection/index.js | 3 + .../src/components/taskSelection/legend.js | 3 - frontend/src/components/taskSelection/map.js | 169 +++++++++++++++++- .../src/components/taskSelection/messages.js | 5 + 7 files changed, 196 insertions(+), 8 deletions(-) create mode 100644 frontend/src/assets/img/mapillary-compass.png create mode 100644 frontend/src/components/taskSelection/filterControls.js diff --git a/frontend/src/assets/img/mapillary-compass.png b/frontend/src/assets/img/mapillary-compass.png new file mode 100644 index 0000000000000000000000000000000000000000..a0130dcc8c927baf272db587cc577991a8a6cf7a GIT binary patch literal 2580 zcmZ`*c|25WA3wv0xQUCa7@5ctnXzRV!;pFH%Vf!(^g@l07y~=06GHz7I`lEGyueE z1Hfzm0AS7lfGqi3{cbD|Ab_5>p^lD#2G14&1Yo}df;ig0AIBMfR~9k1evfO zC{y4&YQq%#Ve^S;bK&m*KtP-5=1KE(bif41kWhgkF+m_IfkfsL0Biz=XOci#ATogz z6%An$OqEs{7@o~{qm_`W6k4RIlBXj9X&FNWkp?Jjl(v$YC=!XpQbR&9E_kbN;k=cp zQaFu9#-P#h@$sm5JyZ-e46S2qY>d{{MeFKn@fccAVl*uQqM>iw;%yMkN6!dCaS zCWqxG!w`rGV3Zf0NCKlFUTJ2Ay4Y2fe*iz~Tnn^}iHf1Rk^_T5Go5cCKe_&wy(;7R zE192wp91++W1Oi(kk?Rt+xR;F@O|TB(fpqN)Z?`ST=nu!&`cDI{(c+GMB6lyg8@KT z*cNZ$mH^`x_(e&(OVgj6{~BfQ!<6t&bGu4pu|zgWG~@Atl8H$CA?qU>7u{x^Ul~di zOZX6^m{^IFAnm8Z5%49ty0mOJAfx0rcLlv%*R?a5o5*B@r%^6bIiiokfA@t#CotZ_7)ve=7(Db#t>?KtUQHX z{W&(U5i8pA+s6toBAq^{^qf}gz5(^ThgzHH)BaKg1~^Hz6Qu|5I&J;i&(V<6v}Y%K z0LVTN++4f+!kh;UcBz2g-X4cJ8&}VWl$$mj5zLcD#N}l3m)0-|iiD(9(2F z0Inso6Bq38e&+4y)*Xv#hH(hvN2J0H62^Th(J?1<+CP0&d+vq6mJaXU?^^Ux*fmFn z5cZ{=DRB$b7AN=0)DQK%yST6}1JxkD$DGypjz&YTi!y82>fUcO-@9|~wZR*9I1}XC zq~cAPCA%kX`JuboBAKE=pQvS#2h69v$V=r?M(E`BiI9|}?uW9??+Z>Y4^OFk2pmRa zwmk6mmZumcq7_*3q>_ey(=N8O6Bz0@jPsjmOJr-OCo)wgsbx@Bt$}cj;_@+j|CFS> zY^3gh=ZMYgO8e!_&eaIzd*<^Kcj8qz2ei3)0%;m6q^!}7b>jr3*h{F6q*yfC22i&aDul6AMyRii!i-FMBl6g8%0dWFy~m1qHLu^tDFbL_*H;h={9){A0d~r&g~E z->{JGPMv;rjJ$f3#pze$)*R904w#~Hyx z7Y-dH&n+h2MfA{zZ6)QfdPIY~$DR~f^)%@t_zN9vZ2=pVJDs+}@bh>I<=tk69w%y! zeBUc!#6#%3uw{w!t}hlF}`t z-Umz}pnXe;9{TWxWnpg14IgiBD~_0PnHOwgauU_5CbuFaoV{hyoAPL5|7$u;KFy$_ zHEVOlQ0*j^EpV@}#`9B)dRN`Z73|rr+%C(MKJS9(B%f$ZZGaGia&yAO!GfvrZjiuy`7_O)E!L46R(%PBP>bl(TlbKUpUKx{GTj;K!wom_;Cj631-$MulQjy1yu z`F?xMKTB&hub+U_!DcNMG_Z$nZ>}g=yasDZJgtIb z7?^N4oEvrAT(dpqQmPI}qovMcF6_+r#=a*`6~I6h&AHi6*^0QYr*G$u7syB$Gp=Qr z=A~($E8dN7N1?n7BV}IYbY$OnZ6ELUQ0$EJ0PN!g_(E^V_N=*GoUu$#;1i9aE~v$vO>Tg+IIwZlZtkTbgA71EHwXBd<8cM_Tt~Ncb6gEi`QyyW!U&oEEY>9~M+vzsd zp*oX_F>l}B;Xl4OLt*LHpa;Pn%O>TW&XJnfJ{Lxbh6tj~df|foU6s+_$?I$3z5*y% gKK)nA^n$xM)$5DO3=d0X{!f$bznt)8y8_bw14|Y`ZvX%Q literal 0 HcmV?d00001 diff --git a/frontend/src/components/taskSelection/actionSidebars.js b/frontend/src/components/taskSelection/actionSidebars.js index 845b9f7cc..7e2dec543 100644 --- a/frontend/src/components/taskSelection/actionSidebars.js +++ b/frontend/src/components/taskSelection/actionSidebars.js @@ -418,8 +418,9 @@ export function CompletionTabForValidation({

+

- +

{tasksIds.length > 3 && (
@@ -579,9 +580,8 @@ const TaskValidationSelector = ({ setShowCommentInput(!showCommentInput)} icon={ comment ? ( diff --git a/frontend/src/components/taskSelection/filterControls.js b/frontend/src/components/taskSelection/filterControls.js new file mode 100644 index 000000000..ea9fd0398 --- /dev/null +++ b/frontend/src/components/taskSelection/filterControls.js @@ -0,0 +1,16 @@ +import React, { useState } from 'react'; +import { SwitchToggle } from '../formInputs'; + +export function TasksMapFilterControls({ state, changeState }) { + const lineClasses = 'mv2 blue-dark f5'; + return ( +
+ {changeState()}} + /> +
+ ); +} diff --git a/frontend/src/components/taskSelection/index.js b/frontend/src/components/taskSelection/index.js index ae5090f66..f5af554e8 100644 --- a/frontend/src/components/taskSelection/index.js +++ b/frontend/src/components/taskSelection/index.js @@ -23,6 +23,7 @@ import { ChangesetCommentTags } from './changesetComment'; import { ProjectHeader } from '../projectDetail/header'; import Contributions from './contributions'; import { UserPermissionErrorContent } from './permissionErrorModal'; +import { TasksMapFilterControls } from './filterControls'; const TaskSelectionFooter = React.lazy(() => import('./footer')); @@ -367,6 +368,8 @@ export function TaskSelection({ project, type, loading }: Object) { taskBordersOnly={false} priorityAreas={priorityAreas} animateZoom={false} + earliestStreetImagery={project.earliestStreetImagery} + mapillaryOrganizationId={parseInt(project.mapillaryOrganizationId) || 0} /> diff --git a/frontend/src/components/taskSelection/legend.js b/frontend/src/components/taskSelection/legend.js index e37108509..8b4ce3593 100644 --- a/frontend/src/components/taskSelection/legend.js +++ b/frontend/src/components/taskSelection/legend.js @@ -19,7 +19,6 @@ export function TasksMapLegend({ imageCaptureMode }) { {expand && (
- <>

@@ -48,8 +47,6 @@ export function TasksMapLegend({ imageCaptureMode }) {

)} - -

diff --git a/frontend/src/components/taskSelection/map.js b/frontend/src/components/taskSelection/map.js index b0054d284..75d1f0b79 100644 --- a/frontend/src/components/taskSelection/map.js +++ b/frontend/src/components/taskSelection/map.js @@ -5,12 +5,16 @@ import mapboxgl from 'mapbox-gl'; import 'mapbox-gl/dist/mapbox-gl.css'; import MapboxLanguage from '@mapbox/mapbox-gl-language'; import { FormattedMessage } from 'react-intl'; - import WebglUnsupported from '../webglUnsupported'; import messages from './messages'; import { MAPBOX_TOKEN, TASK_COLOURS, MAP_STYLE, MAPBOX_RTL_PLUGIN_URL } from '../../config'; import lock from '../../assets/img/lock.png'; import redlock from '../../assets/img/red-lock.png'; +import axios from 'axios'; +import compassIcon from '../../assets/img/mapillary-compass.png'; +import { SwitchToggle } from '../formInputs'; + + let lockIcon = new Image(17, 20); lockIcon.src = lock; @@ -39,6 +43,8 @@ export const TasksMap = ({ animateZoom = true, showTaskIds = false, selected: selectedOnMap, + earliestStreetImagery = '1970-01-01T00:00:00.000000Z', + mapillaryOrganizationId, }) => { const mapRef = React.createRef(); const locale = useSelector((state) => state.preferences['locale']); @@ -70,6 +76,8 @@ export const TasksMap = ({ // eslint-disable-next-line }, []); + console.log(mapResults); + useLayoutEffect(() => { // should run only when triggered from tasks list if (typeof zoomedTaskId === 'number') { @@ -164,6 +172,19 @@ export const TasksMap = ({ } taskStatusCondition = [...taskStatusCondition, ...[locked, 'lock', '']]; + + map.addControl( + new mapboxgl.GeolocateControl({ + positionOptions: { + enableHighAccuracy: true + }, + // When active the map will receive updates to the device's location as it changes. + trackUserLocation: true, + // Draw an arrow next to the location dot to indicate which direction the device is heading. + showUserHeading: true + }) + ); + map.addLayer({ id: 'tasks-icon', type: 'symbol', @@ -212,6 +233,38 @@ export const TasksMap = ({ 'tasks-icon', ); + map.addSource('mapillary', { + type: 'vector', + tiles: ['https://tiles.mapillary.com/maps/vtp/mly1_public/2/{z}/{x}/{y}?access_token=MLY|5458526104199012|c91f32db4e70dcd39a263dce9aa7f261'], + minzoom: 1, + maxzoom: 14 + }); + + map.addLayer({ + id: 'mapillary-sequences', + type: 'line', + source: 'mapillary', + 'source-layer': 'sequence', + layout: { + 'line-join': 'round', + 'line-cap': 'round', + }, + paint: { + 'line-color': ['case', ['within', mapResults.features[0]], '#000000', '#ff0000'], + 'line-width': 2 + } + }); + map.addLayer({ + id: 'mapillary-images', + type: 'circle', + source: 'mapillary', + 'source-layer': 'image', + paint: { + 'circle-color': '#05CB63', + 'circle-radius': 5, + } + }); + map.addLayer({ id: 'selected-tasks-border', type: 'line', @@ -390,6 +443,120 @@ export const TasksMap = ({ map.getCanvas().style.cursor = 'pointer'; } }); + + map.loadImage(compassIcon, (error, image) => { + if (error) throw error; + + if (!map.hasImage('compass')) { + map.addImage('compass', image); + } + + if (!map.getSource('point')) { + map.addSource('point', { + 'type': 'geojson', + 'data': { + 'type': 'FeatureCollection', + 'features': [ + { + 'type': 'Feature', + 'geometry': { + 'type': 'Point', + 'coordinates': [0, 0] + } + } + ] + } + }); + } + + if (!map.getLayer('mapillary-compass')) { + map.addLayer({ + 'id': 'mapillary-compass', + 'type': 'symbol', + 'source': 'point', // reference the data source + 'layout': { + 'icon-image': 'compass', // reference the image + 'icon-size': 0.5, + 'visibility': 'none' + } + }); + } + }) + + + + const popup = new mapboxgl.Popup({ + closeButton: true, + closeOnClick: false + }); + + function displayMapPopup(e) { + popup.remove(); + + map.getCanvas().style.cursor = 'pointer'; + let imageObj = e.features[0].properties; + + console.log(e.features); + + axios.get(`https://graph.mapillary.com/${imageObj.id}?fields=thumb_256_url,computed_compass_angle,camera_type`, { + headers: { + 'Authorization': "OAuth MLY|5494923973921616|75ede84ae518fed4232a6e7eb7d53688" + } + }).then(resp => { + popup.setLngLat([e.lngLat.lng, e.lngLat.lat]).setHTML(``).addTo(map); + + const geoJsonData = { + 'type': 'FeatureCollection', + 'features': [ + { + 'type': 'Feature', + 'geometry': { + 'type': 'Point', + 'coordinates': [e.lngLat.lng, e.lngLat.lat] + } + } + ] + } + + + map.getSource('point').setData(geoJsonData); + map.setLayoutProperty('mapillary-compass', 'visibility', 'visible'); + map.setLayoutProperty('mapillary-compass', 'icon-rotate', resp.data.computed_compass_angle); + }); + } + map.on('mousemove', 'mapillary-images', (e) => displayMapPopup(e)); + popup.on('close', () => map.setLayoutProperty('mapillary-compass', 'visibility', 'none')); + + map.on('mouseenter', 'mapillary-sequences', (e) => console.log(e)); + + + // map.on('idle', () => { + // mapillaryLayer ? map.setLayoutProperty('mapillary-images', 'visibility', 'visible') : map.setLayoutProperty('mapillary-images', 'visibility', 'none') + // mapillaryLayer ? map.setLayoutProperty('mapillary-sequences', 'visibility', 'visible') : map.setLayoutProperty('mapillary-sequences', 'visibility', 'none') + // }); + + map.setFilter( + 'mapillary-images', + ['all', ['>=', ['get', 'captured_at'], new Date(earliestStreetImagery).getTime()]] + ); + + map.setFilter( + 'mapillary-sequences', + ['all', ['>=', ['get', 'captured_at'], new Date(earliestStreetImagery).getTime()]] + ); + + if (mapillaryOrganizationId > 0) { + map.setFilter( + 'mapillary-images', + ['all', ['==', ['get', 'organization_id'], mapillaryOrganizationId]] + ); + + map.setFilter( + 'mapillary-sequences', + ['all', ['==', ['get', 'organization_id'], mapillaryOrganizationId]] + ); + } + map.on('click', 'tasks-fill', onSelectTaskClick); map.on('mouseleave', 'tasks-fill', function (e) { // Change the cursor style as a UI indicator. diff --git a/frontend/src/components/taskSelection/messages.js b/frontend/src/components/taskSelection/messages.js index 09de65e5e..4cf5ea8be 100644 --- a/frontend/src/components/taskSelection/messages.js +++ b/frontend/src/components/taskSelection/messages.js @@ -506,6 +506,11 @@ export default defineMessages({ defaultMessage: '{number, plural, one {Is this task well mapped?} other {Are these tasks well mapped?}}', }, + validatedImageQuestion: { + id: 'project.tasks.action.options.validated_image_question', + defaultMessage: + '{number, plural, one {Is imagery capture complete for this task?} other {Is imagery capture complete for hese tasks?}}', + }, complete: { id: 'project.tasks.action.options.complete', defaultMessage: 'Yes', From 762c995abb299836c836cf85881859e5980ffa86 Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Thu, 4 Aug 2022 10:04:27 -0700 Subject: [PATCH 16/25] Moved compass icon loading to load event --- frontend/src/components/taskSelection/map.js | 73 +++++++++----------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/frontend/src/components/taskSelection/map.js b/frontend/src/components/taskSelection/map.js index 75d1f0b79..1cdb1a582 100644 --- a/frontend/src/components/taskSelection/map.js +++ b/frontend/src/components/taskSelection/map.js @@ -178,9 +178,7 @@ export const TasksMap = ({ positionOptions: { enableHighAccuracy: true }, - // When active the map will receive updates to the device's location as it changes. trackUserLocation: true, - // Draw an arrow next to the location dot to indicate which direction the device is heading. showUserHeading: true }) ); @@ -265,6 +263,40 @@ export const TasksMap = ({ } }); + map.loadImage(compassIcon, (error, image) => { + if (error) throw error; + + map.addImage('compass', image); + + }) + + map.addSource('point', { + 'type': 'geojson', + 'data': { + 'type': 'FeatureCollection', + 'features': [ + { + 'type': 'Feature', + 'geometry': { + 'type': 'Point', + 'coordinates': [0, 0] + } + } + ] + } + }); + + map.addLayer({ + 'id': 'mapillary-compass', + 'type': 'symbol', + 'source': 'point', // reference the data source + 'layout': { + 'icon-image': 'compass', // reference the image + 'icon-size': 0.5, + 'visibility': 'none' + } + }) + map.addLayer({ id: 'selected-tasks-border', type: 'line', @@ -444,44 +476,7 @@ export const TasksMap = ({ } }); - map.loadImage(compassIcon, (error, image) => { - if (error) throw error; - if (!map.hasImage('compass')) { - map.addImage('compass', image); - } - - if (!map.getSource('point')) { - map.addSource('point', { - 'type': 'geojson', - 'data': { - 'type': 'FeatureCollection', - 'features': [ - { - 'type': 'Feature', - 'geometry': { - 'type': 'Point', - 'coordinates': [0, 0] - } - } - ] - } - }); - } - - if (!map.getLayer('mapillary-compass')) { - map.addLayer({ - 'id': 'mapillary-compass', - 'type': 'symbol', - 'source': 'point', // reference the data source - 'layout': { - 'icon-image': 'compass', // reference the image - 'icon-size': 0.5, - 'visibility': 'none' - } - }); - } - }) From 1e32e740e3aee28b2fa2703e45fbf998439ce2d4 Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Thu, 4 Aug 2022 10:09:19 -0700 Subject: [PATCH 17/25] Update map.js removed prototyping color --- frontend/src/components/taskSelection/map.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/frontend/src/components/taskSelection/map.js b/frontend/src/components/taskSelection/map.js index 1cdb1a582..9dc0773a0 100644 --- a/frontend/src/components/taskSelection/map.js +++ b/frontend/src/components/taskSelection/map.js @@ -248,7 +248,7 @@ export const TasksMap = ({ 'line-cap': 'round', }, paint: { - 'line-color': ['case', ['within', mapResults.features[0]], '#000000', '#ff0000'], + 'line-color': '#05CB63', 'line-width': 2 } }); @@ -476,10 +476,6 @@ export const TasksMap = ({ } }); - - - - const popup = new mapboxgl.Popup({ closeButton: true, closeOnClick: false From 9edb7bea22bc706b84b019c544592dccb15c64d3 Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Thu, 4 Aug 2022 10:40:57 -0700 Subject: [PATCH 18/25] Visibility toggle --- frontend/src/components/taskSelection/map.js | 24 +++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/taskSelection/map.js b/frontend/src/components/taskSelection/map.js index 9dc0773a0..76876fbe5 100644 --- a/frontend/src/components/taskSelection/map.js +++ b/frontend/src/components/taskSelection/map.js @@ -267,7 +267,6 @@ export const TasksMap = ({ if (error) throw error; map.addImage('compass', image); - }) map.addSource('point', { @@ -289,9 +288,9 @@ export const TasksMap = ({ map.addLayer({ 'id': 'mapillary-compass', 'type': 'symbol', - 'source': 'point', // reference the data source + 'source': 'point', 'layout': { - 'icon-image': 'compass', // reference the image + 'icon-image': 'compass', 'icon-size': 0.5, 'visibility': 'none' } @@ -521,10 +520,13 @@ export const TasksMap = ({ map.on('mouseenter', 'mapillary-sequences', (e) => console.log(e)); - // map.on('idle', () => { - // mapillaryLayer ? map.setLayoutProperty('mapillary-images', 'visibility', 'visible') : map.setLayoutProperty('mapillary-images', 'visibility', 'none') - // mapillaryLayer ? map.setLayoutProperty('mapillary-sequences', 'visibility', 'visible') : map.setLayoutProperty('mapillary-sequences', 'visibility', 'none') - // }); + map.on('idle', () => { + let element = document.getElementById("mapillary-toggle"); + let visibility = element ? element.checked : false; + + visibility ? map.setLayoutProperty('mapillary-images', 'visibility', 'visible') : map.setLayoutProperty('mapillary-images', 'visibility', 'none') + visibility ? map.setLayoutProperty('mapillary-sequences', 'visibility', 'visible') : map.setLayoutProperty('mapillary-sequences', 'visibility', 'none') + }); map.setFilter( 'mapillary-images', @@ -640,7 +642,13 @@ export const TasksMap = ({
)} -
+
+
+ + + +
+
); } From c4b94ed4494c215781fef18fc8c6f00ce4f17e9d Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Thu, 4 Aug 2022 11:12:07 -0700 Subject: [PATCH 19/25] Redirect to mapillary app on ios/android --- frontend/src/components/taskSelection/footer.js | 9 +++++++++ frontend/src/components/taskSelection/map.js | 14 ++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/taskSelection/footer.js b/frontend/src/components/taskSelection/footer.js index 62e78bcef..edfccecaf 100644 --- a/frontend/src/components/taskSelection/footer.js +++ b/frontend/src/components/taskSelection/footer.js @@ -110,6 +110,15 @@ const TaskSelectionFooter = ({ defaultUserEditor, project, tasks, taskAction, se } }) .catch((e) => lockFailed(windowObjectReference, e.message)); + + if (project.imageCaptureMode) { + if (navigator.userAgent.includes("Android")) { + navigate("mapillary://mapillary/explore") + } + else if (navigator.userAgent.includes("like Mac OS X")) { + navigate("mapillary://goto/camera") + } + } } if (['resumeMapping', 'resumeValidation'].includes(taskAction)) { const urlParams = openEditor( diff --git a/frontend/src/components/taskSelection/map.js b/frontend/src/components/taskSelection/map.js index 76876fbe5..af780b72b 100644 --- a/frontend/src/components/taskSelection/map.js +++ b/frontend/src/components/taskSelection/map.js @@ -644,12 +644,10 @@ export const TasksMap = ({ )}
- - - + +
-
- - ); - } -}; +
+ + )} +} From f11b29a8d271571123956abe8a9c97c049ee6f0d Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Mon, 8 Aug 2022 15:26:55 -0700 Subject: [PATCH 20/25] Fixed react warnings, ran yarn prettier --- .../components/projectCreate/trimProject.js | 34 ++-- .../taskSelection/actionSidebars.js | 14 +- .../taskSelection/filterControls.js | 16 -- .../src/components/taskSelection/footer.js | 9 +- .../src/components/taskSelection/index.js | 3 +- .../src/components/taskSelection/legend.js | 56 +++--- frontend/src/components/taskSelection/map.js | 187 ++++++++++-------- 7 files changed, 163 insertions(+), 156 deletions(-) delete mode 100644 frontend/src/components/taskSelection/filterControls.js diff --git a/frontend/src/components/projectCreate/trimProject.js b/frontend/src/components/projectCreate/trimProject.js index 841d2b4aa..10fba5f5e 100644 --- a/frontend/src/components/projectCreate/trimProject.js +++ b/frontend/src/components/projectCreate/trimProject.js @@ -76,23 +76,23 @@ export default function TrimProject({ metadata, mapObj, updateMetadata }) { label={} /> -
- { - setWaterStatus(!waterStatus); - }} - label={} - /> -
-
- { - setRoadStatus(!roadStatus); - }} +
+ { + setWaterStatus(!waterStatus); + }} + label={} + /> +
+
+ { + setRoadStatus(!roadStatus); + }} label={} />
diff --git a/frontend/src/components/taskSelection/actionSidebars.js b/frontend/src/components/taskSelection/actionSidebars.js index 7e2dec543..a05e4db71 100644 --- a/frontend/src/components/taskSelection/actionSidebars.js +++ b/frontend/src/components/taskSelection/actionSidebars.js @@ -418,9 +418,14 @@ export function CompletionTabForValidation({

- +

- +

{tasksIds.length > 3 && (
@@ -580,8 +585,9 @@ const TaskValidationSelector = ({ setShowCommentInput(!showCommentInput)} icon={ comment ? ( diff --git a/frontend/src/components/taskSelection/filterControls.js b/frontend/src/components/taskSelection/filterControls.js deleted file mode 100644 index ea9fd0398..000000000 --- a/frontend/src/components/taskSelection/filterControls.js +++ /dev/null @@ -1,16 +0,0 @@ -import React, { useState } from 'react'; -import { SwitchToggle } from '../formInputs'; - -export function TasksMapFilterControls({ state, changeState }) { - const lineClasses = 'mv2 blue-dark f5'; - return ( -
- {changeState()}} - /> -
- ); -} diff --git a/frontend/src/components/taskSelection/footer.js b/frontend/src/components/taskSelection/footer.js index edfccecaf..a8e4f81ea 100644 --- a/frontend/src/components/taskSelection/footer.js +++ b/frontend/src/components/taskSelection/footer.js @@ -112,11 +112,10 @@ const TaskSelectionFooter = ({ defaultUserEditor, project, tasks, taskAction, se .catch((e) => lockFailed(windowObjectReference, e.message)); if (project.imageCaptureMode) { - if (navigator.userAgent.includes("Android")) { - navigate("mapillary://mapillary/explore") - } - else if (navigator.userAgent.includes("like Mac OS X")) { - navigate("mapillary://goto/camera") + if (navigator.userAgent.includes('Android')) { + navigate('mapillary://mapillary/explore'); + } else if (navigator.userAgent.includes('like Mac OS X')) { + navigate('mapillary://goto/camera'); } } } diff --git a/frontend/src/components/taskSelection/index.js b/frontend/src/components/taskSelection/index.js index f5af554e8..71cf8b377 100644 --- a/frontend/src/components/taskSelection/index.js +++ b/frontend/src/components/taskSelection/index.js @@ -23,7 +23,6 @@ import { ChangesetCommentTags } from './changesetComment'; import { ProjectHeader } from '../projectDetail/header'; import Contributions from './contributions'; import { UserPermissionErrorContent } from './permissionErrorModal'; -import { TasksMapFilterControls } from './filterControls'; const TaskSelectionFooter = React.lazy(() => import('./footer')); @@ -368,7 +367,7 @@ export function TaskSelection({ project, type, loading }: Object) { taskBordersOnly={false} priorityAreas={priorityAreas} animateZoom={false} - earliestStreetImagery={project.earliestStreetImagery} + earliestStreetImagery={project.earliestStreetImagery} mapillaryOrganizationId={parseInt(project.mapillaryOrganizationId) || 0} /> diff --git a/frontend/src/components/taskSelection/legend.js b/frontend/src/components/taskSelection/legend.js index 8b4ce3593..d2ef76cf1 100644 --- a/frontend/src/components/taskSelection/legend.js +++ b/frontend/src/components/taskSelection/legend.js @@ -19,34 +19,34 @@ export function TasksMapLegend({ imageCaptureMode }) { {expand && (
-

- -

-

- -

-

- -

-

- -

-

- -

- {imageCaptureMode && ( - <> -

- -

-

- -

-

- -

- - )} +

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+ {imageCaptureMode && ( + <> +

+ +

+

+ +

+

+ +

+ + )}

diff --git a/frontend/src/components/taskSelection/map.js b/frontend/src/components/taskSelection/map.js index af780b72b..2e1aadbce 100644 --- a/frontend/src/components/taskSelection/map.js +++ b/frontend/src/components/taskSelection/map.js @@ -12,9 +12,6 @@ import lock from '../../assets/img/lock.png'; import redlock from '../../assets/img/red-lock.png'; import axios from 'axios'; import compassIcon from '../../assets/img/mapillary-compass.png'; -import { SwitchToggle } from '../formInputs'; - - let lockIcon = new Image(17, 20); lockIcon.src = lock; @@ -172,15 +169,14 @@ export const TasksMap = ({ } taskStatusCondition = [...taskStatusCondition, ...[locked, 'lock', '']]; - map.addControl( new mapboxgl.GeolocateControl({ positionOptions: { - enableHighAccuracy: true + enableHighAccuracy: true, }, trackUserLocation: true, - showUserHeading: true - }) + showUserHeading: true, + }), ); map.addLayer({ @@ -233,9 +229,11 @@ export const TasksMap = ({ map.addSource('mapillary', { type: 'vector', - tiles: ['https://tiles.mapillary.com/maps/vtp/mly1_public/2/{z}/{x}/{y}?access_token=MLY|5458526104199012|c91f32db4e70dcd39a263dce9aa7f261'], + tiles: [ + 'https://tiles.mapillary.com/maps/vtp/mly1_public/2/{z}/{x}/{y}?access_token=MLY|5458526104199012|c91f32db4e70dcd39a263dce9aa7f261', + ], minzoom: 1, - maxzoom: 14 + maxzoom: 14, }); map.addLayer({ @@ -249,8 +247,8 @@ export const TasksMap = ({ }, paint: { 'line-color': '#05CB63', - 'line-width': 2 - } + 'line-width': 2, + }, }); map.addLayer({ id: 'mapillary-images', @@ -260,41 +258,41 @@ export const TasksMap = ({ paint: { 'circle-color': '#05CB63', 'circle-radius': 5, - } + }, }); map.loadImage(compassIcon, (error, image) => { if (error) throw error; map.addImage('compass', image); - }) + }); map.addSource('point', { - 'type': 'geojson', - 'data': { - 'type': 'FeatureCollection', - 'features': [ + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [ { - 'type': 'Feature', - 'geometry': { - 'type': 'Point', - 'coordinates': [0, 0] - } - } - ] - } + type: 'Feature', + geometry: { + type: 'Point', + coordinates: [0, 0], + }, + }, + ], + }, }); map.addLayer({ - 'id': 'mapillary-compass', - 'type': 'symbol', - 'source': 'point', - 'layout': { + id: 'mapillary-compass', + type: 'symbol', + source: 'point', + layout: { 'icon-image': 'compass', 'icon-size': 0.5, - 'visibility': 'none' - } - }) + visibility: 'none', + }, + }); map.addLayer({ id: 'selected-tasks-border', @@ -477,7 +475,7 @@ export const TasksMap = ({ const popup = new mapboxgl.Popup({ closeButton: true, - closeOnClick: false + closeOnClick: false, }); function displayMapPopup(e) { @@ -488,66 +486,80 @@ export const TasksMap = ({ console.log(e.features); - axios.get(`https://graph.mapillary.com/${imageObj.id}?fields=thumb_256_url,computed_compass_angle,camera_type`, { - headers: { - 'Authorization': "OAuth MLY|5494923973921616|75ede84ae518fed4232a6e7eb7d53688" - } - }).then(resp => { - popup.setLngLat([e.lngLat.lng, e.lngLat.lat]).setHTML(``).addTo(map); - - const geoJsonData = { - 'type': 'FeatureCollection', - 'features': [ - { - 'type': 'Feature', - 'geometry': { - 'type': 'Point', - 'coordinates': [e.lngLat.lng, e.lngLat.lat] - } - } - ] - } - + axios + .get( + `https://graph.mapillary.com/${imageObj.id}?fields=thumb_256_url,computed_compass_angle,camera_type`, + { + headers: { + Authorization: 'OAuth MLY|5494923973921616|75ede84ae518fed4232a6e7eb7d53688', + }, + }, + ) + .then((resp) => { + popup + .setLngLat([e.lngLat.lng, e.lngLat.lat]) + .setHTML(``) + .addTo(map); + + const geoJsonData = { + type: 'FeatureCollection', + features: [ + { + type: 'Feature', + geometry: { + type: 'Point', + coordinates: [e.lngLat.lng, e.lngLat.lat], + }, + }, + ], + }; - map.getSource('point').setData(geoJsonData); - map.setLayoutProperty('mapillary-compass', 'visibility', 'visible'); - map.setLayoutProperty('mapillary-compass', 'icon-rotate', resp.data.computed_compass_angle); - }); + map.getSource('point').setData(geoJsonData); + map.setLayoutProperty('mapillary-compass', 'visibility', 'visible'); + map.setLayoutProperty( + 'mapillary-compass', + 'icon-rotate', + resp.data.computed_compass_angle, + ); + }); } map.on('mousemove', 'mapillary-images', (e) => displayMapPopup(e)); popup.on('close', () => map.setLayoutProperty('mapillary-compass', 'visibility', 'none')); map.on('mouseenter', 'mapillary-sequences', (e) => console.log(e)); - map.on('idle', () => { - let element = document.getElementById("mapillary-toggle"); + let element = document.getElementById('mapillary-toggle'); let visibility = element ? element.checked : false; - visibility ? map.setLayoutProperty('mapillary-images', 'visibility', 'visible') : map.setLayoutProperty('mapillary-images', 'visibility', 'none') - visibility ? map.setLayoutProperty('mapillary-sequences', 'visibility', 'visible') : map.setLayoutProperty('mapillary-sequences', 'visibility', 'none') + visibility + ? map.setLayoutProperty('mapillary-images', 'visibility', 'visible') + : map.setLayoutProperty('mapillary-images', 'visibility', 'none'); + visibility + ? map.setLayoutProperty('mapillary-sequences', 'visibility', 'visible') + : map.setLayoutProperty('mapillary-sequences', 'visibility', 'none'); }); - map.setFilter( - 'mapillary-images', - ['all', ['>=', ['get', 'captured_at'], new Date(earliestStreetImagery).getTime()]] - ); + map.setFilter('mapillary-images', [ + 'all', + ['>=', ['get', 'captured_at'], new Date(earliestStreetImagery).getTime()], + ]); - map.setFilter( - 'mapillary-sequences', - ['all', ['>=', ['get', 'captured_at'], new Date(earliestStreetImagery).getTime()]] - ); + map.setFilter('mapillary-sequences', [ + 'all', + ['>=', ['get', 'captured_at'], new Date(earliestStreetImagery).getTime()], + ]); if (mapillaryOrganizationId > 0) { - map.setFilter( - 'mapillary-images', - ['all', ['==', ['get', 'organization_id'], mapillaryOrganizationId]] - ); - - map.setFilter( - 'mapillary-sequences', - ['all', ['==', ['get', 'organization_id'], mapillaryOrganizationId]] - ); + map.setFilter('mapillary-images', [ + 'all', + ['==', ['get', 'organization_id'], mapillaryOrganizationId], + ]); + + map.setFilter('mapillary-sequences', [ + 'all', + ['==', ['get', 'organization_id'], mapillaryOrganizationId], + ]); } map.on('click', 'tasks-fill', onSelectTaskClick); @@ -630,6 +642,8 @@ export const TasksMap = ({ authDetails.id, showTaskIds, zoomedTaskId, + earliestStreetImagery, + mapillaryOrganizationId, ]); if (!mapboxgl.supported()) { @@ -643,11 +657,16 @@ export const TasksMap = ({
)}
-
+
- +
-
- - )} -} +
+ + ); + } +}; From 857807ddc0fac7f41005cb9add70f128ccc4c183 Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Wed, 10 Aug 2022 12:41:21 -0700 Subject: [PATCH 21/25] Update frontend/src/components/taskSelection/footer.js Co-authored-by: Zack LaVergne --- frontend/src/components/taskSelection/footer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/taskSelection/footer.js b/frontend/src/components/taskSelection/footer.js index a8e4f81ea..24ab7351c 100644 --- a/frontend/src/components/taskSelection/footer.js +++ b/frontend/src/components/taskSelection/footer.js @@ -114,7 +114,7 @@ const TaskSelectionFooter = ({ defaultUserEditor, project, tasks, taskAction, se if (project.imageCaptureMode) { if (navigator.userAgent.includes('Android')) { navigate('mapillary://mapillary/explore'); - } else if (navigator.userAgent.includes('like Mac OS X')) { + } else if (navigator.userAgent.includes('iPad|iPhone|iPod')) { navigate('mapillary://goto/camera'); } } From da14707b21c971ecd5d1b97b834161bc15fc725c Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Wed, 10 Aug 2022 13:02:35 -0700 Subject: [PATCH 22/25] Mapillary tokens in env; mapbox reorganize --- frontend/.env.expand | 1 + frontend/src/components/taskSelection/map.js | 57 +++++++++----------- frontend/src/config/index.js | 5 +- 3 files changed, 31 insertions(+), 32 deletions(-) diff --git a/frontend/.env.expand b/frontend/.env.expand index 3247d4410..916ae8ead 100644 --- a/frontend/.env.expand +++ b/frontend/.env.expand @@ -42,3 +42,4 @@ REACT_APP_SENTRY_FRONTEND_DSN=$TM_SENTRY_FRONTEND_DSN REACT_APP_ENVIRONMENT=$TM_ENVIRONMENT REACT_APP_TM_DEFAULT_CHANGESET_COMMENT=$TM_DEFAULT_CHANGESET_COMMENT REACT_APP_RAPID_EDITOR_URL=$RAPID_EDITOR_URL +REACT_APP_MAPILLARY_TOKEN=$MAPILLARY_ACCESS_TOKEN \ No newline at end of file diff --git a/frontend/src/components/taskSelection/map.js b/frontend/src/components/taskSelection/map.js index 2e1aadbce..1bbb0f930 100644 --- a/frontend/src/components/taskSelection/map.js +++ b/frontend/src/components/taskSelection/map.js @@ -7,7 +7,7 @@ import MapboxLanguage from '@mapbox/mapbox-gl-language'; import { FormattedMessage } from 'react-intl'; import WebglUnsupported from '../webglUnsupported'; import messages from './messages'; -import { MAPBOX_TOKEN, TASK_COLOURS, MAP_STYLE, MAPBOX_RTL_PLUGIN_URL } from '../../config'; +import { MAPBOX_TOKEN, TASK_COLOURS, MAP_STYLE, MAPBOX_RTL_PLUGIN_URL, MAPILLARY_TOKEN } from '../../config'; import lock from '../../assets/img/lock.png'; import redlock from '../../assets/img/red-lock.png'; import axios from 'axios'; @@ -73,8 +73,6 @@ export const TasksMap = ({ // eslint-disable-next-line }, []); - console.log(mapResults); - useLayoutEffect(() => { // should run only when triggered from tasks list if (typeof zoomedTaskId === 'number') { @@ -230,7 +228,7 @@ export const TasksMap = ({ map.addSource('mapillary', { type: 'vector', tiles: [ - 'https://tiles.mapillary.com/maps/vtp/mly1_public/2/{z}/{x}/{y}?access_token=MLY|5458526104199012|c91f32db4e70dcd39a263dce9aa7f261', + `https://tiles.mapillary.com/maps/vtp/mly1_public/2/{z}/{x}/{y}?access_token=${MAPILLARY_TOKEN}`, ], minzoom: 1, maxzoom: 14, @@ -322,6 +320,29 @@ export const TasksMap = ({ ); } + map.setFilter('mapillary-images', [ + 'all', + ['>=', ['get', 'captured_at'], new Date(earliestStreetImagery).getTime()], + ]); + + map.setFilter('mapillary-sequences', [ + 'all', + ['>=', ['get', 'captured_at'], new Date(earliestStreetImagery).getTime()], + ]); + + if (mapillaryOrganizationId > 0) { + map.setFilter('mapillary-images', [ + 'all', + ['==', ['get', 'organization_id'], mapillaryOrganizationId], + ]); + + map.setFilter('mapillary-sequences', [ + 'all', + ['==', ['get', 'organization_id'], mapillaryOrganizationId], + ]); + } + + if (map.getSource('tasks-outline') === undefined && taskBordersMap) { map.addSource('tasks-outline', { type: 'geojson', @@ -484,14 +505,12 @@ export const TasksMap = ({ map.getCanvas().style.cursor = 'pointer'; let imageObj = e.features[0].properties; - console.log(e.features); - axios .get( `https://graph.mapillary.com/${imageObj.id}?fields=thumb_256_url,computed_compass_angle,camera_type`, { headers: { - Authorization: 'OAuth MLY|5494923973921616|75ede84ae518fed4232a6e7eb7d53688', + Authorization: `OAuth ${MAPILLARY_TOKEN}`, }, }, ) @@ -526,8 +545,6 @@ export const TasksMap = ({ map.on('mousemove', 'mapillary-images', (e) => displayMapPopup(e)); popup.on('close', () => map.setLayoutProperty('mapillary-compass', 'visibility', 'none')); - map.on('mouseenter', 'mapillary-sequences', (e) => console.log(e)); - map.on('idle', () => { let element = document.getElementById('mapillary-toggle'); let visibility = element ? element.checked : false; @@ -540,28 +557,6 @@ export const TasksMap = ({ : map.setLayoutProperty('mapillary-sequences', 'visibility', 'none'); }); - map.setFilter('mapillary-images', [ - 'all', - ['>=', ['get', 'captured_at'], new Date(earliestStreetImagery).getTime()], - ]); - - map.setFilter('mapillary-sequences', [ - 'all', - ['>=', ['get', 'captured_at'], new Date(earliestStreetImagery).getTime()], - ]); - - if (mapillaryOrganizationId > 0) { - map.setFilter('mapillary-images', [ - 'all', - ['==', ['get', 'organization_id'], mapillaryOrganizationId], - ]); - - map.setFilter('mapillary-sequences', [ - 'all', - ['==', ['get', 'organization_id'], mapillaryOrganizationId], - ]); - } - map.on('click', 'tasks-fill', onSelectTaskClick); map.on('mouseleave', 'tasks-fill', function (e) { // Change the cursor style as a UI indicator. diff --git a/frontend/src/config/index.js b/frontend/src/config/index.js index 7e0958f1f..b54da4181 100644 --- a/frontend/src/config/index.js +++ b/frontend/src/config/index.js @@ -21,7 +21,6 @@ export const ADVANCED_LEVEL_COUNT = Number(process.env.REACT_APP_TM_MAPPER_LEVEL export const MAPBOX_TOKEN = process.env.REACT_APP_MAPBOX_TOKEN || ''; export const ENABLE_SERVICEWORKER = process.env.REACT_APP_ENABLE_SERVICEWORKER || 0; export const MAX_AOI_AREA = Number(process.env.REACT_APP_MAX_AOI_AREA) || 5000; -export const MAPILLARY_TOKEN = process.env.REACT_APP_MAPILLARY_TOKEN || ''; export const MAX_FILESIZE = parseInt(process.env.REACT_APP_MAX_FILESIZE) || 5000000; // bytes // ORGANISATIONAL INFORMATION @@ -50,6 +49,10 @@ export const HOMEPAGE_VIDEO_URL = process.env.REACT_APP_HOMEPAGE_VIDEO_URL || '' // Sentry.io DSN export const SENTRY_FRONTEND_DSN = process.env.REACT_APP_SENTRY_FRONTEND_DSN; +// Mapillary +export const MAPILLARY_TOKEN = process.env.REACT_APP_MAPILLARY_TOKEN || ''; +export const MAPILLARY_GRAPH_URL = process.env.REACT_APP_MAPILLARY_GRAPH_URL || 'https://graph.mapillary.com/'; + // OSM API and Editor URLs export const OSM_SERVER_URL = process.env.REACT_APP_OSM_SERVER_URL || 'https://www.openstreetmap.org'; From 5b142eaaf45176794d0bcfb7cc69f2fab252a5f6 Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Wed, 10 Aug 2022 16:26:57 -0700 Subject: [PATCH 23/25] Changed mapillary layer toggle to state-based component --- frontend/src/components/taskSelection/map.js | 50 ++++++++++++------- .../src/components/taskSelection/messages.js | 4 ++ frontend/src/config/index.js | 3 +- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/frontend/src/components/taskSelection/map.js b/frontend/src/components/taskSelection/map.js index 1bbb0f930..c55b194dd 100644 --- a/frontend/src/components/taskSelection/map.js +++ b/frontend/src/components/taskSelection/map.js @@ -1,4 +1,4 @@ -import React, { useLayoutEffect, useState } from 'react'; +import React, { useEffect, useLayoutEffect, useState } from 'react'; import { useSelector } from 'react-redux'; import bbox from '@turf/bbox'; import mapboxgl from 'mapbox-gl'; @@ -7,11 +7,18 @@ import MapboxLanguage from '@mapbox/mapbox-gl-language'; import { FormattedMessage } from 'react-intl'; import WebglUnsupported from '../webglUnsupported'; import messages from './messages'; -import { MAPBOX_TOKEN, TASK_COLOURS, MAP_STYLE, MAPBOX_RTL_PLUGIN_URL, MAPILLARY_TOKEN } from '../../config'; +import { + MAPBOX_TOKEN, + TASK_COLOURS, + MAP_STYLE, + MAPBOX_RTL_PLUGIN_URL, + MAPILLARY_TOKEN, +} from '../../config'; import lock from '../../assets/img/lock.png'; import redlock from '../../assets/img/red-lock.png'; import axios from 'axios'; import compassIcon from '../../assets/img/mapillary-compass.png'; +import { SwitchToggle } from '../formInputs'; let lockIcon = new Image(17, 20); lockIcon.src = lock; @@ -47,6 +54,7 @@ export const TasksMap = ({ const locale = useSelector((state) => state.preferences['locale']); const authDetails = useSelector((state) => state.auth.get('userDetails')); const [hoveredTaskId, setHoveredTaskId] = useState(null); + const [mapillaryShown, setMapillaryShown] = useState(false); const [map, setMapObj] = useState(null); @@ -247,6 +255,9 @@ export const TasksMap = ({ 'line-color': '#05CB63', 'line-width': 2, }, + layout: { + visibility: 'none', + }, }); map.addLayer({ id: 'mapillary-images', @@ -257,6 +268,9 @@ export const TasksMap = ({ 'circle-color': '#05CB63', 'circle-radius': 5, }, + layout: { + visibility: 'none', + }, }); map.loadImage(compassIcon, (error, image) => { @@ -342,7 +356,6 @@ export const TasksMap = ({ ]); } - if (map.getSource('tasks-outline') === undefined && taskBordersMap) { map.addSource('tasks-outline', { type: 'geojson', @@ -545,18 +558,6 @@ export const TasksMap = ({ map.on('mousemove', 'mapillary-images', (e) => displayMapPopup(e)); popup.on('close', () => map.setLayoutProperty('mapillary-compass', 'visibility', 'none')); - map.on('idle', () => { - let element = document.getElementById('mapillary-toggle'); - let visibility = element ? element.checked : false; - - visibility - ? map.setLayoutProperty('mapillary-images', 'visibility', 'visible') - : map.setLayoutProperty('mapillary-images', 'visibility', 'none'); - visibility - ? map.setLayoutProperty('mapillary-sequences', 'visibility', 'visible') - : map.setLayoutProperty('mapillary-sequences', 'visibility', 'none'); - }); - map.on('click', 'tasks-fill', onSelectTaskClick); map.on('mouseleave', 'tasks-fill', function (e) { // Change the cursor style as a UI indicator. @@ -641,6 +642,17 @@ export const TasksMap = ({ mapillaryOrganizationId, ]); + useEffect(() => { + if (map) { + mapillaryShown + ? map.setLayoutProperty('mapillary-images', 'visibility', 'visible') + : map.setLayoutProperty('mapillary-images', 'visibility', 'none'); + mapillaryShown + ? map.setLayoutProperty('mapillary-sequences', 'visibility', 'visible') + : map.setLayoutProperty('mapillary-sequences', 'visibility', 'none'); + } + }, [mapillaryShown]); + if (!mapboxgl.supported()) { return ; } else { @@ -657,8 +669,12 @@ export const TasksMap = ({ id={'mapillary-checkbox'} className={'cf left-1 top-1 pa2 absolute bg-white br1'} > - - + setMapillaryShown(!mapillaryShown)} + label={} + />
diff --git a/frontend/src/components/taskSelection/messages.js b/frontend/src/components/taskSelection/messages.js index 4cf5ea8be..afa1c6662 100644 --- a/frontend/src/components/taskSelection/messages.js +++ b/frontend/src/components/taskSelection/messages.js @@ -603,6 +603,10 @@ export default defineMessages({ id: 'project.resources.changesets.task', defaultMessage: "See task's changesets", }, + showMapillaryLayer: { + id: 'project.input.placeholder.mapillary', + defaultMessage: 'Show Mapillary layer', + }, taskOnOSMCha: { id: 'project.tasks.activity.osmcha', defaultMessage: 'View changesets in OSMCha', diff --git a/frontend/src/config/index.js b/frontend/src/config/index.js index b54da4181..fbce8dd87 100644 --- a/frontend/src/config/index.js +++ b/frontend/src/config/index.js @@ -51,7 +51,8 @@ export const SENTRY_FRONTEND_DSN = process.env.REACT_APP_SENTRY_FRONTEND_DSN; // Mapillary export const MAPILLARY_TOKEN = process.env.REACT_APP_MAPILLARY_TOKEN || ''; -export const MAPILLARY_GRAPH_URL = process.env.REACT_APP_MAPILLARY_GRAPH_URL || 'https://graph.mapillary.com/'; +export const MAPILLARY_GRAPH_URL = + process.env.REACT_APP_MAPILLARY_GRAPH_URL || 'https://graph.mapillary.com/'; // OSM API and Editor URLs export const OSM_SERVER_URL = From 5537dfeebd0f1d35a77b03b5277b3fb827bfa3a2 Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Wed, 10 Aug 2022 16:33:19 -0700 Subject: [PATCH 24/25] Replaced graph url with env --- frontend/src/components/projectEdit/imageryForm.js | 4 ++-- frontend/src/components/taskSelection/map.js | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/projectEdit/imageryForm.js b/frontend/src/components/projectEdit/imageryForm.js index 0661628af..853cd4603 100644 --- a/frontend/src/components/projectEdit/imageryForm.js +++ b/frontend/src/components/projectEdit/imageryForm.js @@ -8,7 +8,7 @@ import { StateContext, styleClasses } from '../../views/projectEdit'; import { Code } from '../code'; import { fetchLocalJSONAPI } from '../../network/genericJSONRequest'; import { useImageryOption, IMAGERY_OPTIONS } from '../../hooks/UseImageryOption'; -import { MAPILLARY_TOKEN } from '../../config'; +import { MAPILLARY_TOKEN, MAPILLARY_GRAPH_URL } from '../../config'; import axios from 'axios'; export const ImageryForm = () => { @@ -29,7 +29,7 @@ export const ImageryForm = () => { if (projectInfo.mapillaryOrganizationId) { axios .get( - `https://graph.mapillary.com/${projectInfo.mapillaryOrganizationId}?access_token=${MAPILLARY_TOKEN}&fields=name`, + `${MAPILLARY_GRAPH_URL}${projectInfo.mapillaryOrganizationId}?access_token=${MAPILLARY_TOKEN}&fields=name`, ) .then((resp) => setOrganization(resp.data.name)) .catch(() => setOrganization(null)); diff --git a/frontend/src/components/taskSelection/map.js b/frontend/src/components/taskSelection/map.js index c55b194dd..4d0bb2708 100644 --- a/frontend/src/components/taskSelection/map.js +++ b/frontend/src/components/taskSelection/map.js @@ -13,6 +13,7 @@ import { MAP_STYLE, MAPBOX_RTL_PLUGIN_URL, MAPILLARY_TOKEN, + MAPILLARY_GRAPH_URL, } from '../../config'; import lock from '../../assets/img/lock.png'; import redlock from '../../assets/img/red-lock.png'; @@ -520,7 +521,7 @@ export const TasksMap = ({ axios .get( - `https://graph.mapillary.com/${imageObj.id}?fields=thumb_256_url,computed_compass_angle,camera_type`, + `${MAPILLARY_GRAPH_URL}${imageObj.id}?fields=thumb_256_url,computed_compass_angle,camera_type`, { headers: { Authorization: `OAuth ${MAPILLARY_TOKEN}`, From cd01f2b810dba02d6460508668a3a4e0d052a9ef Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Thu, 18 Aug 2022 11:36:16 -0700 Subject: [PATCH 25/25] Rerun checks --- frontend/src/components/taskSelection/map.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/components/taskSelection/map.js b/frontend/src/components/taskSelection/map.js index 4d0bb2708..e66a8c594 100644 --- a/frontend/src/components/taskSelection/map.js +++ b/frontend/src/components/taskSelection/map.js @@ -227,7 +227,6 @@ export const TasksMap = ({ TASK_COLOURS.IMAGE_CAPTURE_DONE, 'rgba(0,0,0,0)', ], - // 'fill-opacity': ['/', ['*', 2, ['get', 'taskId']], 1000], // Temporary.... creates a gradient 'fill-opacity': 0.8, }, },