From dae2a6c14db87b002938795be4c7487da231d06f Mon Sep 17 00:00:00 2001 From: JoshuaVulcan <38018017+JoshuaVulcan@users.noreply.github.com> Date: Mon, 22 Jul 2024 10:50:18 -0700 Subject: [PATCH] feat:wiring up new back-end permissions for data export functionality --- src/GlobalMenuDrawer/index.js | 91 +++++++++++++-------- src/GlobalMenuDrawer/index.test.js | 127 +++++++++++++++++++++-------- src/constants/index.js | 2 + 3 files changed, 153 insertions(+), 67 deletions(-) diff --git a/src/GlobalMenuDrawer/index.js b/src/GlobalMenuDrawer/index.js index 7b828f791..6bfa9c68e 100644 --- a/src/GlobalMenuDrawer/index.js +++ b/src/GlobalMenuDrawer/index.js @@ -67,6 +67,8 @@ const GlobalMenuDrawer = () => { const { t } = useTranslation('menu-drawer', { keyPrefix: 'globalMenuDrawer' }); const hasPatrolViewPermissions = usePermissions(PERMISSION_KEYS.PATROLS, PERMISSIONS.READ); + const hasObservationExportPermissions = usePermissions(PERMISSION_KEYS.OBSERVATIONS_EXPORT, PERMISSIONS.READ); + const hasEventExportPermissions = usePermissions(PERMISSION_KEYS.EVENTS_EXPORT, PERMISSIONS.READ); const isMediumLayoutOrLarger = useMatchMedia(BREAKPOINTS.screenIsMediumLayoutOrLarger); @@ -79,37 +81,62 @@ const GlobalMenuDrawer = () => { const token = useSelector((state) => state.data.token); const user = useSelector((state) => state.data.user); - const modals = useMemo(() => [ - ...(dailyReportEnabled ? [{ - title: t('dailyReportModal.title'), - content: DailyReportModal, - modalProps: { className: 'daily-report-modal' }, - }] : []), - { - title: t('fieldReportsModal.title'), - content: DataExportModal, - url: 'activity/events/export', - paramString: calcEventFilterForRequest(), - children:
{t('fieldReportsModal.content')}
- }, - ...(kmlExportEnabled ? [{ - title: t('masterKMLModal.title'), - content: KMLExportModal, - url: 'subjects/kml/root', - modalProps: { className: 'kml-export-modal' }, - }] : []), - { - title: t('subjectInformationModal.title'), - content: DataExportModal, - url: 'trackingmetadata/export', - }, - { - title: t('subjectReportsModal.title'), - content: DataExportModal, - url: 'trackingdata/export', - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - ], [dailyReportEnabled, eventFilter, eventTypes, kmlExportEnabled, t]); + const modals = useMemo(() => { + const modals = [ + ]; + + if (dailyReportEnabled) { + modals.push( + { + title: t('dailyReportModal.title'), + content: DailyReportModal, + modalProps: { className: 'daily-report-modal' }, + } + ); + } + + if (kmlExportEnabled) { + modals.push( + { + title: t('masterKMLModal.title'), + content: KMLExportModal, + url: 'subjects/kml/root', + modalProps: { className: 'kml-export-modal' }, + } + ); + } + + if (hasObservationExportPermissions) { + modals.push(...[ + { + title: t('subjectInformationModal.title'), + content: DataExportModal, + url: 'trackingmetadata/export', + }, + { + title: t('subjectReportsModal.title'), + content: DataExportModal, + url: 'trackingdata/export', + } + ]); + } + + if (hasEventExportPermissions) { + modals.push( + { + title: t('fieldReportsModal.title'), + content: DataExportModal, + url: 'activity/events/export', + paramString: calcEventFilterForRequest(), + children:
{t('fieldReportsModal.content')}
+ } + ); + } + + return modals; + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + }, [eventFilter, hasEventExportPermissions, hasObservationExportPermissions, dailyReportEnabled, kmlExportEnabled, t]); + const showPatrols = !!patrolFlagEnabled && !!hasPatrolViewPermissions; const onModalClick = useCallback((modal, analyticsTitle = REPORT_EXPORT_CATEGORY) => { @@ -140,7 +167,7 @@ const GlobalMenuDrawer = () => { if (siteInput) { siteInput.value = window.location.hostname; } - const username = (selectedUserProfile?.id ? selectedUserProfile: user)?.username; + const username = (selectedUserProfile?.id ? selectedUserProfile : user)?.username; const userInput = selectSupportFormFieldByLabelText('ER Requestor Name'); if (userInput) { diff --git a/src/GlobalMenuDrawer/index.test.js b/src/GlobalMenuDrawer/index.test.js index 9a7069cae..80d9f12eb 100644 --- a/src/GlobalMenuDrawer/index.test.js +++ b/src/GlobalMenuDrawer/index.test.js @@ -36,11 +36,11 @@ jest.mock('../hooks/useNavigate', () => jest.fn()); describe('GlobalMenuDrawer', () => { let addModalMock, fetchTableauDashboardMock, hideDrawerMock, navigate, store, useMatchMediaMock, useNavigateMock; beforeEach(() => { - addModalMock = jest.fn(() => () => {}); + addModalMock = jest.fn(() => () => { }); addModal.mockImplementation(addModalMock); fetchTableauDashboardMock = jest.fn(() => () => Promise.resolve({ display_url: 'tableau url ' })); fetchTableauDashboard.mockImplementation(fetchTableauDashboardMock); - hideDrawerMock = jest.fn(() => () => {}); + hideDrawerMock = jest.fn(() => () => { }); hideDrawer.mockImplementation(hideDrawerMock); useMatchMediaMock = jest.fn(() => true); useMatchMedia.mockImplementation(useMatchMediaMock); @@ -59,6 +59,8 @@ describe('GlobalMenuDrawer', () => { user: { permissions: { [PERMISSION_KEYS.PATROLS]: [PERMISSIONS.READ], + [PERMISSION_KEYS.EVENTS_EXPORT]: [PERMISSIONS.READ], + [PERMISSION_KEYS.OBSERVATIONS_EXPORT]: [PERMISSIONS.READ], } }, }, @@ -320,22 +322,41 @@ describe('GlobalMenuDrawer', () => { expect(addModal.mock.calls[0][0].title).toBe('Daily Report'); }); - test('opens the field reports modal when clicking the Field Reports button', async () => { - render( - - - - ); + describe('exporting field reports', () => { + const getFieldEventsButton = () => screen.queryByText('Field Events'); - expect(addModal).toHaveBeenCalledTimes(0); + test('does not show the Field Reports button if a user doesn\'t have export event data permissions', () => { + delete store.data.user.permissions[PERMISSION_KEYS.EVENTS_EXPORT]; - const fieldReportsButton = await screen.findByText('Field Events'); - userEvent.click(fieldReportsButton); + render( + + + + ); - expect(addModal).toHaveBeenCalledTimes(1); - expect(addModal.mock.calls[0][0].title).toBe('Field Events'); + const fieldEventsButton = getFieldEventsButton(); + + expect(fieldEventsButton).toBeNull(); + }); + + test('opens the field reports modal when clicking the Field Reports button', () => { + render( + + + + ); + + expect(addModal).toHaveBeenCalledTimes(0); + + const fieldEventsButton = getFieldEventsButton(); + userEvent.click(fieldEventsButton); + + expect(addModal).toHaveBeenCalledTimes(1); + expect(addModal.mock.calls[0][0].title).toBe('Field Events'); + }); }); + test('opens the kml export modal when clicking the Master KML button', async () => { render( @@ -352,38 +373,74 @@ describe('GlobalMenuDrawer', () => { expect(addModal.mock.calls[0][0].title).toBe('Subject KML'); }); - test('opens the subject information modal when clicking the Subject Information button', async () => { - render( - - - - ); - expect(addModal).toHaveBeenCalledTimes(0); + describe('exporting subject information', () => { + const getSubjectInfoButton = () => screen.queryByText('Subject Summary'); - const subjectInformationButton = await screen.findByText('Subject Summary'); - userEvent.click(subjectInformationButton); + test('does not show the subject information link if a user doesn\'t have export observation data permissions', () => { + delete store.data.user.permissions[PERMISSION_KEYS.OBSERVATIONS_EXPORT]; - expect(addModal).toHaveBeenCalledTimes(1); - expect(addModal.mock.calls[0][0].title).toBe('Subject Summary'); + render( + + + + ); + + const subjectInfoButton = getSubjectInfoButton(); + expect(subjectInfoButton).toBeNull(); + }); + + test('opens the subject information modal when clicking the Subject Information button', () => { + render( + + + + ); + + expect(addModal).toHaveBeenCalledTimes(0); + + const subjectInfoButton = getSubjectInfoButton(); + userEvent.click(subjectInfoButton); + + expect(addModal).toHaveBeenCalledTimes(1); + expect(addModal.mock.calls[0][0].title).toBe('Subject Summary'); + }); }); - test('opens the subject reports modal when clicking the Subject Reports button', async () => { - render( - - - - ); + describe('exporting subject reports', () => { + const getSubjectReportsButton = () => screen.queryByText('Observations'); - expect(addModal).toHaveBeenCalledTimes(0); + test('does not show the subject reports link if a user doesn\'t have export observation data permissions', () => { + delete store.data.user.permissions[PERMISSION_KEYS.OBSERVATIONS_EXPORT]; - const subjectReportsButton = await screen.findByText('Observations'); - userEvent.click(subjectReportsButton); + render( + + + + ); - expect(addModal).toHaveBeenCalledTimes(1); - expect(addModal.mock.calls[0][0].title).toBe('Observations'); + const subjectReportsButton = getSubjectReportsButton(); + expect(subjectReportsButton).toBeNull(); + }); + + test('opens the subject reports modal when clicking the Subject Reports button', () => { + render( + + + + ); + + expect(addModal).toHaveBeenCalledTimes(0); + + const subjectReportsButton = getSubjectReportsButton(); + userEvent.click(subjectReportsButton); + + expect(addModal).toHaveBeenCalledTimes(1); + expect(addModal.mock.calls[0][0].title).toBe('Observations'); + }); }); + test('lists links to various privacy and data policies', async () => { render( diff --git a/src/constants/index.js b/src/constants/index.js index 2c5657082..bbc36dcbf 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -297,6 +297,8 @@ export const PERMISSION_KEYS = { PATROLS: 'patrol', PATROL_TYPES: 'patroltype', MESSAGING: 'message', + OBSERVATIONS_EXPORT: 'export_observation_data', + EVENTS_EXPORT: 'export_event_data', };