From ddbf65d2d2608eede94379e087b6870caa185e03 Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Fri, 26 Feb 2021 07:50:45 +0100 Subject: [PATCH] feat: register passive view of dashboards [DHIS2-7016] (#1572) log when a passive view of the dashboard occurs (user opens dashboard without specifically requesting the specific dashboard) This implementation posts to data statistics when the dashboard app renders a dashboard in view mode for the first time (a passive view); any subsequent passive views, regardless of dashboard, are not registered. In line with the back-end implementation by @jimgrace, the dashboard app has been modified to always make these posts for passive views, whereas api/dataStatistics will count these passive views only if the newly added system setting keyCountPassiveDashboardViewsInUsageAnalytics=true. This change is requested by PEPFAR to allow better oversight over which dashboards are being accessed by users. This change will not affect statistics unless a system admin chooses to set keyCountPassiveDashboardViewsInUsageAnalytics=true, so this PR does not change default behaviour for existing instances (https://jira.dhis2.org/browse/DHIS2-7016) Co-authored-by: Thomas Zemp --- src/actions/passiveViewRegistered.js | 5 +++++ src/components/Dashboard/ViewDashboard.js | 18 ++++++++++++++++++ .../Dashboard/__tests__/ViewDashboard.spec.js | 19 +++++++++++++++++++ src/reducers/index.js | 2 ++ src/reducers/passiveViewRegistered.js | 13 +++++++++++++ 5 files changed, 57 insertions(+) create mode 100644 src/actions/passiveViewRegistered.js create mode 100644 src/reducers/passiveViewRegistered.js diff --git a/src/actions/passiveViewRegistered.js b/src/actions/passiveViewRegistered.js new file mode 100644 index 000000000..e580ac8de --- /dev/null +++ b/src/actions/passiveViewRegistered.js @@ -0,0 +1,5 @@ +import { REGISTER_PASSIVE_VIEW } from '../reducers/passiveViewRegistered' + +export const acSetPassiveViewRegistered = () => ({ + type: REGISTER_PASSIVE_VIEW, +}) diff --git a/src/components/Dashboard/ViewDashboard.js b/src/components/Dashboard/ViewDashboard.js index 079676cdd..18e49d8e9 100644 --- a/src/components/Dashboard/ViewDashboard.js +++ b/src/components/Dashboard/ViewDashboard.js @@ -11,8 +11,11 @@ import DashboardsBar from '../ControlBar/ViewControlBar/DashboardsBar' import { sGetIsEditing } from '../../reducers/editDashboard' import { sGetIsPrinting } from '../../reducers/printDashboard' import { sGetSelectedId } from '../../reducers/selected' +import { sGetPassiveViewRegistered } from '../../reducers/passiveViewRegistered' import { acClearEditDashboard } from '../../actions/editDashboard' import { acClearPrintDashboard } from '../../actions/printDashboard' +import { acSetPassiveViewRegistered } from '../../actions/passiveViewRegistered' +import { apiPostDataStatistics } from '../../api/dataStatistics' import classes from './styles/ViewDashboard.module.css' @@ -35,6 +38,17 @@ export const ViewDashboard = props => { }) }, [props.selectedId]) + useEffect(() => { + if (!props.passiveViewRegistered) { + apiPostDataStatistics( + 'PASSIVE_DASHBOARD_VIEW', + props.selectedId + ).then(() => { + props.registerPassiveView() + }) + } + }, [props.passiveViewRegistered]) + const onExpandedChanged = expanded => setControlbarExpanded(expanded) return ( @@ -64,6 +78,8 @@ ViewDashboard.propTypes = { clearPrintDashboard: PropTypes.func, dashboardIsEditing: PropTypes.bool, dashboardIsPrinting: PropTypes.bool, + passiveViewRegistered: PropTypes.bool, + registerPassiveView: PropTypes.func, selectedId: PropTypes.string, } @@ -71,6 +87,7 @@ const mapStateToProps = state => { return { dashboardIsEditing: sGetIsEditing(state), dashboardIsPrinting: sGetIsPrinting(state), + passiveViewRegistered: sGetPassiveViewRegistered(state), selectedId: sGetSelectedId(state), } } @@ -78,4 +95,5 @@ const mapStateToProps = state => { export default connect(mapStateToProps, { clearEditDashboard: acClearEditDashboard, clearPrintDashboard: acClearPrintDashboard, + registerPassiveView: acSetPassiveViewRegistered, })(ViewDashboard) diff --git a/src/components/Dashboard/__tests__/ViewDashboard.spec.js b/src/components/Dashboard/__tests__/ViewDashboard.spec.js index 8957cbc86..c2b55fadb 100644 --- a/src/components/Dashboard/__tests__/ViewDashboard.spec.js +++ b/src/components/Dashboard/__tests__/ViewDashboard.spec.js @@ -2,6 +2,7 @@ import React from 'react' import { mount } from 'enzyme' import toJson from 'enzyme-to-json' import { ViewDashboard } from '../ViewDashboard' +import { apiPostDataStatistics } from '../../../api/dataStatistics' jest.mock('react', () => ({ ...jest.requireActual('react'), @@ -38,6 +39,12 @@ jest.mock( } ) +jest.mock('../../../api/dataStatistics', () => ({ + apiPostDataStatistics: jest.fn(() => { + return new Promise(resolve => resolve(true)) + }), +})) + describe('ViewDashboard', () => { let props @@ -72,4 +79,16 @@ describe('ViewDashboard', () => { expect(props.clearEditDashboard).not.toHaveBeenCalled() expect(props.clearPrintDashboard).toHaveBeenCalled() }) + + it('does not post passive view to api if passive view has been registered', () => { + props.passiveViewRegistered = true + mount() + expect(apiPostDataStatistics).not.toHaveBeenCalled() + }) + + it('posts passive view to api if passive view has not been registered', () => { + props.passiveViewRegistered = false + mount() + expect(apiPostDataStatistics).toHaveBeenCalled() + }) }) diff --git a/src/reducers/index.js b/src/reducers/index.js index d8ec91575..64b52993d 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -14,6 +14,7 @@ import itemFilters from './itemFilters' import style from './style' import dimensions from './dimensions' import activeModalDimension from './activeModalDimension' +import passiveViewRegistered from './passiveViewRegistered' export default combineReducers({ dashboards, @@ -30,4 +31,5 @@ export default combineReducers({ alert, dimensions, activeModalDimension, + passiveViewRegistered, }) diff --git a/src/reducers/passiveViewRegistered.js b/src/reducers/passiveViewRegistered.js new file mode 100644 index 000000000..2d7652651 --- /dev/null +++ b/src/reducers/passiveViewRegistered.js @@ -0,0 +1,13 @@ +export const REGISTER_PASSIVE_VIEW = 'REGISTER_PASSIVE_VIEW' + +export default (state = false, action) => { + switch (action.type) { + case REGISTER_PASSIVE_VIEW: { + return true + } + default: + return state + } +} + +export const sGetPassiveViewRegistered = state => state.passiveViewRegistered