-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Show active users modal #2863
Show active users modal #2863
Conversation
…ects-view that displays all users with open tasks of the selected project in a modal
…d a modified copy of the task_transfer_modal to control a bulk task transfer
…hold, waiting for backend to provide the api request
…real functionallity
@MichaelBuessemeyer: Please add the change notes from this PR to the changelog |
…-api-request-for-open-tasks
…w-active-users-modal
…bknossos into add-api-request-for-open-tasks
CHANGELOG.md
Outdated
- Added permission for team managers to refresh datasets. [#2688](https://github.com/scalableminds/webknossos/pull/2688) | ||
- Added backend-unit-test setup and a first test for NML validation. [#2829](https://github.com/scalableminds/webknossos/pull/2829) | ||
|
||
* Added a button to the administration/project-tab, that displays a modal with all users with active annotations of the selected project. All these annotations can be transfered to a single user [#2670](https://github.com/scalableminds/webknossos/issues/2670) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MichaelBuessemeyer You accidently re-formatted the whole CHANGELOG.md file (or better, the prettier sublime plugin did). Please revert the changes in this file, add the following to your JsPrettier sublime user config: "auto_format_on_save_excludes": ["*/node_modules/*","*.md"]
(so .md files are no longer "prettified", and then re-add your changelog entry :)
…to display the table in the modal
…tive tasks of a project, transfer modal only renders if set to visible
…and change api call to post-type
…bknossos into show-active-users-modal
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome, nice work, @MichaelBuessemeyer! The code looks really good and idiomatic 👍
Nevertheless, I made a few remarks on how to improve the code even further. Most of them are minor things and should be quick to fix, so don't feel overwhelmed :)
I'll test after the next iteration!
}); | ||
}; | ||
|
||
transferCommited = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rename this to onTaskTransferComplete
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function is not used at the moment, right? Shouldn't it be called when the modal is closed?
@@ -283,6 +302,13 @@ class ProjectListView extends React.PureComponent<Props, State> { | |||
/> | |||
</Table> | |||
</Spin> | |||
{this.state.isTransferTasksVisible ? ( | |||
<TransferAllTasksModal | |||
visible={this.state.isTransferTasksVisible} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Due to the ternary from two lines above, this prop will always be true
. You can remove it.
|
||
type Props = { | ||
project: ?APIProjectType, | ||
onCancel: Function, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use () => void
instead of Function
? This is more precise, as it specifies the types of the variables and the return value.
if (this.props.project) { | ||
usersWithActiveTasks = await getUsersWithActiveTasks(this.props.project.name); | ||
} | ||
this.setState({ isLoading: false, usersWithActiveTasks }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can combine this setState
call with the one in line 56.
} | ||
|
||
async fetchData() { | ||
this.setState({ isLoading: true }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please structure this function like this so that potential errors from the server, won't freeze the view.
try {
this.setState({ isLoading: true });
// .... await ...
} except (error) {
handleGenericError(error);
} finally {
this.setState({isLoading: false});
}
Otherwise, isLoading
would never be set to false if a request fails. handleGenericError
can be imported from error_handling.js
.
} | ||
const project = this.props.project; | ||
if (!project) { | ||
Toast.error(messages["project.none_selected"]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When does this happen? Showing a toast is a side effect (if the render function is called twice and this block is executed, there will be two toast notifications). In general, side effects should be avoided within the render function, as it can be executed various times. In this specific scenario, I would just remove the toast.error line. Instead leave the return null
line.
Toast.error(messages["project.none_selected"]); | ||
return null; | ||
} else { | ||
Toast.close(messages["project.none_selected"]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here. If you would like to show such message (when does this happen?), you can just return the message, as this will be the content of the modal.
return ( | ||
<Modal | ||
title={title} | ||
visible={this.props.visible} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the modal will always be visible when this component is rendered you can just write <Modal title={title} visible onCancel=...
.
> | ||
Transfer all tasks | ||
</Button> | ||
<Button onClick={() => this.props.onCancel()}>Close</Button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can just write onClick={this.props.onCancel}
. The arrow function would be important, if the context is important. However, the parent component has to take care of that, anyway, since you are getting that value from props
.
In line 164, you could also write onClick={this.transferAllActiveTasks}
if you define the corresponding function like transferAllActiveTasks = async () => {...
. However, the current way is also fine :)
app/assets/javascripts/messages.js
Outdated
@@ -90,6 +90,11 @@ In order to restore the current window, a reload is necessary.`, | |||
"project.delete": "Do you really want to delete this project?", | |||
"project.increase_instances": | |||
"Do you really want to add one additional instance to all tasks of this project?", | |||
"project.none_selected": "No currently selected project found", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make sure that the messages are ended with a fullstop.
@fm3 Can you review the backend code? |
|
||
renderFormContent() { | ||
return ( | ||
<Select |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You copied that code from the transfer_task_modal, right? If you feel like it, you can share this code by creating a new <UserSelectionComponent />
component. The approach would be very similar to the TeamSelectionComponent
which abstracts the same thing for teams. If you think it's to much for this PR, please add a comment above this line here (e.g., "Todo: create a component which is used here and in transfer_task_modal").
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Backend LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made some last, small remarks :) Will test now!
CHANGELOG.md
Outdated
@@ -18,8 +18,9 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.md). | |||
- Added shortcuts for moving along the current tracing direction in orthogonal mode. Pressing 'e' (and 'r' for the reverse direction) will move along the "current direction", which is defined by the vector between the last two created nodes. | |||
- Added a banner to the user list to notify admins of new inactive users that need to be activated. [#2994](https://github.com/scalableminds/webknossos/pull/2994) | |||
- When a lot of changes need to be persisted to the server (e.g., after importing a large NML), the save button will show a percentage-based progress indicator. | |||
- Added placeholders and functionality hints to (nearly) empty lists and tables in the admin views. [#2969](https://github.com/scalableminds/webknossos/pull/2969) | |||
- Added the possibility for admins to see and transfer all active tasks of a project to a single user in the porject tab[#2863](https://github.com/scalableminds/webknossos/pull/2863) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo in project :)
}); | ||
} catch (error) { | ||
handleGenericError(error); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add an isLoading
attribute to the component's state. This attribute should be set to true before fetching, and set to false in a finally
block after catch. Similar to:
try {
this.setState({
isLoading: true,
});
const updatedProject = await increaseProjectTaskInstances(project.name);
this.setState({
projects: this.state.projects.map(p => (p.id === project.id ? updatedProject : p)),
});
} catch (error) {
handleGenericError(error);
} finally {
this.setState({ isLoading: false });
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then, use the isLoading
attribute to render a spin component. Similar to
render() {
return <Spin spinning={this.state.isLoading} size="large"> ... </Spin>;
}
Not sure how I managed to do this, but I think something is not right with the back-end part. @fm3 Can you have a look? I created a second user and a second project B. For both projects I created some tasks, and requested them for both users. Afterwards, I transferred the tasks. For the task of project B, the tasks route does give me an annotation, but the This leads to an error message (front-end says: "Annotation 5b6d70a27d0000d100b4f2bf has no task assigned. Please inform your admin.") and none of the tasks are rendered in the task lists because of that. When I transfer all the tasks back to scmboy, I don't get the error anymore. Only the one task of project B is causing this 🤔 |
@philippotto Good catch! This happens when the user has no read access to the annotation’s dataset. I just pushed a commit that forbids this transfer entirely. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome 👍 Should be good to go, now.
@fm3 This PR doesn't need a special deployment (migration / datastore update), right?
Just tested it and there is a comprehensible error message 👍 It might be useful to say "transfer all tasks which whose datasets are accessible for the user", but I'd wait until this feature is actually requested from the lab. |
yes, does not contain datastore or schema changes :) |
Mailable description of changes:
URL of deployed dev instance (used for testing):
Steps to test:
Issues: