diff --git a/docs/rbac.md b/docs/rbac.md index e90b4b23f..5b788f27f 100644 --- a/docs/rbac.md +++ b/docs/rbac.md @@ -4,7 +4,7 @@ Fhir web Rbac implementation limits what logged in users can see and actions the ## Approach -The rbac module provisions an internal role definition and plugins that can parse IAM role information into the pre-defined internal role representation. [This comment](https://github.com/onaio/fhir-web/issues/1182#issuecomment-1486729934) has more information on what this role definition looks like. +The rbac module provisions an internal role definition and plugins that can parse IAM role information into the pre-defined internal role representation. [This comment](https://github.com/onaio/fhir-web/issues/1411#issuecomment-2175911075) has more information on what this role definition looks like. The following adapters exist and can be configured using the `REACT_APP_AUTHZ_STRATEGY` env diff --git a/packages/fhir-location-management/src/components/AllLocationListFlat/core.tsx b/packages/fhir-location-management/src/components/AllLocationListFlat/core.tsx index 786e0c80a..2f950bd86 100644 --- a/packages/fhir-location-management/src/components/AllLocationListFlat/core.tsx +++ b/packages/fhir-location-management/src/components/AllLocationListFlat/core.tsx @@ -1,6 +1,5 @@ import React from 'react'; import { - URL_LOCATION_UNIT_EDIT, URL_LOCATION_UNIT_ADD, URL_LOCATION_VIEW_DETAILS, BACK_SEARCH_PARAM, @@ -13,6 +12,7 @@ import { MenuProps } from 'antd'; import { MoreOutlined, PlusOutlined } from '@ant-design/icons'; import { BaseAllLocationListFlat, BaseAllLocationListFlatProps } from './base'; import { Dictionary } from '@onaio/utils'; +import { EditLink } from '../EditLink'; export type AllLocationListFlatProps = Omit< BaseAllLocationListFlatProps, @@ -30,6 +30,7 @@ export const AllLocationListFlat: React.FC = (props) = const location = useLocation(); const backToParam = new URLSearchParams({ [BACK_SEARCH_PARAM]: location.pathname }); + const getItems = (_: Dictionary): MenuProps['items'] => { return [ { @@ -73,12 +74,7 @@ export const AllLocationListFlat: React.FC = (props) = <> - - {t('Edit')} - + diff --git a/packages/fhir-location-management/src/components/AllLocationListFlat/tests/utils.test.tsx b/packages/fhir-location-management/src/components/AllLocationListFlat/tests/utils.test.tsx index 23059794a..adaa71fb1 100644 --- a/packages/fhir-location-management/src/components/AllLocationListFlat/tests/utils.test.tsx +++ b/packages/fhir-location-management/src/components/AllLocationListFlat/tests/utils.test.tsx @@ -19,6 +19,7 @@ describe('location-management/src/components/AllLocationListFlat/utils', () => { parent: '', status: 'active', type: 'Building', + location: flatLocations.entry[0].resource, }, ]); }); diff --git a/packages/fhir-location-management/src/components/AllLocationListFlat/utils.tsx b/packages/fhir-location-management/src/components/AllLocationListFlat/utils.tsx index 37a15f2be..0fed7f1de 100644 --- a/packages/fhir-location-management/src/components/AllLocationListFlat/utils.tsx +++ b/packages/fhir-location-management/src/components/AllLocationListFlat/utils.tsx @@ -39,7 +39,7 @@ export function getResourceParentName( */ export function getTableData(data: BundleEntry[]) { const resourcesById: Dictionary = {}; - const tableData: Dictionary[] = []; + const tableData: Dictionary[] = []; data.forEach((entry) => { const id = entry.resource?.id; if (id) { @@ -57,6 +57,7 @@ export function getTableData(data: BundleEntry[]) { type: resource.physicalType?.coding[0]?.display, status: resource.status, parent: getResourceParentName(resource, resourcesById), + location: resource, }; tableData.push(rowData); } diff --git a/packages/fhir-location-management/src/components/EditLink/index.tsx b/packages/fhir-location-management/src/components/EditLink/index.tsx new file mode 100644 index 000000000..353091faa --- /dev/null +++ b/packages/fhir-location-management/src/components/EditLink/index.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import { Link, useLocation } from 'react-router-dom'; +import { + BACK_SEARCH_PARAM, + URL_LOCATION_UNIT_EDIT, + URL_SERVICE_POINT_ADD_EDIT, +} from '../../constants'; +import { ILocation } from '@smile-cdr/fhirts/dist/FHIR-R4/interfaces/ILocation'; + +interface EditLinkProps { + location: ILocation; + editLinkText: string; +} + +const EditLink: React.FC = (props) => { + const { location, editLinkText } = props; + const { id, physicalType } = location; + const isBuilding = physicalType?.coding?.[0].code === 'bu'; + const currentLocation = useLocation(); + + const backToParam = new URLSearchParams({ [BACK_SEARCH_PARAM]: currentLocation.pathname }); + + return ( + + {editLinkText} + + ); +}; + +export { EditLink }; diff --git a/packages/fhir-location-management/src/components/EditLink/tests/fixtures.ts b/packages/fhir-location-management/src/components/EditLink/tests/fixtures.ts new file mode 100644 index 000000000..af5f63a84 --- /dev/null +++ b/packages/fhir-location-management/src/components/EditLink/tests/fixtures.ts @@ -0,0 +1,36 @@ +import { ILocation } from '@smile-cdr/fhirts/dist/FHIR-R4/interfaces/ILocation'; + +export const Location: ILocation = { + resourceType: 'Location', + id: '303', + meta: { + versionId: '4', + lastUpdated: '2021-10-14T13:12:22.740+00:00', + source: '#13bbc7f09daa1751', + }, + identifier: [{ use: 'official', value: '93bc9c3d-6321-41b0-9b93-1275d7114e22' }], + status: 'active', + name: 'Yosemite', + description: 'The Sub location', + partOf: { reference: 'Location/2252', display: 'Root FHIR Location' }, + type: [ + { + coding: [ + { + system: 'http://terminology.hl7.org/CodeSystem/location-physical-type', + code: 'bu', + display: 'Building', + }, + ], + }, + ], + physicalType: { + coding: [ + { + system: 'http://terminology.hl7.org/CodeSystem/location-physical-type', + code: 'bu', + display: 'Building', + }, + ], + }, +}; diff --git a/packages/fhir-location-management/src/components/EditLink/tests/index.test.tsx b/packages/fhir-location-management/src/components/EditLink/tests/index.test.tsx new file mode 100644 index 000000000..520ee5bbb --- /dev/null +++ b/packages/fhir-location-management/src/components/EditLink/tests/index.test.tsx @@ -0,0 +1,56 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { BrowserRouter as Router } from 'react-router-dom'; +import '@testing-library/jest-dom/extend-expect'; +import { URL_LOCATION_UNIT_EDIT, URL_SERVICE_POINT_ADD_EDIT } from '../../../constants'; +import { EditLink } from '..'; +import { Location } from './fixtures'; + +describe('EditLink', () => { + it('renders the correct link for building locations', () => { + const { getByText } = render( + + + + ); + + const link = getByText('Edit'); + expect(link).toBeInTheDocument(); + expect(link).toHaveAttribute('href', `${URL_SERVICE_POINT_ADD_EDIT}/303?back_to=%2F`); + }); + + it('renders the correct link for non-building locations', () => { + const location = { + ...Location, + physicalType: { + coding: [ + { + system: 'http://terminology.hl7.org/CodeSystem/location-physical-type', + code: 'jdn', + display: 'Jurisdiction', + }, + ], + }, + }; + + const { getByText } = render( + + + + ); + + const link = getByText('Edit'); + expect(link).toBeInTheDocument(); + expect(link).toHaveAttribute('href', `${URL_LOCATION_UNIT_EDIT}/303?back_to=%2F`); + }); + it('renders custom link text from props', () => { + const { getByText } = render( + + + + ); + + const link = getByText('Edit details'); + expect(link).toBeInTheDocument(); + }); +}); diff --git a/packages/fhir-location-management/src/components/ViewDetails/DetailsTabs/ChildLocations.tsx b/packages/fhir-location-management/src/components/ViewDetails/DetailsTabs/ChildLocations.tsx index b01588365..a586a7e8b 100644 --- a/packages/fhir-location-management/src/components/ViewDetails/DetailsTabs/ChildLocations.tsx +++ b/packages/fhir-location-management/src/components/ViewDetails/DetailsTabs/ChildLocations.tsx @@ -5,7 +5,6 @@ import { Alert, Button, Col, Divider, Dropdown, MenuProps, Row } from 'antd'; import { BACK_SEARCH_PARAM, URL_LOCATION_UNIT_ADD, - URL_LOCATION_UNIT_EDIT, URL_LOCATION_VIEW_DETAILS, locationResourceType, parentIdQueryParam, @@ -16,6 +15,7 @@ import { MoreOutlined, PlusOutlined } from '@ant-design/icons'; import { useHistory, useLocation } from 'react-router'; import { Link } from 'react-router-dom'; import { get } from 'lodash'; +import { EditLink } from '../../EditLink'; export interface InventoryViewProps { fhirBaseUrl: string; @@ -59,7 +59,6 @@ export const ChildLocations = ({ fhirBaseUrl, locationId }: InventoryViewProps) type TableData = typeof tableData[0]; const backParamObj = { [BACK_SEARCH_PARAM]: location.pathname }; - const backToParam = new URLSearchParams(backParamObj).toString(); const getItems = (_: TableData): MenuProps['items'] => { // Todo: replace _ above when handling onClick return [ @@ -100,13 +99,7 @@ export const ChildLocations = ({ fhirBaseUrl, locationId }: InventoryViewProps) <> - - {t('Edit')} - + @@ -175,5 +168,6 @@ export function parseTableData(locations: ILocation[]) { description: loc.description, status: loc.status, type: get(loc, 'physicalType.coding.0.display'), + location: loc, })); } diff --git a/packages/fhir-location-management/src/components/ViewDetails/LocationDetails/index.tsx b/packages/fhir-location-management/src/components/ViewDetails/LocationDetails/index.tsx index 24c1148ee..55fd26a45 100644 --- a/packages/fhir-location-management/src/components/ViewDetails/LocationDetails/index.tsx +++ b/packages/fhir-location-management/src/components/ViewDetails/LocationDetails/index.tsx @@ -2,10 +2,9 @@ import { ILocation } from '@smile-cdr/fhirts/dist/FHIR-R4/interfaces/ILocation'; import { useMls } from '../../../mls'; import React from 'react'; import { ResourceDetails } from '@opensrp/react-utils'; -import { Link, useLocation } from 'react-router-dom'; import { parseLocationDetails } from '../utils'; -import { BACK_SEARCH_PARAM, URL_LOCATION_UNIT_EDIT } from '../../../constants'; import { RbacCheck } from '@opensrp/rbac'; +import { EditLink } from '../../EditLink'; const GeometryRender = ({ geometry }: { geometry?: string }) => { let formattedGeo = geometry ?? ''; @@ -46,10 +45,6 @@ export const LocationDetails = ({ location }: { location: ILocation }) => { administrativeLevel, } = parseLocationDetails(location); - const loc = useLocation(); - const currentPath = loc.pathname; - const backToParam = new URLSearchParams({ [BACK_SEARCH_PARAM]: currentPath }).toString(); - const otherDetailsMap = { [t('Location Name')]: name, [t('Status')]: status, @@ -74,7 +69,7 @@ export const LocationDetails = ({ location }: { location: ILocation }) => { headerRightData={dateCreatedKeyPairing} headerActions={ - {t('Edit details')} + } bodyData={otherDetailsMap}