diff --git a/.env b/.env
index 479b14d76..fffbc5886 100644
--- a/.env
+++ b/.env
@@ -10,7 +10,6 @@ REACT_APP_TITLE='MapRoulette'
# Features flags. Set each to 'enabled' or 'disabled'.
REACT_APP_FEATURE_SOCIAL_SHARING='enabled'
-REACT_APP_FEATURE_BOUNDED_TASK_BROWSING='disabled'
REACT_APP_FEATURE_LEADERBOARD='enabled'
REACT_APP_FEATURE_CHALLENGE_ANALYSIS_TABLE='disabled'
REACT_APP_FEATURE_MOBILE_DEVICES='disabled'
@@ -45,7 +44,7 @@ REACT_APP_NEARBY_LATITUDE_LENGTH=0.75
# box in order for map-bounded task browsing to become available on the locator
# map. The larger this value, the greater the load put on the server when users
# are browsing map-bounded tasks.
-REACT_APP_BOUNDED_TASKS_MAX_DIMENSION=2.5
+REACT_APP_BOUNDED_TASKS_MAX_DIMENSION=70
# Default time, in hours, until a newly-created virtual challenge expires.
REACT_APP_VIRTUAL_CHALLENGE_DURATION=36
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dd9ffc3a8..eb8be813b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,23 @@ The format is based on
This project adheres to
[Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+## [v3.5] - 2019-12-06
+### Added
+- Task browsing at much lower zoom levels on Find Challenges page
+- Overlay on Find Challenges map with "Near Me" option and nominatum search
+- Relocated location filters on Find Challenges page above search results
+- Automatic refreshing of task locks while mapper is actively working on a task
+- New option to explictly "unlock" (abandon) a task on task-completion page
+
+### Fixed
+- Potential wrong timezone on origin/sourcing date recorded for task data
+- Occasional incorrect challenge-completion status resulting from stale checks
+- Incorrect OSM entity ids sometimes sent to iD and JOSM editors
+
+### Removed
+- "Within Map Bounds" filter now that task browsing is offered at lower zoom
+
+
## [v3.4.6] - 2019-11-14
### Added
- Option to change task data source date when rebuilding tasks
diff --git a/package.json b/package.json
index 095cd1064..2db34347e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "maproulette3",
- "version": "3.4.6",
+ "version": "3.5",
"private": true,
"dependencies": {
"@mapbox/geo-viewport": "^0.4.0",
diff --git a/src/PersistedStore.js b/src/PersistedStore.js
index 6ed7ac127..2809c0b83 100644
--- a/src/PersistedStore.js
+++ b/src/PersistedStore.js
@@ -9,6 +9,7 @@ import { virtualChallengeEntities }
from './services/VirtualChallenge/VirtualChallenge'
import { taskEntities } from './services/Task/Task'
import { currentClusteredTasks } from './services/Task/ClusteredTask'
+import { currentTaskClusters } from './services/Task/TaskClusters'
import { currentBoundedTasks } from './services/Task/BoundedTask'
import { currentReviewTasks } from './services/Task/TaskReview/TaskReview'
import { commentEntities } from './services/Comment/Comment'
@@ -55,6 +56,7 @@ export const initializeStore = function() {
adminContext,
currentPreferences,
currentClusteredTasks,
+ currentTaskClusters,
currentBoundedTasks,
currentReviewTasks,
entities,
diff --git a/src/components/AdminPane/HOCs/WithCurrentChallenge/WithCurrentChallenge.js b/src/components/AdminPane/HOCs/WithCurrentChallenge/WithCurrentChallenge.js
index 916f1e43e..5eef77e49 100644
--- a/src/components/AdminPane/HOCs/WithCurrentChallenge/WithCurrentChallenge.js
+++ b/src/components/AdminPane/HOCs/WithCurrentChallenge/WithCurrentChallenge.js
@@ -14,8 +14,6 @@ import { addError } from '../../../../services/Error/Error'
import AppErrors from '../../../../services/Error/AppErrors'
import AsManageableChallenge
from '../../../../interactions/Challenge/AsManageableChallenge'
-import { isUsableChallengeStatus }
- from '../../../../services/Challenge/ChallengeStatus/ChallengeStatus'
import WithClusteredTasks
from '../../../HOCs/WithClusteredTasks/WithClusteredTasks'
import WithChallengeManagement
@@ -27,12 +25,10 @@ import WithChallengeManagement
*
* @author [Neil Rotstan](https://github.com/nrotstan)
*/
-const WithCurrentChallenge = function(WrappedComponent,
- includeTasks=false) {
+const WithCurrentChallenge = function(WrappedComponent) {
return class extends Component {
state = {
loadingChallenge: true,
- loadingTasks: includeTasks,
}
currentChallengeId = () =>
@@ -53,24 +49,10 @@ const WithCurrentChallenge = function(WrappedComponent,
this.props.fetchChallengeActivity(challengeId, new Date(challenge.created)),
this.props.fetchChallengeActions(challengeId),
]).then(() => this.setState({loadingChallenge: false}))
-
- if (includeTasks) {
- // Only fetch tasks if the challenge is in a usable status. Otherwise
- // we risk errors if the tasks are still building or failed to build.
- if (isUsableChallengeStatus(challenge.status, true)) {
- this.setState({loadingTasks: true})
- this.props.fetchClusteredTasks(challengeId).then(() =>
- this.setState({loadingTasks: false})
- )
- }
- else {
- this.setState({loadingTasks: false})
- }
- }
})
}
else {
- this.setState({loadingChallenge: false, loadingTasks: false})
+ this.setState({loadingChallenge: false})
}
}
@@ -89,23 +71,16 @@ const WithCurrentChallenge = function(WrappedComponent,
challengeDenormalizationSchema(),
this.props.entities)
)
-
- if (includeTasks &&
- _get(this.props, 'clusteredTasks.challengeId') === challengeId) {
- clusteredTasks = this.props.clusteredTasks
- }
}
return