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

feat(#9116): update user place field in admin to allow setting multiple places #9128

Open
wants to merge 50 commits into
base: master
Choose a base branch
from

Conversation

Benmuiruri
Copy link
Contributor

@Benmuiruri Benmuiruri commented May 16, 2024

Description

This is a continuation of #6543

Now, users can be associated with more than one facility. This PR enables the CHT's Admin app to provide a way to associate those facilities with the user.

To get the feature to work, the admin user must enable can_have_multiple_places to some specific roles (e.g Supervisor, community_health_assistant, etc)

Whenever a new user is added:

  • The dialog displays, and the place field is a multiselect dropdown.
  • The admin submits the form and CHT validates:
    • At least one of the selected roles has can_have_multiple_places
    • Selected places are at the same hierarchy level
    • The user should be a child of at least one of the selected places.
  • CHT displays error in form when above validations don't pass successfully.
  • When editing an existing user, the form should load with the multiselect field prefilled with the user's current place or places. On editing a user the form saves changes correctly

Closes #9116

Code review checklist

  • Readable: Concise, well named, follows the style guide, documented if necessary.
  • Documented: Configuration and user documentation on cht-docs
  • Tested: Unit and/or e2e where appropriate
  • Internationalised: All user facing text
  • Backwards compatible: Works with existing data and configuration or includes a migration. Any breaking changes documented in the release notes.

Compose URLs

If Build CI hasn't passed, these may 404:

License

The software is provided under AGPL-3.0. Contributions to this project are accepted under the same license.

@latin-panda
Copy link
Contributor

@Benmuiruri, this is just a reminder to please enable the test tests/e2e/default/more-options-menu/offline-user/all-permissions.wdio-spec.js so that we can have all the tests working again.

Copy link

@ralfudx ralfudx left a comment

Choose a reason for hiding this comment

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

All AC's in the description look good to me

Copy link
Member

@dianabarsan dianabarsan left a comment

Choose a reason for hiding this comment

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

Cool stuff! Great work!
I left some comments mostly about readability and reusability.

admin/src/js/controllers/edit-user.js Show resolved Hide resolved
admin/src/js/controllers/edit-user.js Outdated Show resolved Hide resolved
Comment on lines +246 to +247
const allowedRoles = $scope.permissions.can_have_multiple_places;

const userHasPermission = userRoles.some(role => allowedRoles.includes(role));
Copy link
Member

Choose a reason for hiding this comment

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

I think we're duplicating logic that we already have in the cht script api. This should already be available in the admin app. https://github.com/medic/cht-core/blob/master/admin/src/js/services/auth.js#L65

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, the value of userCtx.roles is admin. It ends up being a check whether current user (Admin) has the permission

Copy link
Member

Choose a reason for hiding this comment

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

Yea, I think you have to call it like:

return chtScriptApi.v1.hasPermissions(['can_have_multiple_places'], $scope.editUserModel.role, settings.permissions);

admin/src/js/controllers/edit-user.js Outdated Show resolved Hide resolved
admin/src/js/controllers/edit-user.js Show resolved Hide resolved
shared-libs/user-management/src/users.js Outdated Show resolved Hide resolved
tests/integration/api/controllers/users.spec.js Outdated Show resolved Hide resolved
webapp/src/ts/modules/contacts/contacts.component.ts Outdated Show resolved Hide resolved
webapp/src/ts/modules/contacts/contacts.component.ts Outdated Show resolved Hide resolved
webapp/src/ts/modules/contacts/contacts.component.ts Outdated Show resolved Hide resolved
@Benmuiruri
Copy link
Contributor Author

Hi @dianabarsan I have made almost all of the requested changes. The one I could not figure out is the suggestion to use _all_docs. Do you mind sharing a suggestion for that one. Thank you 🙏

Base automatically changed from 6543-ui-changes to master June 7, 2024 12:28
@Benmuiruri Benmuiruri force-pushed the 9116-update-admin-place-field branch from 9c72aa4 to 43a970b Compare June 10, 2024 06:18
admin/src/js/services/select2-search.js Dismissed Show dismissed Hide dismissed
Copy link
Member

@dianabarsan dianabarsan left a comment

Choose a reason for hiding this comment

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

Nice work! Some minor things inline to unblock you. I'll give this a try tomorrow!

Comment on lines +246 to +247
const allowedRoles = $scope.permissions.can_have_multiple_places;

const userHasPermission = userRoles.some(role => allowedRoles.includes(role));
Copy link
Member

Choose a reason for hiding this comment

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

Yea, I think you have to call it like:

return chtScriptApi.v1.hasPermissions(['can_have_multiple_places'], $scope.editUserModel.role, settings.permissions);

return DB().allDocs({ keys: placeIds, include_docs: true, limit: docsFetched })
.then(result => {
const places = result.rows.map(row => row.doc);
const contactTypes = new Set(places.map(place => place.contact_type));
Copy link
Member

Choose a reason for hiding this comment

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

I believe that checking the contact_type is not enough here.
A contact can have a type and a contact_type as well.

Have a look at the contact type utils library: https://github.com/medic/cht-core/blob/master/shared-libs/contact-types-utils/src/index.js#L13

I think this function, that checks whether a list of contacts are of the same type can belong there, instead of here.

@@ -254,24 +277,57 @@ angular
return hasPlace && hasContact;
};

const validateFacilityHierarchy = () => {
const placeIds = $scope.editUserModel.place;
const docsFetched = 10;
Copy link
Member

Choose a reason for hiding this comment

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

It's unclear why we are fetching less docs than we are actually selecting?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, I forgot to take it out after some experimentation.

};

const getDocs = function (ids) {
const docsFetched = 10;
Copy link
Member

Choose a reason for hiding this comment

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

It's unclear why we are limiting to 10 documents, when we can clearly have a longer selection.

Comment on lines +145 to +146
const docs = result.rows.map(row => row.doc);
const docIds = docs.map(doc => doc._id);
Copy link
Member

Choose a reason for hiding this comment

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

I think you can do this in a single line:

Suggested change
const docs = result.rows.map(row => row.doc);
const docIds = docs.map(doc => doc._id);
const docIds = result.rows.map(row => row.doc._id);

return resolution.then(function() { //NoSONAR
$timeout(() => { //NoSONAR
selectEl.trigger('change');
}, 1000);
Copy link
Member

Choose a reason for hiding this comment

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

I think we should figure out why this timeout is needed. I'm not comfortable with keeping this at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This seems what's mainly left. I will dedicate tomorrow morning to it.

selectEl.select2('data', select2Data);
$timeout(() => { //NoSONAR
selectEl.trigger('change');
}, 1000);
Copy link
Member

Choose a reason for hiding this comment

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

Same. We should not have delays like this, we need to figure out what is happening here.

@@ -257,6 +256,7 @@ export class ContactsComponent implements OnInit, AfterViewInit, OnDestroy {

private canViewLastVisitedDate() {
if (this.sessionService.isAdmin()) {
// disable UHC for DB admins
Copy link
Member

Choose a reason for hiding this comment

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

Is this added accidentally?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make place field in the user form a multiselect dropdown
4 participants