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 {
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 {
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) => {