Skip to content

Commit

Permalink
Add ability to add/remove roles for user's affiliations
Browse files Browse the repository at this point in the history
  • Loading branch information
ryandberger committed Jan 24, 2025
1 parent 1f4afe4 commit fe59adf
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 12 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* Update fee/fine actions column UX for accessibility. Refs UIU-3027.
* Rename permission after BE changes. Refs UIU-3309.
* Change import of `exportToCsv` from `stripes-util` to `stripes-components`. Refs UIU-3202.
* Add ability to create/edit role assignments for all of a user's affiliations. Refs UIU-3179.

## [11.0.10](https://github.com/folio-org/ui-users/tree/v11.0.10) (2025-01-10)
[Full Changelog](https://github.com/folio-org/ui-users/compare/v11.0.9...v11.0.10)
Expand Down
41 changes: 36 additions & 5 deletions src/components/EditSections/EditUserRoles/EditUserRoles.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,41 @@
import React, { useMemo, useState } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import { useIntl, FormattedMessage } from 'react-intl';
import { withRouter } from 'react-router';
import PropTypes from 'prop-types';
import { isEmpty } from 'lodash';
import { FieldArray } from 'react-final-form-arrays';
import { OnChange } from 'react-final-form-listeners';
import { IfPermission } from '@folio/stripes/core';

import { IfPermission, useStripes } from '@folio/stripes/core';
import { Accordion, Headline, Badge, Row, Col, List, Button, Icon, ConfirmationModal } from '@folio/stripes/components';
import { useAllRolesData } from '../../../hooks';

import { useAllRolesData, useUserAffiliations } from '../../../hooks';
import AffiliationsSelect from '../../AffiliationsSelect/AffiliationsSelect';
import IfConsortium from '../../IfConsortium';
import IfConsortiumPermission from '../../IfConsortiumPermission';
import UserRolesModal from './components/UserRolesModal/UserRolesModal';
import { isAffiliationsEnabled } from '../../util/util';
import { filtersConfig } from './helpers';

function EditUserRoles({ accordionId, form:{ change }, setAssignedRoleIds, assignedRoleIds }) {
function EditUserRoles({ accordionId, form:{ change }, user, setAssignedRoleIds, assignedRoleIds, setTenantId, tenantId }) {

Check failure on line 20 in src/components/EditSections/EditUserRoles/EditUserRoles.js

View workflow job for this annotation

GitHub Actions / build-npm

'user' is missing in props validation

Check failure on line 20 in src/components/EditSections/EditUserRoles/EditUserRoles.js

View workflow job for this annotation

GitHub Actions / build-npm

'setTenantId' is missing in props validation

Check failure on line 20 in src/components/EditSections/EditUserRoles/EditUserRoles.js

View workflow job for this annotation

GitHub Actions / build-npm

'tenantId' is missing in props validation
const stripes = useStripes();
const [isOpen, setIsOpen] = useState(false);
const [unassignModalOpen, setUnassignModalOpen] = useState(false);
const intl = useIntl();

const { isLoading: isAllRolesDataLoading, allRolesMapStructure } = useAllRolesData();
const {
affiliations,
isFetching: isAffiliationsFetching,
} = useUserAffiliations({ userId: user.id }, { enabled: isAffiliationsEnabled(user) });

Check failure on line 29 in src/components/EditSections/EditUserRoles/EditUserRoles.js

View workflow job for this annotation

GitHub Actions / build-npm

'user.id' is missing in props validation

const { isLoading: isAllRolesDataLoading, allRolesMapStructure, refetch } = useAllRolesData({ tenantId });

useEffect(() => {
if (!affiliations.some(({ tenantId: assigned }) => tenantId === assigned)) {
setTenantId(stripes.okapi.tenant);
}
refetch();
}, [affiliations, stripes.okapi.tenant, tenantId]);

Check warning on line 38 in src/components/EditSections/EditUserRoles/EditUserRoles.js

View workflow job for this annotation

GitHub Actions / build-npm

React Hook useEffect has missing dependencies: 'refetch' and 'setTenantId'. Either include them or remove the dependency array. If 'setTenantId' changes too often, find the parent component that defines it and wrap that definition in useCallback

const changeUserRoles = (roleIds) => {
change('assignedRoleIds', roleIds);
Expand Down Expand Up @@ -101,6 +120,18 @@ function EditUserRoles({ accordionId, form:{ change }, setAssignedRoleIds, assig
displayWhenClosed={<Badge>{assignedRoleIds.length}</Badge>}
>
<Row>
<IfConsortium>
<IfConsortiumPermission perm="consortia.user-tenants.collection.get">
{Boolean(affiliations?.length) && (
<AffiliationsSelect
affiliations={affiliations}
onChange={setTenantId}
isLoading={isAllRolesDataLoading || isAffiliationsFetching}
value={tenantId}
/>
)}
</IfConsortiumPermission>
</IfConsortium>
{renderUserRoles()}
<IfPermission perm="ui-authorization-roles.users.settings.manage">
<Button data-testid="add-roles-button" onClick={() => setIsOpen(true)}><FormattedMessage id="ui-users.roles.addRoles" /></Button>
Expand Down
9 changes: 6 additions & 3 deletions src/components/Wrappers/withUserRoles.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ const withUserRoles = (WrappedComponent) => (props) => {
const { okapi, config } = useStripes();
// eslint-disable-next-line react/prop-types
const userId = props.match.params.id;
const [tenantId, setTenantId] = useState(okapi.tenant);
const [assignedRoleIds, setAssignedRoleIds] = useState([]);
const [initialAssignedRoleIds, setInitialAssignedRoleIds] = useState([]);
const [isCreateKeycloakUserConfirmationOpen, setIsCreateKeycloakUserConfirmationOpen] = useState(false);
const callout = useCallout();
const sendErrorCallout = error => showErrorCallout(error, callout.sendCallout);

const { mutateAsync: createKeycloakUser } = useCreateAuthUserKeycloak(sendErrorCallout, { tenantId: okapi.tenant });
const { mutateAsync: createKeycloakUser } = useCreateAuthUserKeycloak(sendErrorCallout, { tenantId });

const { isLoading: isAllRolesDataLoading, allRolesMapStructure } = useAllRolesData();

Expand All @@ -28,7 +29,7 @@ const withUserRoles = (WrappedComponent) => (props) => {
const ky = useOkapiKy();
const api = ky.extend({
hooks: {
beforeRequest: [(req) => req.headers.set('X-Okapi-Tenant', okapi.tenant)]
beforeRequest: [(req) => req.headers.set('X-Okapi-Tenant', tenantId)]
}
});

Expand Down Expand Up @@ -57,7 +58,7 @@ const withUserRoles = (WrappedComponent) => (props) => {
},
// Adding api, searchParams to deps causes infinite callback call. Listed deps are enough to track changes.
// eslint-disable-next-line react-hooks/exhaustive-deps
[userId, isAllRolesDataLoading, setAssignedRoleIdsOnLoad]);
[userId, isAllRolesDataLoading, setAssignedRoleIdsOnLoad, tenantId]);

const updateUserRoles = (roleIds) => api.put(
`roles/users/${userId}`, { json: {
Expand Down Expand Up @@ -116,6 +117,8 @@ const withUserRoles = (WrappedComponent) => (props) => {

return <WrappedComponent
{...props}
tenantId={tenantId}
setTenantId={setTenantId}
assignedRoleIds={assignedRoleIds}
setAssignedRoleIds={setAssignedRoleIds}
isCreateKeycloakUserConfirmationOpen={isCreateKeycloakUserConfirmationOpen}
Expand Down
9 changes: 5 additions & 4 deletions src/hooks/useAllRolesData/useAllRolesData.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ import { useQuery } from 'react-query';
* - isSuccess: A boolean indicating if the data fetch was successful.
*/

function useAllRolesData() {
function useAllRolesData(options = {}) {
const { tenantId } = options;
const stripes = useStripes();
const ky = useOkapiKy();
const ky = useOkapiKy({ tenant: tenantId || stripes.okapi.tenant });

const [namespace] = useNamespace();

const { data, isLoading, isSuccess } = useQuery([namespace, 'user-roles'], () => {
const { data, isLoading, isSuccess, refetch } = useQuery([namespace, 'user-roles'], () => {
return ky.get(`roles?limit=${stripes.config.maxUnpagedResourceCount}&query=cql.allRecords=1 sortby name`).json();
}, { enabled: stripes.hasInterface('roles') });

Expand All @@ -32,7 +33,7 @@ function useAllRolesData() {
return rolesMap;
}, [data]);

return { data, isLoading, allRolesMapStructure, isSuccess };
return { data, isLoading, allRolesMapStructure, isSuccess, refetch };
}

export default useAllRolesData;
4 changes: 4 additions & 0 deletions src/views/UserEdit/UserEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,8 @@ class UserEdit extends React.Component {
location,
match: { params },
isCreateKeycloakUserConfirmationOpen,
setTenantId,

Check failure on line 462 in src/views/UserEdit/UserEdit.js

View workflow job for this annotation

GitHub Actions / build-npm

'setTenantId' is missing in props validation
tenantId,

Check failure on line 463 in src/views/UserEdit/UserEdit.js

View workflow job for this annotation

GitHub Actions / build-npm

'tenantId' is missing in props validation
setAssignedRoleIds,
assignedRoleIds
} = this.props;
Expand Down Expand Up @@ -497,6 +499,8 @@ class UserEdit extends React.Component {
isCreateKeycloakUserConfirmationOpen={isCreateKeycloakUserConfirmationOpen}
onCancelKeycloakConfirmation={this.onCompleteEdit}
confirmCreateKeycloakUser={() => this.props.confirmCreateKeycloakUser(this.onCompleteEdit)}
setTenantId={setTenantId}
tenantId={tenantId}
setAssignedRoleIds={setAssignedRoleIds}
assignedRoleIds={assignedRoleIds}
/>
Expand Down
3 changes: 3 additions & 0 deletions src/views/UserEdit/UserForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,9 @@ class UserForm extends React.Component {
setButtonRef={this.setButtonRef}
/> : <EditUserRoles
form={form}
user={initialValues}
setTenantId={this.props.setTenantId}

Check failure on line 476 in src/views/UserEdit/UserForm.js

View workflow job for this annotation

GitHub Actions / build-npm

'setTenantId' is missing in props validation
tenantId={this.props.tenantId}

Check failure on line 477 in src/views/UserEdit/UserForm.js

View workflow job for this annotation

GitHub Actions / build-npm

'tenantId' is missing in props validation
setAssignedRoleIds={this.props.setAssignedRoleIds}
assignedRoleIds={this.props.assignedRoleIds}
accordionId="userRoles"
Expand Down

0 comments on commit fe59adf

Please sign in to comment.