Skip to content

Commit

Permalink
Merge pull request #4684 from hotosm/develop
Browse files Browse the repository at this point in the history
v4.4.7 release
  • Loading branch information
willemarcel authored May 25, 2021
2 parents 55c6bc8 + 2c2170f commit 563a5a9
Show file tree
Hide file tree
Showing 20 changed files with 613 additions and 502 deletions.
3 changes: 3 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -334,3 +334,6 @@ workflows:
- deployment/hot-tasking-manager
stack_name: "tm4-production"
context: tasking-manager-tm4-production
notify:
webhooks:
-url: https://api.opsgenie.com/v1/json/circleci?apiKey=$OPSGENIE_API
9 changes: 9 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,12 @@
- scripts/docker/**/*
- scripts/install/**/*
- docker-*.yml
"dependencies":
- frontend/yarn.lock
- ./requirements.txt
"javascript":
- frontend/yarn.lock
"python":
- ./requirements.txt
"Type: Translations":
- frontend/src/locales/*
5 changes: 0 additions & 5 deletions backend/services/messaging/message_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,11 +536,6 @@ def _get_managers(message: str, project_id: int) -> List[str]:
team_members = [item for sublist in team_members for item in sublist]
project_managers.extend(team_members)

# Add organization managers.
if project.organisation is not None:
org_usernames = [u.username for u in project.organisation.managers]
project_managers.extend(org_usernames)

return project_managers

@staticmethod
Expand Down
28 changes: 14 additions & 14 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@
"license": "BSD-2-Clause",
"private": false,
"dependencies": {
"@formatjs/intl-locale": "^2.4.24",
"@formatjs/intl-pluralrules": "^4.0.18",
"@formatjs/intl-relativetimeformat": "^8.1.8",
"@formatjs/intl-locale": "^2.4.28",
"@formatjs/intl-pluralrules": "^4.0.22",
"@formatjs/intl-relativetimeformat": "^9.1.2",
"@formatjs/macro": "^0.2.8",
"@hotosm/id": "^2.19.6",
"@hotosm/iso-countries-languages": "^1.1.1",
"@lokibai/react-use-copy-clipboard": "^1.0.4",
"@mapbox/geo-viewport": "^0.4.1",
"@mapbox/mapbox-gl-draw": "^1.2.2",
"@mapbox/mapbox-gl-draw": "^1.3.0",
"@mapbox/mapbox-gl-geocoder": "^4.7.0",
"@mapbox/mapbox-gl-language": "^0.10.1",
"@reach/router": "^1.3.4",
"@sentry/react": "^6.3.6",
"@sentry/tracing": "^6.3.6",
"@sentry/react": "^6.4.1",
"@sentry/tracing": "^6.4.1",
"@tmcw/togeojson": "^4.4.1",
"@turf/area": "^6.3.0",
"@turf/bbox": "^6.3.0",
Expand All @@ -29,7 +29,7 @@
"@turf/truncate": "^6.3.0",
"@webscopeio/react-textarea-autocomplete": "^4.7.3",
"axios": "^0.21.1",
"chart.js": "^3.2.1",
"chart.js": "^3.3.0",
"date-fns": "^2.21.3",
"dompurify": "^2.2.8",
"downshift-hooks": "^0.8.1",
Expand All @@ -39,7 +39,7 @@
"immutable": "^4.0.0-rc.12",
"mapbox-gl": "^1.13.1",
"mapbox-gl-draw-rectangle-mode": "^1.0.4",
"marked": "^2.0.3",
"marked": "^2.0.5",
"osmtogeojson": "^3.0.0-beta.3",
"query-string": "^7.0.0",
"react": "^17.0.2",
Expand All @@ -51,7 +51,7 @@
"react-dom": "^17.0.2",
"react-dropzone": "^11.3.2",
"react-final-form": "^6.5.3",
"react-intl": "^5.17.5",
"react-intl": "^5.18.1",
"react-meta-elements": "^1.0.0",
"react-placeholder": "^4.1.0",
"react-redux": "^7.2.4",
Expand All @@ -61,7 +61,7 @@
"reactjs-popup": "^1.5.0",
"redux": "^4.1.0",
"redux-thunk": "^2.3.0",
"sass": "^1.32.12",
"sass": "^1.34.0",
"short-number": "^1.0.7",
"shpjs": "^3.6.3",
"slug": "^5.0.1",
Expand Down Expand Up @@ -105,12 +105,12 @@
},
"devDependencies": {
"@testing-library/jest-dom": "^5.12.0",
"@testing-library/react": "^11.2.6",
"@testing-library/react-hooks": "^5.1.2",
"@testing-library/user-event": "^13.1.8",
"@testing-library/react": "^11.2.7",
"@testing-library/react-hooks": "^7.0.0",
"@testing-library/user-event": "^13.1.9",
"combine-react-intl-messages": "^4.0.0",
"jest-canvas-mock": "^2.3.1",
"msw": "^0.28.2",
"msw": "^0.29.0",
"prettier": "^2.3.0",
"react-select-event": "^5.3.0",
"react-test-renderer": "^17.0.2",
Expand Down
29 changes: 14 additions & 15 deletions frontend/src/components/comments/commentInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ import FileRejections from './fileRejections';
import DropzoneUploadStatus from './uploadStatus';
import { DROPZONE_SETTINGS } from '../../config';

export const CommentInputField = ({ comment, setComment, enableHashtagPaste = false }: Object) => {
const token = useSelector((state) => state.auth.get('token'));
export const CommentInputField = ({
comment,
setComment,
enableHashtagPaste = false,
autoFocus,
}: Object) => {
const appendImgToComment = (url) => setComment(`${comment}\n![image](${url})\n`);
const [uploadError, uploading, onDrop] = useOnDrop(appendImgToComment);
const { fileRejections, getRootProps, getInputProps } = useDropzone({
Expand All @@ -25,7 +29,7 @@ export const CommentInputField = ({ comment, setComment, enableHashtagPaste = fa
inputProps={getInputProps}
value={comment}
setValueFn={(e) => setComment(e.target.value)}
token={token}
autoFocus={autoFocus}
/>
{comment && enableHashtagPaste && (
<span className="blue-grey f6 pt2">
Expand All @@ -40,27 +44,22 @@ export const CommentInputField = ({ comment, setComment, enableHashtagPaste = fa
);
};

export const UserFetchTextarea = ({ value, setValueFn, token, inputProps }) => {
export const UserFetchTextarea = ({ value, setValueFn, inputProps, autoFocus }) => {
const token = useSelector((state) => state.auth.get('token'));
const fetchUsers = async (user) => {
const url = `users/queries/filter/${user}/`;
let userItems;

try {
const res = await fetchLocalJSONAPI(url, token);
userItems = res.usernames.map((u) => {
return { name: u };
});
const res = await fetchLocalJSONAPI(`users/queries/filter/${user}/`, token);
return res.usernames.map((u) => ({ name: u }));
} catch (e) {
userItems = [];
return [];
}

return userItems;
};

return (
<ReactTextareaAutocomplete
{...inputProps}
value={value}
innerRef={(textArea) => autoFocus && textArea && textArea.focus()}
listClassName="list ma0 pa0 ba b--grey-light bg-blue-grey overflow-y-scroll base-font f5 relative z-5"
listStyle={{ maxHeight: '16rem' }}
onChange={setValueFn}
Expand All @@ -72,7 +71,7 @@ export const UserFetchTextarea = ({ value, setValueFn, token, inputProps }) => {
'@': {
dataProvider: fetchUsers,
component: Item,
output: (item, trigger) => '@[' + item.name + ']',
output: (item, trigger) => `@[${item.name}]`,
},
}}
/>
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/components/projectEdit/priorityAreasForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,10 +239,9 @@ export const PriorityAreasForm = () => {
mapObj.map.on('load', () => {
mapObj.map.addControl(mapObj.draw);
addMapLayers(mapObj.map);
mapObj.map.fitBounds(projectInfo.aoiBBOX, { duration: 0, padding: 100 });
});

mapObj.map.fitBounds(projectInfo.aoiBBOX, { duration: 0, padding: 100 });

mapObj.map.on('styledata', () => {
addMapLayers(mapObj.map);
if (mapObj.map.getSource('priority_areas') !== undefined) {
Expand Down
11 changes: 7 additions & 4 deletions frontend/src/components/projects/filterSelectFields.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,10 @@ export const TagFilterPickerAutocomplete = ({
}
};
const getValue = (option) => {
if (option.value) {
if (option && option.value) {
return option.value;
}
if (option.name) {
if (option && option.name) {
return option.name;
}
return option;
Expand All @@ -131,12 +131,14 @@ export const TagFilterPickerAutocomplete = ({
{
...allQueryParams,
page: undefined,
[fieldsetName]: newValue,
[fieldsetName]: newValue || undefined,
},
'pushIn',
);
};

const [selectedOption] = tagOptions.filter((option) => option.name === queryParamSelectedItem);

return (
<Select
onChange={handleTagChange}
Expand All @@ -146,7 +148,8 @@ export const TagFilterPickerAutocomplete = ({
autoFocus={true}
placeholder={allQueryParams[fieldsetName] || fieldsetTitle}
options={tagOptions}
value={queryParamSelectedItem}
value={selectedOption || null}
isClearable={true}
/>
);
};
35 changes: 18 additions & 17 deletions frontend/src/components/taskSelection/actionSidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ export function CompletionTabForMapping({
value="MAPPED"
className={radioInput}
checked={selectedStatus === 'MAPPED'}
onClick={() => setSelectedStatus('MAPPED')}
onChange={() => setSelectedStatus('MAPPED')}
/>
<label htmlFor="MAPPED">
<FormattedMessage {...messages.complete} />
Expand All @@ -187,7 +187,7 @@ export function CompletionTabForMapping({
value="READY"
className={radioInput}
checked={selectedStatus === 'READY'}
onClick={() => setSelectedStatus('READY')}
onChange={() => setSelectedStatus('READY')}
/>
<label htmlFor="READY">
<FormattedMessage {...messages.incomplete} />
Expand All @@ -201,7 +201,7 @@ export function CompletionTabForMapping({
value="BADIMAGERY"
className={radioInput}
checked={selectedStatus === 'BADIMAGERY'}
onClick={() => setSelectedStatus('BADIMAGERY')}
onChange={() => setSelectedStatus('BADIMAGERY')}
/>
<label htmlFor="BADIMAGERY">
<FormattedMessage {...messages.badImagery} />
Expand Down Expand Up @@ -430,21 +430,21 @@ const TaskValidationSelector = ({
<label htmlFor="INVALIDATED">
<FormattedMessage {...messages.incomplete} />
</label>
{currentStatus && (
<CustomButton
className={`${
showCommentInput ? 'b--red red' : 'b--grey-light blue-dark'
} bg-white ba br1 ml3 pv2 ph3`}
onClick={() => setShowCommentInput(!showCommentInput)}
>
{comment ? (
<CommentIcon className="h1 w1 v-mid mr1" />
<CustomButton
className={`${
showCommentInput ? 'b--red red' : 'b--grey-light blue-dark'
} bg-white ba br1 ml3 pv2 ph3`}
onClick={() => setShowCommentInput(!showCommentInput)}
icon={
comment ? (
<CommentIcon className="h1 w1 v-mid" />
) : (
<PlusIcon className="h1 w1 mr1 v-mid" />
)}
<FormattedMessage {...messages.comment} />
</CustomButton>
)}
<PlusIcon className="h1 w1 v-mid" />
)
}
>
<FormattedMessage {...messages.comment} />
</CustomButton>
</div>
</div>
{showCommentInput && (
Expand All @@ -454,6 +454,7 @@ const TaskValidationSelector = ({
comment={comment}
setComment={setComment}
enableHashtagPaste={false}
autoFocus={true}
/>
</div>
{isValidatingMultipleTasks && comment && (
Expand Down
31 changes: 2 additions & 29 deletions frontend/src/components/taskSelection/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import { useSelector, useDispatch } from 'react-redux';
import { useQueryParam, StringParam } from 'use-query-params';
import Popup from 'reactjs-popup';
import ReactPlaceholder from 'react-placeholder';
import { FormattedMessage } from 'react-intl';

import messages from './messages';
import { useFetch } from '../../hooks/UseFetch';
import { useInterval } from '../../hooks/UseInterval';
import { useGetLockedTasks } from '../../hooks/UseLockedTasks';
Expand All @@ -16,6 +14,7 @@ import { getRandomArrayItem } from '../../utils/random';
import { updateTasksStatus } from '../../utils/updateTasksStatus';
import { fetchLocalJSONAPI } from '../../network/genericJSONRequest';
import { TasksMap } from './map.js';
import { TabSelector } from './tabSelector.js';
import { TaskList } from './taskList';
import { TasksMapLegend } from './legend';
import { ProjectInstructions } from './instructions';
Expand Down Expand Up @@ -294,33 +293,7 @@ export function TaskSelection({ project, type, loading }: Object) {
>
<ProjectHeader project={project} />
<div className="cf">
<div className="cf ttu barlow-condensed f4 pv2 blue-dark">
<span
className={`mr4 pb2 pointer ${activeSection === 'tasks' && 'bb b--blue-dark'}`}
onClick={() => setActiveSection('tasks')}
>
<FormattedMessage {...messages.tasks} />
</span>
<span
className={`mr4 pb2 pointer ${
activeSection === 'instructions' && 'bb b--blue-dark'
}`}
onClick={() => setActiveSection('instructions')}
>
<FormattedMessage {...messages.instructions} />
</span>
<span
className={`mr4 pb2 pointer ${
activeSection === 'contributions' && 'bb b--blue-dark'
}`}
onClick={() => {
getContributions(project.projectId);
setActiveSection('contributions');
}}
>
<FormattedMessage {...messages.contributions} />
</span>
</div>
<TabSelector activeSection={activeSection} setActiveSection={setActiveSection} />
<div className="pt3">
<div className={`${activeSection !== 'tasks' ? 'dn' : ''}`}>
<TaskList
Expand Down
17 changes: 17 additions & 0 deletions frontend/src/components/taskSelection/tabSelector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { FormattedMessage } from 'react-intl';

import messages from './messages';

export const TabSelector = ({ activeSection, setActiveSection }) => (
<div className="cf ttu barlow-condensed f4 pv2 blue-dark">
{['tasks', 'instructions', 'contributions'].map((section) => (
<span
key={section}
className={`mr4 pb1 pointer ${activeSection === section && 'bb bw1 b--blue-dark'}`}
onClick={() => setActiveSection(section)}
>
<FormattedMessage {...messages[section]} />
</span>
))}
</div>
);
2 changes: 1 addition & 1 deletion frontend/src/components/taskSelection/taskActivity.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const TaskHistory = ({ projectId, taskId, commentPayload }) => {
const [shownHistory, setShownHistory] = useState([]);

useEffect(() => {
if (commentPayload) {
if (commentPayload && commentPayload.taskHistory) {
setHistory(commentPayload.taskHistory);
setTaskComments(commentPayload.taskHistory.filter((t) => t.action === 'COMMENT'));
setTaskChanges(commentPayload.taskHistory.filter((t) => t.action !== 'COMMENT'));
Expand Down
Loading

0 comments on commit 563a5a9

Please sign in to comment.