Skip to content
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

Merged
merged 32 commits into from
Aug 13, 2018
Merged

Show active users modal #2863

merged 32 commits into from
Aug 13, 2018

Conversation

MichaelBuessemeyer
Copy link
Contributor

@MichaelBuessemeyer MichaelBuessemeyer commented Jul 9, 2018

Mailable description of changes:

  • Admins now can see and transfer all active tasks of a project to a single user

URL of deployed dev instance (used for testing):

Steps to test:

  • go to the admin -> projects
  • use the show active users button on the right side to open the modal
  • check the table if its showing all users with their active tasks
  • select a user and then transfer the active tasks to the user (a toast should show up to confirm the transfer)
  • then check the tasks-tab from the dashboard to confirm the transfer

Issues:


  • Ready for review

…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
@jstriebel
Copy link
Contributor

@MichaelBuessemeyer: Please add the change notes from this PR to the changelog

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)
Copy link
Member

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 :)

@philippotto philippotto changed the title [WIP] Show active users modal Show active users modal Jul 13, 2018
Copy link
Member

@philippotto philippotto left a 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 = () => {
Copy link
Member

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.

Copy link
Member

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}
Copy link
Member

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,
Copy link
Member

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 });
Copy link
Member

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 });
Copy link
Member

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"]);
Copy link
Member

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"]);
Copy link
Member

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}
Copy link
Member

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>
Copy link
Member

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 :)

@@ -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",
Copy link
Member

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.

@philippotto
Copy link
Member

@fm3 Can you review the backend code?

@philippotto philippotto requested a review from fm3 July 13, 2018 13:26

renderFormContent() {
return (
<Select
Copy link
Member

@philippotto philippotto Jul 13, 2018

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").

Copy link
Member

@fm3 fm3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backend LGTM

@philippotto philippotto modified the milestones: Sprint 25a, Sprint 24a Aug 6, 2018
Copy link
Member

@philippotto philippotto left a 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)
Copy link
Member

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);
}
Copy link
Member

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 });
        }

Copy link
Member

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>;
}

@philippotto
Copy link
Member

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 task attribute is null?

image

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 🤔

@fm3
Copy link
Member

fm3 commented Aug 13, 2018

@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.
Do we expect to merge this today? Because part of that bug exists in master, so I would create a separate PR to fix it faster.

Copy link
Member

@philippotto philippotto left a 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?

@philippotto
Copy link
Member

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.

@fm3
Copy link
Member

fm3 commented Aug 13, 2018

This PR doesn't need a special deployment (migration / datastore update), right?

yes, does not contain datastore or schema changes :)

@fm3 fm3 merged commit d099fd7 into master Aug 13, 2018
@philippotto philippotto deleted the show-active-users-modal branch August 13, 2018 11:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants