From 27fd83705e7db69e3eaba4051c31b18499f62ab2 Mon Sep 17 00:00:00 2001 From: Collin Beczak Date: Mon, 2 Feb 2026 18:11:11 -0600 Subject: [PATCH 1/3] fix edit button verbage --- src/components/UserEditorSelector/Messages.js | 6 +++--- .../Widgets/TaskMapWidget/Messages.js | 20 +++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/components/UserEditorSelector/Messages.js b/src/components/UserEditorSelector/Messages.js index bdc27aa65..6b0fbe458 100644 --- a/src/components/UserEditorSelector/Messages.js +++ b/src/components/UserEditorSelector/Messages.js @@ -11,16 +11,16 @@ export default defineMessages({ editLabel: { id: "UserEditorSelector.openEditor.label", - defaultMessage: "Open Editor", + defaultMessage: "Open External Editor", }, defaultEditor: { id: "UserEditorSelector.defaultEditor.label", - defaultMessage: "Set Default Editor:", + defaultMessage: "Set Default External Editor:", }, unsupportedEditor: { id: "UserEditorSelector.unsupportedEditor.label", - defaultMessage: "Open Unsupported Editor:", + defaultMessage: "Open Unsupported External Editor:", }, }); diff --git a/src/components/Widgets/TaskMapWidget/Messages.js b/src/components/Widgets/TaskMapWidget/Messages.js index a66640507..716144597 100644 --- a/src/components/Widgets/TaskMapWidget/Messages.js +++ b/src/components/Widgets/TaskMapWidget/Messages.js @@ -28,4 +28,24 @@ export default defineMessages({ id: "Widgets.TaskMapWidget.reselectTask", defaultMessage: "Re-Select Task", }, + + viewTab: { + id: "Widgets.TaskMapWidget.tab.view", + defaultMessage: "View", + }, + + editTab: { + id: "Widgets.TaskMapWidget.tab.edit", + defaultMessage: "Edit", + }, + + externalEditTab: { + id: "Widgets.TaskMapWidget.tab.externalEdit", + defaultMessage: "External Edit", + }, + + externalEditPrompt: { + id: "Widgets.TaskMapWidget.externalEditPrompt", + defaultMessage: "Use the button below to open this task in an external editor.", + }, }); From e8701f803221fbb309beaee44b7018f693e6d90f Mon Sep 17 00:00:00 2001 From: Collin Beczak Date: Mon, 2 Feb 2026 18:32:51 -0600 Subject: [PATCH 2/3] Update editor labels and descriptions for clarity and consistency across the application --- lang/en-US.json | 28 ++-- .../TaskCompletionStep/TaskCompletionStep.jsx | 2 - .../Widgets/TaskMapWidget/Messages.js | 4 +- .../Widgets/TaskMapWidget/TaskMapWidget.jsx | 121 ++++++++++++++---- src/pages/Profile/Messages.js | 4 +- src/services/Editor/Messages.js | 12 +- src/services/KeyboardShortcuts/Messages.js | 12 +- 7 files changed, 126 insertions(+), 57 deletions(-) diff --git a/lang/en-US.json b/lang/en-US.json index f0e5720f3..9905ac0e3 100644 --- a/lang/en-US.json +++ b/lang/en-US.json @@ -769,12 +769,12 @@ "Dashboard.header.somethingNew": "something new", "Dashboard.header.userScore": "{points, number} points", "Dashboard.header.welcomeBack": "Welcome Back, {username}!", - "Editor.id.label": "Edit in iD (web editor)", - "Editor.josm.label": "Edit in JOSM", - "Editor.josmFeatures.label": "Edit just features in JOSM", - "Editor.josmLayer.label": "Edit in new JOSM layer", - "Editor.level0.label": "Edit in Level0", - "Editor.rapid.label": "Edit in Rapid", + "Editor.id.label": "Open in iD Editor", + "Editor.josm.label": "Open in JOSM Editor", + "Editor.josmFeatures.label": "Open just features in JOSM Editor", + "Editor.josmLayer.label": "Open in new JOSM Editor layer", + "Editor.level0.label": "Open in Level0 Editor", + "Editor.rapid.label": "Open in Rapid Editor", "EnhancedMap.SearchControl.noResults": "No Results", "EnhancedMap.SearchControl.nominatimQuery.placeholder": "Nominatim Query", "ErrorModal.title": "Oops!", @@ -958,7 +958,7 @@ "KeyMapping.layers.layerMapillary": "Toggle Mapillary Layer", "KeyMapping.layers.layerOSMData": "Toggle OSM Data Layer", "KeyMapping.layers.layerTaskFeatures": "Toggle Features Layer", - "KeyMapping.openEditor.editId": "Edit in iD", + "KeyMapping.openEditor.editId": "Open in iD Editor", "KeyMapping.taskCompletion.alreadyFixed": "Already fixed", "KeyMapping.taskCompletion.falsePositive": "No / Not an issue", "KeyMapping.taskCompletion.fixed": "Yes / I fixed it!", @@ -1083,8 +1083,8 @@ "Profile.form.customBasemaps.label": "Custom Basemaps", "Profile.form.defaultBasemap.description": "Select the default basemap to display on the map. Only a default challenge basemap will override the option selected here.", "Profile.form.defaultBasemap.label": "Default Basemap", - "Profile.form.defaultEditor.description": "Select the default editor that you want to use when fixing tasks. By selecting this option you will be able to skip the editor selection dialog after clicking on edit in a task.", - "Profile.form.defaultEditor.label": "Default Editor", + "Profile.form.defaultEditor.description": "Select the default external editor that you want to use when fixing tasks. This editor opens in a new tab or application and is separate from the embedded Rapid editor shown within MapRoulette. By selecting this option you will be able to skip the editor selection dialog after clicking on edit in a task.", + "Profile.form.defaultEditor.label": "Default External Editor", "Profile.form.disableTaskConfirm.description": "This will allow the user to bypass the task confirmation modal when a user clicks 'I fixed it!'. Be aware some projects and challenges won't allow this behavior.", "Profile.form.disableTaskConfirm.label": "Disable Task Confirmation Modal", "Profile.form.email.description": "If you request emails in your Notification Subscriptions, they will be sent here.\n\nDecide which MapRoulette notifications you would like to receive, along with whether you would like to be sent an email informing you of the notification (either immediately or as a daily digest)", @@ -1425,9 +1425,9 @@ "TopUserChallenges.widget.label": "Your Top Challenges", "User.sort.numOfChallenges": "Score", "UserEditorSelector.currentEditor.label": "Current Editor:", - "UserEditorSelector.defaultEditor.label": "Set Default Editor:", - "UserEditorSelector.openEditor.label": "Open Editor", - "UserEditorSelector.unsupportedEditor.label": "Open Unsupported Editor:", + "UserEditorSelector.defaultEditor.label": "Set Default External Editor:", + "UserEditorSelector.openEditor.label": "Open External Editor", + "UserEditorSelector.unsupportedEditor.label": "Open Unsupported External Editor:", "UserProfile.favoriteChallenges.header": "Your Favorite Challenges", "UserProfile.lockedTasks.header": "Your Locked Tasks", "UserProfile.savedTasks.header": "Tracked Tasks", @@ -1555,9 +1555,13 @@ "Widgets.TaskLocationWidget.controls.showLonLat.label": "Lon/Lat", "Widgets.TaskLocationWidget.label": "Location", "Widgets.TaskMapWidget.editMode": "Current Mode:", + "Widgets.TaskMapWidget.externalEditPrompt": "Use the button below to open this task in an external editor.", "Widgets.TaskMapWidget.rapidDiscardUnsavedChanges": "You have unsaved changes in Rapid which will be discarded. Are you sure you want to proceed?", "Widgets.TaskMapWidget.rapidFailed": "Widget Failed! Geometries Null!", "Widgets.TaskMapWidget.reselectTask": "Re-Select Task", + "Widgets.TaskMapWidget.tab.edit": "Rapid Editor", + "Widgets.TaskMapWidget.tab.externalEdit": "External Edit", + "Widgets.TaskMapWidget.tab.view": "Task Map", "Widgets.TaskMoreOptionsWidget.label": "More Options", "Widgets.TaskNearbyMap.currentTaskTooltip": "Current Task", "Widgets.TaskNearbyMap.tooltip.loadMoreTasks.control": "Load More Tasks", diff --git a/src/components/TaskPane/ActiveTaskDetails/ActiveTaskControls/TaskCompletionStep/TaskCompletionStep.jsx b/src/components/TaskPane/ActiveTaskDetails/ActiveTaskControls/TaskCompletionStep/TaskCompletionStep.jsx index b18eb10b7..94e3551fd 100644 --- a/src/components/TaskPane/ActiveTaskDetails/ActiveTaskControls/TaskCompletionStep/TaskCompletionStep.jsx +++ b/src/components/TaskPane/ActiveTaskDetails/ActiveTaskControls/TaskCompletionStep/TaskCompletionStep.jsx @@ -2,7 +2,6 @@ import PropTypes from "prop-types"; import { Component } from "react"; import { FormattedMessage } from "react-intl"; import { TaskStatus } from "../../../../../services/Task/TaskStatus/TaskStatus"; -import UserEditorSelector from "../../../../UserEditorSelector/UserEditorSelector"; import TaskAlreadyFixedControl from "../TaskAlreadyFixedControl/TaskAlreadyFixedControl"; import TaskFalsePositiveControl from "../TaskFalsePositiveControl/TaskFalsePositiveControl"; import TaskFixedControl from "../TaskFixedControl/TaskFixedControl"; @@ -49,7 +48,6 @@ export default class TaskCompletionStep extends Component { )} -
{this.props.needsRevised && (
diff --git a/src/components/Widgets/TaskMapWidget/Messages.js b/src/components/Widgets/TaskMapWidget/Messages.js index 716144597..3cdb8957b 100644 --- a/src/components/Widgets/TaskMapWidget/Messages.js +++ b/src/components/Widgets/TaskMapWidget/Messages.js @@ -31,12 +31,12 @@ export default defineMessages({ viewTab: { id: "Widgets.TaskMapWidget.tab.view", - defaultMessage: "View", + defaultMessage: "Task Map", }, editTab: { id: "Widgets.TaskMapWidget.tab.edit", - defaultMessage: "Edit", + defaultMessage: "Rapid Editor", }, externalEditTab: { diff --git a/src/components/Widgets/TaskMapWidget/TaskMapWidget.jsx b/src/components/Widgets/TaskMapWidget/TaskMapWidget.jsx index 7d70cca3e..3a6f75e7c 100644 --- a/src/components/Widgets/TaskMapWidget/TaskMapWidget.jsx +++ b/src/components/Widgets/TaskMapWidget/TaskMapWidget.jsx @@ -1,15 +1,22 @@ import { Component } from "react"; import { FormattedMessage } from "react-intl"; +import { replacePropertyTags } from "../../../hooks/UsePropertyReplacement/UsePropertyReplacement"; import AsCooperativeWork from "../../../interactions/Task/AsCooperativeWork"; +import { Editor } from "../../../services/Editor/Editor"; +import { OPEN_STREET_MAP } from "../../../services/VisibleLayer/LayerSources"; import { WidgetDataTarget, registerWidgetType } from "../../../services/Widget/Widget"; import MapPane from "../../EnhancedMap/MapPane/MapPane"; +import WithEditor from "../../HOCs/WithEditor/WithEditor"; import WithKeyboardShortcuts from "../../HOCs/WithKeyboardShortcuts/WithKeyboardShortcuts"; import QuickWidget from "../../QuickWidget/QuickWidget"; import TaskMap from "../../TaskPane/TaskMap/TaskMap"; +import UserEditorSelector from "../../UserEditorSelector/UserEditorSelector"; import messages from "./Messages"; -import EditSwitch from "./RapidEditor/EditSwitch"; import RapidEditor from "./RapidEditor/RapidEditor"; +const TAB_VIEW = "view"; +const TAB_EDIT = "edit"; + const descriptor = { widgetKey: "TaskMapWidget", label: messages.label, @@ -20,24 +27,68 @@ const descriptor = { defaultHeight: 19, }; +const getActiveTab = (props, disableRapid) => { + if (!props.getUserAppSetting) return TAB_VIEW; + + const mapTab = props.getUserAppSetting(props.user, "mapTab"); + if (mapTab) { + // If editing is disabled, force view tab + if (disableRapid && mapTab !== TAB_VIEW) return TAB_VIEW; + return mapTab; + } + + // Backward compatibility: migrate from isEditMode boolean + const isEditMode = props.getUserAppSetting(props.user, "isEditMode"); + if (isEditMode && !disableRapid) return TAB_EDIT; + return TAB_VIEW; +}; + export default class TaskMapWidget extends Component { componentWillUnmount = () => { this.props.resumeKeyboardShortcuts(); }; componentDidUpdate(prevProps) { - const prevEditMode = prevProps.getUserAppSetting - ? prevProps.getUserAppSetting(prevProps.user, "isEditMode") - : false; - const currentEditMode = this.props.getUserAppSetting - ? this.props.getUserAppSetting(this.props.user, "isEditMode") - : false; - - if (currentEditMode !== prevEditMode) { - currentEditMode ? this.props.pauseKeyboardShortcuts() : this.props.resumeKeyboardShortcuts(); + const prevTab = getActiveTab(prevProps, false); + const currentTab = getActiveTab(this.props, false); + + if (currentTab !== prevTab) { + currentTab === TAB_EDIT + ? this.props.pauseKeyboardShortcuts() + : this.props.resumeKeyboardShortcuts(); } } + setTab = (tab) => { + if (this.props.updateUserAppSetting) { + this.props.updateUserAppSetting(this.props.user.id, { mapTab: tab }); + } + }; + + pickEditor = ({ value }) => { + const { task, taskFeatureProperties } = this.props; + const comment = task.parent?.checkinComment; + const replacedComment = replacePropertyTags(comment, taskFeatureProperties, false); + + this.props.editTask( + value, + task, + this.props.mapBounds, + { + imagery: this.props.source?.id !== OPEN_STREET_MAP ? this.props.source : undefined, + photoOverlay: this.props.showMapillaryLayer ? "mapillary" : null, + }, + this.props.taskBundle, + replacedComment, + ); + }; + + allowedEditors = () => { + return AsCooperativeWork(this.props.task).isChangeFileType() + ? [Editor.josmLayer, Editor.josm] + : null; + }; + render() { const cooperative = AsCooperativeWork(this.props.task).isTagType() || this.props.task.cooperativeWork; @@ -52,11 +103,7 @@ export default class TaskMapWidget extends Component { !isReviewing && !this.props.asMetaReview); - const editMode = disableRapid - ? false - : this.props.getUserAppSetting - ? this.props.getUserAppSetting(this.props.user, "isEditMode") - : false; + const activeTab = getActiveTab(this.props, disableRapid); if (!this.props.task.geometries.features) { return ( @@ -72,6 +119,11 @@ export default class TaskMapWidget extends Component { this.props.currentConfiguration?.type === "leftPanel" || this.props.currentConfiguration?.type === "rightPanel"; + const tabs = [ + { key: TAB_VIEW, label: messages.viewTab, disabled: false }, + { key: TAB_EDIT, label: messages.editTab, disabled: disableRapid }, + ]; + return (
{this.props.getUserAppSetting ? ( - <> -
-
- -
-
- -
-
- +
+ {tabs.map((tab) => ( + + ))} + {!disableRapid && ( + + )} +
) : null} - {editMode ? ( + {activeTab === TAB_EDIT ? ( Date: Mon, 2 Feb 2026 19:34:46 -0600 Subject: [PATCH 3/3] Refactor TaskCompletionStep tests for clarity and accuracy - Updated test descriptions for better understanding. - Changed the test to check for the presence of a breadcrumb instead of a specific text. - Adjusted the button text assertion to reflect the new fixed status. --- .../TaskCompletionStep/TaskCompletionStep.test.jsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/components/TaskPane/ActiveTaskDetails/ActiveTaskControls/TaskCompletionStep/TaskCompletionStep.test.jsx b/src/components/TaskPane/ActiveTaskDetails/ActiveTaskControls/TaskCompletionStep/TaskCompletionStep.test.jsx index a659e7255..1bef43541 100644 --- a/src/components/TaskPane/ActiveTaskDetails/ActiveTaskControls/TaskCompletionStep/TaskCompletionStep.test.jsx +++ b/src/components/TaskPane/ActiveTaskDetails/ActiveTaskControls/TaskCompletionStep/TaskCompletionStep.test.jsx @@ -2,8 +2,8 @@ import { describe, expect, it } from "vitest"; import TaskCompletionStep from "./TaskCompletionStep"; describe("TaskCompletionStep", () => { - it("renders task completion step 1 with required props", () => { - const { getByText } = global.withProvider( + it("renders task completion step with required props", () => { + const { container } = global.withProvider( null} @@ -15,13 +15,12 @@ describe("TaskCompletionStep", () => { deactivateKeyboardShortcutGroup={() => null} />, ); - const text = getByText("Open Editor"); - expect(text).toBeInTheDocument(); + expect(container.querySelector(".breadcrumb")).toBeInTheDocument(); }); - it("shows Edit button if allowedProgressions includes 1", () => { + it("shows fixed button if allowedProgressions includes fixed status", () => { const allowedProgressions = new Map(); - allowedProgressions.set(1); + allowedProgressions.set(1, true); const { getByText } = global.withProvider( { deactivateKeyboardShortcutGroup={() => null} />, ); - const text = getByText("Open Editor"); + const text = getByText("I fixed it!"); expect(text).toBeInTheDocument(); }); });