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

User details update #1285

Merged
merged 32 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
71393d4
Add antd pro-design
peterMuriuki Oct 25, 2023
f62cf02
Registering a checkmark
peterMuriuki Oct 26, 2023
7d705b9
Add url to new user view details
peterMuriuki Oct 27, 2023
4b65e72
silence table stripping for a more crisp clean look
peterMuriuki Oct 27, 2023
a3f2f15
Second iteration ideating data flow
peterMuriuki Oct 27, 2023
baf529c
Export fhirDataType components
peterMuriuki Nov 7, 2023
c2f7db8
Update user management constantts
peterMuriuki Nov 7, 2023
769918d
Add second iteration of user detail views
peterMuriuki Nov 7, 2023
047e8ce
Move userDeleteWith popup confirm button to own component
peterMuriuki Nov 8, 2023
6f18b10
Add react import to user delete btn component file
peterMuriuki Nov 8, 2023
e54240b
Change leave text on group detail view to red
peterMuriuki Nov 8, 2023
6f823ec
Test edit btn works
peterMuriuki Nov 8, 2023
d34f105
Fix roleDetail view and add tests
peterMuriuki Nov 8, 2023
4b773f5
Temporarily remove location details view
peterMuriuki Nov 8, 2023
00bb9ab
Make description list responsive
peterMuriuki Nov 8, 2023
3e2b3ae
Replace previous view details components
peterMuriuki Nov 8, 2023
324ebb7
Wrap microcopy in translator function
peterMuriuki Nov 9, 2023
034db37
Recognize practitionerDetail fhir resource in rbac
peterMuriuki Nov 9, 2023
12c02fa
Integrate rbac into user detail view
peterMuriuki Nov 9, 2023
4cc34d9
Fix import
peterMuriuki Nov 9, 2023
0283509
Fix permission string
peterMuriuki Nov 9, 2023
73e1226
Update tests
peterMuriuki Nov 9, 2023
8f8350b
Fix practitionerDetails endpoint
peterMuriuki Jan 15, 2024
1569752
Fix url collision to user details
peterMuriuki Jan 16, 2024
acd64b8
Remove surplus pro-components library
peterMuriuki Jan 22, 2024
f7e1d2c
Fix user details url route
peterMuriuki Jan 22, 2024
5858edb
Invalidate only query that refetches user queries
peterMuriuki Jan 22, 2024
203a63e
Code cleanup
peterMuriuki Jan 22, 2024
7537956
Update tests
peterMuriuki Jan 22, 2024
a687581
Update lock file
peterMuriuki Jan 22, 2024
806543e
Revert "Remove surplus pro-components library"
peterMuriuki Jan 22, 2024
d891d8a
Fix lint issues
peterMuriuki Jan 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"dependencies": {
"@2fd/ant-design-icons": "^2.6.0",
"@ant-design/icons": "^4.7.0",
"@ant-design/pro-components": "^2.6.32",
"@onaio/connected-private-route": "^0.0.11",
"@onaio/connected-reducer-registry": "^0.0.3",
"@onaio/gatekeeper": "1.0.0",
Expand Down
10 changes: 10 additions & 0 deletions app/src/App/fhir-apps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ import {
import {
CreateEditUser as FHIRConnectedCreateEditUser,
UserList as FhirUserList,
USER_DETAILS_URL,
UserDetailsV2,
} from '@opensrp/fhir-user-management';
import { Home } from '../containers/pages/Home/Home';
import {
Expand Down Expand Up @@ -224,6 +226,14 @@ const FHIRApps = () => {
permissions={['iam_user.read']}
component={FhirUserList}
/>
<PrivateComponent
redirectPath={APP_CALLBACK_URL}
disableLoginProtection={DISABLE_LOGIN_PROTECTION}
exact
path={`${USER_DETAILS_URL}/:id`}
permissions={['iam_user.read']}
component={UserDetailsV2}
/>
<PrivateComponent
redirectPath={APP_CALLBACK_URL}
disableLoginProtection={DISABLE_LOGIN_PROTECTION}
Expand Down
1 change: 1 addition & 0 deletions packages/fhir-keycloak-user-management/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"dist"
],
"peerDependencies": {
"@ant-design/pro-components": "^2.6.32",
"@opensrp/store": "^0.0.10",
"antd": "^5.5.1",
"i18next": "^19.8.4",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Popconfirm, Button } from 'antd';
import { KEYCLOAK_URL_USERS } from '@opensrp/user-management';
import { sendErrorNotification } from '@opensrp/notifications';
import { deleteUser } from '../UserList/ListView/utils';
import { useTranslation } from '../../mls';
import { useQueryClient } from 'react-query';
import React from 'react';

export interface UserDeleteBtnProp {
afterActions?: () => void;
keycloakBaseUrl: string;
fhirBaseUrl: string;
resourceId: string;
}

export const UserDeleteBtn = (props: UserDeleteBtnProp) => {
const { afterActions, keycloakBaseUrl, fhirBaseUrl, resourceId } = props;
const { t } = useTranslation();
const queryClient = useQueryClient();

return (
<Popconfirm
key="delete-user"
title={t('Are you sure you want to delete this user?')}
okText={t('Yes')}
cancelText={t('No')}
onConfirm={async () => {
await deleteUser(keycloakBaseUrl, fhirBaseUrl, resourceId, t);
try {
return await queryClient.invalidateQueries({
queryKey: [KEYCLOAK_URL_USERS],
exact: true,
});
} catch {
return sendErrorNotification(
t('Failed to update data, please refresh the page to see the most recent changes')
);
} finally {
afterActions?.();
}
}}
>
<Button data-testid="delete-user" danger type="link">
{t('Delete')}
</Button>
</Popconfirm>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import {
TableLayout,
BrokenPage,
searchQuery,
useSearchParams,
viewDetailsQuery,
} from '@opensrp/react-utils';
import { PlusOutlined } from '@ant-design/icons';
import { URL_USER_CREATE, KEYCLOAK_URL_USERS } from '@opensrp/user-management';
Expand All @@ -20,8 +18,6 @@ import { PageHeader } from '@opensrp/react-utils';
import { getExtraData } from '@onaio/session-reducer';
import { KeycloakUser } from '@opensrp/user-management';
import { useSelector } from 'react-redux';
import { ViewDetailsWrapper } from '../ViewDetails';
import { useQueryClient } from 'react-query';
import { useTranslation } from '@opensrp/i18n';
import { RbacCheck, useUserRole } from '@opensrp/rbac';

Expand All @@ -41,13 +37,9 @@ export const UserList = (props: OrganizationListProps) => {
const history = useHistory();
const match = useRouteMatch();
const extraData = useSelector(getExtraData);
const queryClient = useQueryClient();
const { t } = useTranslation();
const userRole = useUserRole();

const { sParams, addParam } = useSearchParams();
const resourceId = sParams.get(viewDetailsQuery) ?? undefined;

const { isLoading, data, error, isFetching } = useQuery([KEYCLOAK_URL_USERS], () =>
loadKeycloakResources(keycloakBaseURL, KEYCLOAK_URL_USERS)
);
Expand Down Expand Up @@ -77,17 +69,7 @@ export const UserList = (props: OrganizationListProps) => {
};
});

const onViewDetails = (resourceId: string) => addParam(viewDetailsQuery, resourceId);
const columns = getTableColumns(
keycloakBaseURL,
fhirBaseURL,
extraData,
queryClient,
t,
onViewDetails,
userRole,
history
);
const columns = getTableColumns(keycloakBaseURL, fhirBaseURL, extraData, t, userRole, history);

const searchFormProps = {
defaultValue: getQueryParams(location)[searchQuery],
Expand Down Expand Up @@ -134,11 +116,6 @@ export const UserList = (props: OrganizationListProps) => {
</div>
<TableLayout {...tableProps} />
</Col>
<ViewDetailsWrapper
resourceId={resourceId}
fhirBaseUrl={fhirBaseURL}
keycloakBaseUrl={keycloakBaseURL}
/>
</Row>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,42 +1,32 @@
import * as React from 'react';
import { Popconfirm, Divider, Dropdown, Button } from 'antd';
import { Divider, Dropdown, Button } from 'antd';
import type { MenuProps } from 'antd';
import { MoreOutlined } from '@ant-design/icons';
import { deleteUser } from './utils';
import { Link } from 'react-router-dom';
import {
KeycloakUser,
URL_USER_EDIT,
KEYCLOAK_URL_USERS,
URL_USER_CREDENTIALS,
} from '@opensrp/user-management';
import { KeycloakUser, URL_USER_EDIT, URL_USER_CREDENTIALS } from '@opensrp/user-management';
import { Dictionary } from '@onaio/utils';
import { Column } from '@opensrp/react-utils';
import { sendErrorNotification } from '@opensrp/notifications';
import { QueryClient } from 'react-query';
import type { TFunction } from '@opensrp/i18n';
import { RbacCheck, UserRole } from '@opensrp/rbac';
import { History } from 'history';
import { UserDeleteBtn } from '../../UserDeleteBtn';
import { USER_DETAILS_URL } from '../../../constants';

/**
* Get table columns for user list
*
* @param keycloakBaseUrl - keycloak base url
* @param baseUrl - server base url
* @param extraData - session data about logged in user
* @param queryClient - react query client
* @param t - translator function
* @param onViewDetails - callback when view details is clicked.
* @param userRole - role of logged in user.
* @param history - history object for managing navigation
*/
export const getTableColumns = (
keycloakBaseUrl: string,
baseUrl: string,
extraData: Dictionary,
queryClient: QueryClient,
t: TFunction,
onViewDetails: (recordId: string) => void,
userRole: UserRole,
history: History
): Column<KeycloakUser>[] => {
Expand All @@ -61,44 +51,16 @@ export const getTableColumns = (
});

const getItems = (record: KeycloakUser): MenuProps['items'] => {
return [
const items = [
{
key: '1',
permissions: [],
permissions: ['iam_user.read'],
label: (
<Button onClick={() => onViewDetails(record.id)} type="link">
<Button onClick={() => history.push(`${USER_DETAILS_URL}/${record.id}`)} type="link">
{t('View Details')}
</Button>
),
},
{
key: '2',
permissions: ['iam_user.delete'],
label: (
<Popconfirm
title={t('Are you sure you want to delete this user?')}
okText={t('Yes')}
cancelText={t('No')}
onConfirm={async () => {
await deleteUser(keycloakBaseUrl, baseUrl, record.id, t);
try {
return await queryClient.invalidateQueries([KEYCLOAK_URL_USERS]);
} catch {
return sendErrorNotification(
t('Failed to update data, please refresh the page to see the most recent changes')
);
}
}}
>
{user_id &&
(record.id === user_id ? null : (
<Button data-testid="delete-user" danger type="link" style={{ color: '#' }}>
{t('Delete')}
</Button>
))}
</Popconfirm>
),
},
{
key: '3',
permissions: ['iam_user.update'],
Expand All @@ -114,7 +76,22 @@ export const getTableColumns = (
</Button>
),
},
]
];
// don't show delete for the current logged in user - back compatibility reasons.
if (user_id && record.id !== user_id) {
items.push({
key: '2',
permissions: ['iam_user.delete'],
label: (
<UserDeleteBtn
keycloakBaseUrl={keycloakBaseUrl}
fhirBaseUrl={baseUrl}
resourceId={record.id}
/>
),
});
}
return items
.filter((item) => userRole.hasPermissions(item.permissions))
.map((item) => {
const { permissions, ...rest } = item;
Expand Down
Loading
Loading