diff --git a/lang/en-US.json b/lang/en-US.json index f66f78449..e2fb1009d 100644 --- a/lang/en-US.json +++ b/lang/en-US.json @@ -1190,8 +1190,8 @@ "Review.Dashboard.tasksReviewedByMe": "Tasks Reviewed by Me", "Review.Dashboard.tasksToBeReviewed": "Tasks to be Reviewed", "Review.Dashboard.title": "Review Overview", - "Review.Task.fields.featureId.label": "Feature Id", - "Review.Task.fields.id.label": "Internal Id", + "Review.Task.fields.featureId.label": "OSM ID", + "Review.Task.fields.id.label": "Task ID", "Review.TaskAnalysisTable.configureColumns": "Configure columns", "Review.TaskAnalysisTable.controls.fixTask.label": "Fix", "Review.TaskAnalysisTable.controls.metaReviewTask.label": "Meta Review", @@ -1375,8 +1375,8 @@ "Task.taskTags.modify.label": "Modify MR Tags", "Task.taskTags.update.label": "Update MR Tags", "Task.unsave.control.tooltip": "Stop Tracking", - "TaskAnalysisTable.columns.searchFeatureId.placeholder": "Search feature ID...", - "TaskAnalysisTable.columns.searchId.placeholder": "Search ID...", + "TaskAnalysisTable.columns.searchFeatureId.placeholder": "Search OSM ID...", + "TaskAnalysisTable.columns.searchId.placeholder": "Search Task ID...", "TaskAnalysisTable.columns.searchMapper.placeholder": "Search mapper...", "TaskAnalysisTable.columns.searchMetaReviewer.placeholder": "Search meta reviewer...", "TaskAnalysisTable.columns.searchReviewer.placeholder": "Search reviewer...", @@ -1566,8 +1566,8 @@ "Widgets.ReviewNearbyTasksWidget.displayBundledTasksLabel": "Display Bundled Tasks Only", "Widgets.ReviewNearbyTasksWidget.label": "Nearby Tasks", "Widgets.ReviewNearbyTasksWidget.noVirtualChallenges": "Nearby tasks are not available for virtual challenges.", - "Widgets.ReviewNearbyTasksWidget.popup.fields.name.label": "Feature Id:", - "Widgets.ReviewNearbyTasksWidget.popup.fields.taskId.label": "Internal Id:", + "Widgets.ReviewNearbyTasksWidget.popup.fields.name.label": "OSM ID:", + "Widgets.ReviewNearbyTasksWidget.popup.fields.taskId.label": "Task ID:", "Widgets.ReviewNearbyTasksWidget.restoreDefaultFiltersLabel": "Restore Default Filters", "Widgets.ReviewNearbyTasksWidget.saveCurrentFiltersLabel": "Save Current Filters", "Widgets.ReviewNearbyTasksWidget.simultaneousTasks": "Working on {taskCount, number} tasks together", diff --git a/src/components/TaskAnalysisTable/Messages.js b/src/components/TaskAnalysisTable/Messages.js index a9c4504fd..db0f3e354 100644 --- a/src/components/TaskAnalysisTable/Messages.js +++ b/src/components/TaskAnalysisTable/Messages.js @@ -21,12 +21,12 @@ export default defineMessages({ idLabel: { id: "Review.Task.fields.id.label", - defaultMessage: "Internal Id", + defaultMessage: "Task ID", }, featureIdLabel: { id: "Review.Task.fields.featureId.label", - defaultMessage: "Feature Id", + defaultMessage: "OSM ID", }, unbundle: { @@ -282,12 +282,12 @@ export default defineMessages({ searchFeatureIdPlaceholder: { id: "TaskAnalysisTable.columns.searchFeatureId.placeholder", - defaultMessage: "Search feature ID...", + defaultMessage: "Search OSM ID...", }, searchIdPlaceholder: { id: "TaskAnalysisTable.columns.searchId.placeholder", - defaultMessage: "Search ID...", + defaultMessage: "Search Task ID...", }, clearFilterLabel: { diff --git a/src/components/TaskAnalysisTable/columns/taskColumns.jsx b/src/components/TaskAnalysisTable/columns/taskColumns.jsx index b1132b388..3ac8bda46 100644 --- a/src/components/TaskAnalysisTable/columns/taskColumns.jsx +++ b/src/components/TaskAnalysisTable/columns/taskColumns.jsx @@ -1,6 +1,8 @@ import _kebabCase from "lodash/kebabCase"; import { FormattedDate, FormattedMessage, FormattedTime } from "react-intl"; import { Link } from "react-router-dom"; +import AsIdentifiableFeature from "../../../interactions/TaskFeature/AsIdentifiableFeature"; +import { loadObjectsIntoJOSM } from "../../../services/Editor/Editor"; import { messagesByPriority } from "../../../services/Task/TaskPriority/TaskPriority"; import { keysByStatus, messagesByStatus } from "../../../services/Task/TaskStatus/TaskStatus"; import SvgSymbol from "../../SvgSymbol/SvgSymbol"; @@ -8,25 +10,56 @@ import messages from "../Messages"; import TableSearchFilter from "../TableSearchFilter"; import { StatusLabel } from "../TaskTableHelpers"; +const osmIdForTask = (task) => { + const feature = task?.geometries?.features?.[0]; + if (!feature) return null; + const identifiable = AsIdentifiableFeature(feature); + const osmId = identifiable.osmId(); + const osmType = identifiable.osmType(); + if (!osmId || !osmType) return null; + return `${osmType[0]}${osmId}`; +}; + /** - * Creates the Feature ID column + * Creates the OSM ID column */ export const createFeatureIdColumn = (props) => ({ id: "featureId", Header: props.intl.formatMessage(messages.featureIdLabel), - accessor: (t) => t.name || t.title, - Cell: ({ value }) => ( -
- {value || ""} -
- ), + accessor: (t) => osmIdForTask(t) || t.name || t.title, + Cell: ({ value, row }) => { + const josmId = osmIdForTask(row.original); + const content = ( +
+ {value || ""} +
+ ); + + if (!josmId) { + return content; + } + + return ( + { + e.preventDefault(); + loadObjectsIntoJOSM([josmId], true); + }} + className="mr-links-green-lighter" + title="Open in JOSM" + > + {content} + + ); + }, Filter: ({ column: { filterValue, setFilter } }) => ( { + if (!feature) return null; + const identifiable = AsIdentifiableFeature(feature); + const osmId = identifiable.osmId(); + const osmType = identifiable.osmType(); + if (!osmId || !osmType) return null; + return `${osmType[0]}${osmId}`; +}; + /** * The content to show in the popup when a task marker is clicked. */ @@ -17,6 +28,11 @@ class TaskMarkerContent extends Component { this.props.marker.options.priority ?? this.props.marker.options.taskPriority ]; + const firstFeature = this.props.marker.options.geometries?.features?.[0]; + const josmId = osmIdForFeature(firstFeature); + const nameValue = + josmId || this.props.marker.options.name || firstFeature?.id; + return (
@@ -25,8 +41,20 @@ class TaskMarkerContent extends Component {
- {this.props.marker.options.name || - this.props.marker.options.geometries?.features[0]?.id} + {josmId ? ( + { + e.preventDefault(); + loadObjectsIntoJOSM([josmId], true); + }} + title="Open in JOSM" + > + {nameValue} + + ) : ( + nameValue + )}
diff --git a/src/components/Widgets/TaskBundleWidget/Messages.js b/src/components/Widgets/TaskBundleWidget/Messages.js index 4d3a15ce9..d178763ec 100644 --- a/src/components/Widgets/TaskBundleWidget/Messages.js +++ b/src/components/Widgets/TaskBundleWidget/Messages.js @@ -36,12 +36,12 @@ export default defineMessages({ taskIdLabel: { id: "Widgets.ReviewNearbyTasksWidget.popup.fields.taskId.label", - defaultMessage: "Internal Id:", + defaultMessage: "Task ID:", }, nameLabel: { id: "Widgets.ReviewNearbyTasksWidget.popup.fields.name.label", - defaultMessage: "Feature Id:", + defaultMessage: "OSM ID:", }, statusLabel: { diff --git a/src/components/Widgets/TaskBundleWidget/TaskMarkerContent.jsx b/src/components/Widgets/TaskBundleWidget/TaskMarkerContent.jsx index 269b1e021..a974f7257 100644 --- a/src/components/Widgets/TaskBundleWidget/TaskMarkerContent.jsx +++ b/src/components/Widgets/TaskBundleWidget/TaskMarkerContent.jsx @@ -2,10 +2,21 @@ import { Component } from "react"; import { FormattedMessage } from "react-intl"; import { Link } from "react-router-dom"; import AsCooperativeWork from "../../../interactions/Task/AsCooperativeWork"; +import AsIdentifiableFeature from "../../../interactions/TaskFeature/AsIdentifiableFeature"; +import { loadObjectsIntoJOSM } from "../../../services/Editor/Editor"; import { messagesByPriority } from "../../../services/Task/TaskPriority/TaskPriority"; import { messagesByStatus } from "../../../services/Task/TaskStatus/TaskStatus"; import messages from "./Messages"; +const osmIdForFeature = (feature) => { + if (!feature) return null; + const identifiable = AsIdentifiableFeature(feature); + const osmId = identifiable.osmId(); + const osmType = identifiable.osmType(); + if (!osmId || !osmType) return null; + return `${osmType[0]}${osmId}`; +}; + /** * The content to show in the popup when a task marker is clicked. */ @@ -95,6 +106,10 @@ class TaskMarkerContent extends Component { !AsCooperativeWork(this.props.task).isTagType() && this.props.marker.options.taskId !== this.props.task.id; + const firstFeature = this.props.marker.options.geometries?.features?.[0]; + const josmId = osmIdForFeature(firstFeature); + const nameValue = josmId || this.props.marker.options.name || firstFeature?.id; + return (
@@ -103,8 +118,20 @@ class TaskMarkerContent extends Component {
- {this.props.marker.options.name || - this.props.marker.options.geometries?.features[0]?.id} + {josmId ? ( + { + e.preventDefault(); + loadObjectsIntoJOSM([josmId], true); + }} + title="Open in JOSM" + > + {nameValue} + + ) : ( + nameValue + )}
diff --git a/src/pages/Review/TasksReview/Messages.js b/src/pages/Review/TasksReview/Messages.js index b80f1525f..1d4af3939 100644 --- a/src/pages/Review/TasksReview/Messages.js +++ b/src/pages/Review/TasksReview/Messages.js @@ -151,12 +151,12 @@ export default defineMessages({ idLabel: { id: "Review.Task.fields.id.label", - defaultMessage: "Internal Id", + defaultMessage: "Task ID", }, featureIdLabel: { id: "Review.Task.fields.featureId.label", - defaultMessage: "Feature Id", + defaultMessage: "OSM ID", }, statusLabel: { diff --git a/src/pages/Review/TasksReview/TasksReviewTable.jsx b/src/pages/Review/TasksReview/TasksReviewTable.jsx index 0ffca7493..3e2b51d3a 100644 --- a/src/pages/Review/TasksReview/TasksReviewTable.jsx +++ b/src/pages/Review/TasksReview/TasksReviewTable.jsx @@ -21,6 +21,8 @@ import WithSavedFilters from "../../../components/HOCs/WithSavedFilters/WithSave import IntlDatePicker from "../../../components/IntlDatePicker/IntlDatePicker"; import InTableTagFilter from "../../../components/KeywordAutosuggestInput/InTableTagFilter"; import PaginationControl from "../../../components/PaginationControl/PaginationControl"; +import AsIdentifiableFeature from "../../../interactions/TaskFeature/AsIdentifiableFeature"; +import { loadObjectsIntoJOSM } from "../../../services/Editor/Editor"; import ManageSavedFilters from "../../../components/SavedFilters/ManageSavedFilters"; import SavedFiltersList from "../../../components/SavedFilters/SavedFiltersList"; import SvgSymbol from "../../../components/SvgSymbol/SvgSymbol"; @@ -716,6 +718,16 @@ const GearDropdown = ({ ); }; +const osmIdForTask = (task) => { + const feature = task?.geometries?.features?.[0]; + if (!feature) return null; + const identifiable = AsIdentifiableFeature(feature); + const osmId = identifiable.osmId(); + const osmType = identifiable.osmType(); + if (!osmId || !osmType) return null; + return `${osmType[0]}${osmId}`; +}; + export const setupColumnTypes = (props, openComments, criteria) => { const handleClick = (e, linkTo) => { e.preventDefault(); @@ -766,7 +778,7 @@ export const setupColumnTypes = (props, openComments, criteria) => { {filterValue && ( @@ -790,7 +802,25 @@ export const setupColumnTypes = (props, openComments, criteria) => { columns.featureId = { id: "featureId", Header: props.intl.formatMessage(messages.featureIdLabel), - accessor: (row) => row.name || row.title, + accessor: (row) => osmIdForTask(row) || row.name || row.title, + Cell: ({ value, row }) => { + const josmId = osmIdForTask(row.original); + if (!josmId) { + return value || ""; + } + return ( + { + e.preventDefault(); + loadObjectsIntoJOSM([josmId], true); + }} + title="Open in JOSM" + > + {value} + + ); + }, width: 120, minWidth: 80, disableSortBy: true, @@ -799,7 +829,7 @@ export const setupColumnTypes = (props, openComments, criteria) => { {filterValue && ( diff --git a/src/services/Task/TaskReview/TaskReview.js b/src/services/Task/TaskReview/TaskReview.js index 7ec07ed10..47c5dbe6f 100644 --- a/src/services/Task/TaskReview/TaskReview.js +++ b/src/services/Task/TaskReview/TaskReview.js @@ -272,7 +272,8 @@ const buildQueryFilters = function (criteria, addedColumns) { return capitalizedKey.charAt(0).toUpperCase() + capitalizedKey.slice(1); }); //Fix Headers - displayedColumns = displayedColumns.map((e) => (e === "Id" ? "Internal Id" : e)); + displayedColumns = displayedColumns.map((e) => (e === "Id" ? "Task ID" : e)); + displayedColumns = displayedColumns.map((e) => (e === "Feature Id" ? "OSM ID" : e)); displayedColumns = displayedColumns.map((e) => (e === "Mapper Controls" ? "Actions" : e)); displayedColumns = displayedColumns.map((e) => (e === "Reviewer Controls" ? "Actions" : e)); displayedColumns = displayedColumns.map((e) => (e === "Review Requested By" ? "Mapper" : e)); @@ -470,7 +471,7 @@ export const loadNextReviewTask = function (criteria = {}, lastTaskId, asMetaRev ); return function (dispatch) { - const params = { sort, order, ...searchParameters, asMetaReview }; + const params = { sort, order, ...searchParameters, asMetaReview, includeTags: true }; if (Number.isFinite(lastTaskId)) { params.lastTaskId = lastTaskId; } @@ -497,7 +498,7 @@ export const fetchTaskForReview = function (taskId, includeMapillary = false) { return new Endpoint(api.task.startReview, { schema: taskSchema(), variables: { id: taskId }, - params: { mapillary: includeMapillary }, + params: { mapillary: includeMapillary, includeTags: true }, }) .execute() .then((normalizedResults) => {