Skip to content

Commit e09aa07

Browse files
authored
Merge pull request #657 from osmlab/prerelease
v3.2.1
2 parents 7d83ed0 + bf75f86 commit e09aa07

File tree

36 files changed

+515
-355
lines changed

36 files changed

+515
-355
lines changed

CHANGELOG.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,26 @@ The format is based on
77
This project adheres to
88
[Semantic Versioning](http://semver.org/spec/v2.0.0.html).
99

10-
## [v3.2] - 2019-02-15
10+
## [v3.2.1] - 2019-02-25
11+
### Added
12+
- Create & Manage widget for managing project managers (#534)
13+
14+
### Fixed
15+
- Excessive removal of unmatched tasks for line-by-line geojson by @Zverik
16+
- Error when attempting to display zero points in points ticker
17+
- Disallowed task status progressions sometimes offered in task completion
18+
- Dropdown menus extending over widgets sometimes not fully interactive
19+
- Modals sometimes appear behind widgets instead of in front of them
20+
- Incorrect rendering of user settings form in Chrome
21+
22+
### Changed
23+
- Name of User Profile page to User Settings
24+
25+
### Removed
26+
- Tabs on Create & Manage project cards; only challenges are now shown
27+
28+
29+
## [v3.2.0] - 2019-02-15
1130
### Added
1231
- New user interface
1332
- Full-fledged home page (#426)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "maproulette3",
3-
"version": "3.2",
3+
"version": "3.2.1",
44
"private": true,
55
"dependencies": {
66
"@mapbox/geojsonhint": "^2.0.1",

src/components/AdminPane/AdminPane.scss

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,17 @@
7070
&__manage {
7171
&__header {
7272
display: flex;
73-
flex-wrap: wrap;
73+
flex-direction: column;
7474
align-items: flex-start;
75-
justify-content: space-between;
75+
justify-content: flex-start;
7676
margin-top: 0;
7777
margin-bottom: 20px;
7878
}
7979

80+
&__header--flush {
81+
margin-bottom: 0;
82+
}
83+
8084
.subtitle, .subtitle:not(:last-child) {
8185
margin-top: 1em;
8286
margin-bottom: 0.5em;
@@ -107,9 +111,16 @@
107111
font-size: $size-5;
108112
margin-bottom: 0;
109113
color: $white;
114+
margin-bottom: 0.5em;
115+
116+
ul {
117+
flex-wrap: wrap;
118+
max-width: 75vw;
119+
}
110120

111121
li a {
112122
color: $white;
123+
line-height: 16px;
113124
}
114125

115126
li.is-active a {

src/components/AdminPane/HOCs/WithChallengeManagement/WithChallengeManagement.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ async function uploadLineByLine(dispatch, ownProps, challenge, geoJSON, removeUn
3838
const lineFile = AsLineReadableFile(geoJSON)
3939
let allLinesRead = false
4040
let totalTasksCreated = 0
41+
let removeUnmatched = removeUnmatchedTasks
4142

4243
while (!allLinesRead) {
4344
let taskLines = await lineFile.readLines(100)
@@ -47,8 +48,9 @@ async function uploadLineByLine(dispatch, ownProps, challenge, geoJSON, removeUn
4748
}
4849

4950
await dispatch(
50-
uploadChallengeGeoJSON(challenge.id, taskLines.join('\n'), true, removeUnmatchedTasks)
51+
uploadChallengeGeoJSON(challenge.id, taskLines.join('\n'), true, removeUnmatched)
5152
)
53+
removeUnmatched = false
5254
totalTasksCreated += taskLines.length
5355
ownProps.updateCreatingTasksProgress(true, totalTasksCreated)
5456
}

src/components/AdminPane/HOCs/WithCurrentProject/WithCurrentProject.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ const WithCurrentProject = function(WrappedComponent, options={}) {
7171
}
7272

7373
loadProject = props => {
74+
if (props.loadingProjects) {
75+
return
76+
}
77+
7478
const projectId = this.currentProjectId(props)
7579

7680
if (_isFinite(this.routedProjectId(props)) && projectId === null) {
@@ -139,11 +143,16 @@ const WithCurrentProject = function(WrappedComponent, options={}) {
139143
}
140144
}
141145

142-
componentWillMount() {
146+
componentDidMount() {
143147
this.loadProject(this.props)
144148
}
145149

146150
componentWillReceiveProps(nextProps) {
151+
if (this.props.loadingProjects && !nextProps.loadingProjects) {
152+
this.loadProject(nextProps)
153+
return
154+
}
155+
147156
const nextProjectId = this.currentProjectId(nextProps)
148157

149158
if ( _isFinite(nextProjectId) &&

src/components/AdminPane/Manage/ChallengeDashboard/ChallengeDashboard.js

Lines changed: 123 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Link } from 'react-router-dom'
55
import _get from 'lodash/get'
66
import _map from 'lodash/map'
77
import _compact from 'lodash/compact'
8+
import _isEmpty from 'lodash/isEmpty'
89
import AsManager from '../../../../interactions/User/AsManager'
910
import { generateWidgetId, WidgetDataTarget, widgetDescriptor }
1011
from '../../../../services/Widget/Widget'
@@ -22,23 +23,18 @@ import WithFilteredClusteredTasks
2223
from '../../HOCs/WithFilteredClusteredTasks/WithFilteredClusteredTasks'
2324
import WithChallengeMetrics
2425
from '../../HOCs/WithChallengeMetrics/WithChallengeMetrics'
25-
import WithDeactivateOnOutsideClick
26-
from '../../../HOCs/WithDeactivateOnOutsideClick/WithDeactivateOnOutsideClick'
2726
import WidgetWorkspace from '../../../WidgetWorkspace/WidgetWorkspace'
2827
import RebuildTasksControl from '../RebuildTasksControl/RebuildTasksControl'
2928
import TaskUploadingProgress
3029
from '../TaskUploadingProgress/TaskUploadingProgress'
31-
import DropdownButton from '../../../Bulma/DropdownButton'
32-
import BusySpinner from '../../../BusySpinner/BusySpinner'
30+
import Dropdown from '../../../Dropdown/Dropdown'
3331
import SvgSymbol from '../../../SvgSymbol/SvgSymbol'
32+
import BusySpinner from '../../../BusySpinner/BusySpinner'
3433
import ConfirmAction from '../../../ConfirmAction/ConfirmAction'
3534
import manageMessages from '../Messages'
3635
import messages from './Messages'
3736
import './ChallengeDashboard.scss'
3837

39-
// Setup child components with needed HOCs.
40-
const DeactivatableDropdownButton = WithDeactivateOnOutsideClick(DropdownButton)
41-
4238
// The name of this dashboard.
4339
const DASHBOARD_NAME = "challenge"
4440

@@ -98,113 +94,139 @@ export class ChallengeDashboard extends Component {
9894

9995
const manager = AsManager(this.props.user)
10096
const projectId = _get(this.props, 'challenge.parent.id')
97+
const status = _get(this.props, 'challenge.status', ChallengeStatus.none)
98+
const hasTasks = _get(this.props, 'challenge.actions.total', 0) > 0
10199

102-
const managedProjectOptions = _compact(_map(this.props.projects, project => {
103-
if (project.id === projectId || !manager.canWriteProject(project)) {
104-
return null
105-
}
100+
const pageHeader = (
101+
<div className="admin__manage__header admin__manage__header--flush">
102+
<nav className="breadcrumb" aria-label="breadcrumbs">
103+
<ul>
104+
<li>
105+
<Link to='/admin/projects'>
106+
<FormattedMessage {...manageMessages.manageHeader} />
107+
</Link>
108+
</li>
109+
<li>
110+
<Link to={`/admin/project/${projectId}`}>
111+
{_get(this.props, 'challenge.parent.displayName') ||
112+
_get(this.props, 'challenge.parent.name')}
113+
</Link>
114+
</li>
115+
<li className="is-active">
116+
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
117+
<a aria-current="page">
118+
{this.props.challenge.name}
119+
{this.props.loadingChallenge && <BusySpinner inline />}
120+
</a>
121+
</li>
122+
</ul>
123+
</nav>
106124

107-
return {
108-
key: `project-${project.id}`,
109-
text: project.displayName ? project.displayName : project.name,
110-
projectId: project.id,
111-
}
112-
}))
125+
<div className="admin__manage__controls mr-flex">
126+
{hasTasks && isUsableChallengeStatus(status, true) &&
127+
<Link to={`/challenge/${this.props.challenge.id}`}
128+
className="mr-text-green-lighter hover:mr-text-white mr-mr-4">
129+
<FormattedMessage {...messages.startChallengeLabel} />
130+
</Link>
131+
}
113132

114-
const status = _get(this.props, 'challenge.status', ChallengeStatus.none)
115-
const hasTasks = _get(this.props, 'challenge.actions.total', 0) > 0
133+
{manager.canWriteProject(this.props.challenge.parent) &&
134+
<React.Fragment>
135+
<Link to={`/admin/project/${projectId}/` +
136+
`challenge/${this.props.challenge.id}/edit`}
137+
className="mr-text-green-lighter hover:mr-text-white mr-mr-4">
138+
<FormattedMessage {...messages.editChallengeLabel } />
139+
</Link>
116140

117-
return (
118-
<div className="admin__manage challenge-dashboard">
119-
<div className="admin__manage__header">
120-
<nav className="breadcrumb" aria-label="breadcrumbs">
121-
<ul>
122-
<li>
123-
<Link to='/admin/projects'>
124-
<FormattedMessage {...manageMessages.manageHeader} />
125-
</Link>
126-
</li>
127-
<li>
128-
<Link to={`/admin/project/${projectId}`}>
129-
{_get(this.props, 'challenge.parent.displayName') ||
130-
_get(this.props, 'challenge.parent.name')}
131-
</Link>
132-
</li>
133-
<li className="is-active">
141+
{_get(this.props, 'projects.length', 0) > 1 &&
142+
<Dropdown
143+
className="mr-dropdown--fixed"
144+
dropdownButton={dropdown => (
145+
// eslint-disable-next-line jsx-a11y/anchor-is-valid
146+
<a onClick={dropdown.toggleDropdownVisible}
147+
className="mr-text-green-lighter hover:mr-text-white mr-mr-4 mr-flex mr-items-center"
148+
>
149+
<FormattedMessage {...messages.moveChallengeLabel} />
150+
<SvgSymbol
151+
sym="icon-cheveron-down"
152+
viewBox="0 0 20 20"
153+
className="mr-fill-current mr-w-5 mr-h-5"
154+
/>
155+
</a>
156+
)}
157+
dropdownContent={dropdown =>
158+
<ListManagedProjectItems
159+
{...this.props}
160+
currentProjectId={projectId}
161+
manager={manager}
162+
/>
163+
}
164+
/>
165+
}
166+
167+
{this.props.challenge.isRebuildable() &&
168+
<RebuildTasksControl {...this.props} />
169+
}
170+
171+
<Link to={{pathname: `/admin/project/${projectId}/` +
172+
`challenge/${this.props.challenge.id}/clone`,
173+
state: {cloneChallenge: true}}}
174+
className="mr-text-green-lighter hover:mr-text-white mr-mr-4">
175+
<FormattedMessage {...messages.cloneChallengeLabel } />
176+
</Link>
177+
178+
<ConfirmAction>
134179
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
135-
<a aria-current="page">
136-
{this.props.challenge.name}
137-
{this.props.loadingChallenge && <BusySpinner inline />}
180+
<a onClick={this.deleteChallenge}
181+
className="mr-text-green-lighter hover:mr-text-white mr-mr-4">
182+
<FormattedMessage {...messages.deleteChallengeLabel } />
138183
</a>
139-
</li>
140-
</ul>
141-
</nav>
142-
143-
<div className="columns admin__manage__controls">
144-
{hasTasks && isUsableChallengeStatus(status, true) &&
145-
<div className="column is-narrow admin__manage__controls--control">
146-
<Link to={`/challenge/${this.props.challenge.id}`}>
147-
<FormattedMessage {...messages.startChallengeLabel} />
148-
</Link>
149-
</div>
150-
}
151-
152-
{manager.canWriteProject(this.props.challenge.parent) &&
153-
<React.Fragment>
154-
<div className="column is-narrow admin__manage__controls--control">
155-
<Link to={`/admin/project/${projectId}/` +
156-
`challenge/${this.props.challenge.id}/edit`}>
157-
<FormattedMessage {...messages.editChallengeLabel } />
158-
</Link>
159-
</div>
160-
161-
{_get(this.props, 'projects.length', 0) > 1 &&
162-
<div className="column is-narrow admin__manage__controls--control">
163-
<DeactivatableDropdownButton options={managedProjectOptions}
164-
onSelect={this.moveChallenge}
165-
emptyContent={<FormattedMessage {...messages.noProjects} />}>
166-
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
167-
<a>
168-
<FormattedMessage {...messages.moveChallengeLabel} />
169-
<div className="basic-dropdown-indicator" />
170-
</a>
171-
</DeactivatableDropdownButton>
172-
</div>
173-
}
174-
175-
{this.props.challenge.isRebuildable() &&
176-
<div className="column is-narrow admin__manage__controls--control">
177-
<RebuildTasksControl {...this.props} />
178-
</div>
179-
}
180-
181-
<div className="column is-narrow admin__manage__controls--control">
182-
<Link to={{pathname: `/admin/project/${projectId}/` +
183-
`challenge/${this.props.challenge.id}/clone`,
184-
state: {cloneChallenge: true}}}>
185-
<FormattedMessage {...messages.cloneChallengeLabel } />
186-
</Link>
187-
</div>
188-
189-
<div className="column is-narrow admin__manage__controls--control">
190-
<ConfirmAction>
191-
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
192-
<a className='button is-clear' onClick={this.deleteChallenge}>
193-
<SvgSymbol sym='trash-icon' className='icon' viewBox='0 0 20 20' />
194-
</a>
195-
</ConfirmAction>
196-
</div>
197-
</React.Fragment>
198-
}
199-
</div>
184+
</ConfirmAction>
185+
</React.Fragment>
186+
}
200187
</div>
188+
</div>
189+
)
201190

202-
<WidgetWorkspace {...this.props} />
191+
return (
192+
<div className="admin__manage challenge-dashboard">
193+
<WidgetWorkspace
194+
{...this.props}
195+
className="mr-mt-4"
196+
workspaceEyebrow={pageHeader}
197+
/>
203198
</div>
204199
)
205200
}
206201
}
207202

203+
const ListManagedProjectItems = function(props) {
204+
const projectItems = _compact(_map(props.projects, project => {
205+
if (project.id === props.currentProjectId ||
206+
!props.manager.canWriteProject(project)) {
207+
return null
208+
}
209+
210+
return (
211+
<li key={`project-${project.id}`}>
212+
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
213+
<a
214+
onClick={() => props.moveChallenge(props.challenge.id, project.id)}
215+
>
216+
{project.displayName ? project.displayName : project.name}
217+
</a>
218+
</li>
219+
)
220+
}))
221+
222+
return _isEmpty(projectItems) ?
223+
<FormattedMessage {...messages.noProjects} /> : (
224+
<ol className="mr-list-dropdown">
225+
{projectItems}
226+
</ol>
227+
)
228+
}
229+
208230
ChallengeDashboard.propTypes = {
209231
/** The parent project of the challenge */
210232
project: PropTypes.object,

0 commit comments

Comments
 (0)