Skip to content

Commit

Permalink
feat: summarize chart filters that have orgunit levels and/or groups (#…
Browse files Browse the repository at this point in the history
…298)

If a chart filter contains orgUnit levels and or groups, then the filter text will be summarized instead of listing each ou in the level/group. This is to avoid having very long chart filter texts.

Changes include:

 * request ou levels once at app startup, and store as prop in the App component
 * convert numeric ou ids to uids, which may be used when generating the chart title, as well as correctly populating the orgunit dialog
 * update apiVersion to current
 * convert args for tDoLoadVisualization to an object, since it had reached 4 args
 *  remove unused functions: apiFetchOrganisationUnits, apiFetchOrganisationUnitGroups
 *  moved getOrgUnitsFromIds to the DialogManager since it is only relevant for DialogManager

[DHIS2-6990]
  • Loading branch information
jenniferarnesen committed Aug 20, 2019
1 parent 1001d75 commit e5e0a7b
Show file tree
Hide file tree
Showing 11 changed files with 433 additions and 273 deletions.
4 changes: 2 additions & 2 deletions packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"webpack-bundle-analyzer": "^3.0.3"
},
"dependencies": {
"@dhis2/analytics": "2.1.1",
"@dhis2/analytics": "2.3.4",
"@dhis2/d2-i18n": "^1.0.3",
"@dhis2/d2-ui-core": "6.1.0",
"@dhis2/d2-ui-file-menu": "6.1.0",
Expand Down Expand Up @@ -120,7 +120,7 @@
"name": "DHIS2"
},
"dhis2": {
"apiVersion": "31"
"apiVersion": "32"
},
"activities": {
"dhis": {
Expand Down
44 changes: 40 additions & 4 deletions packages/app/src/actions/__tests__/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ const relativePeriod = 'xyzpdq';
selectors.sGetRootOrgUnit = () => rootOrganisationUnit;
selectors.sGetRelativePeriod = () => relativePeriod;

jest.mock('../../modules/orgUnit', () => ({
convertOuLevelsToUids: (ouLevels, vis) => vis,
}));

jest.mock('../../api/organisationUnits', () => ({
apiFetchOrganisationUnitLevels: () =>
Promise.resolve([
{
level: 2,
id: '2nd-floor',
},
]),
}));

describe('index', () => {
describe('tDoLoadVisualization', () => {
it('dispatches the correct actions after successfully fetching visualization', () => {
Expand Down Expand Up @@ -59,7 +73,12 @@ describe('index', () => {
const store = mockStore({});

return store
.dispatch(fromActions.tDoLoadVisualization())
.dispatch(
fromActions.tDoLoadVisualization({
type: 'test',
id: 1,
})
)
.then(() => {
expect(store.getActions()).toEqual(expectedActions);
});
Expand Down Expand Up @@ -101,7 +120,14 @@ describe('index', () => {
const store = mockStore({});

return store
.dispatch(fromActions.tDoLoadVisualization('test', 1, 1))
.dispatch(
fromActions.tDoLoadVisualization({
type: 'test',
id: 1,
interpretationId: 1,
ouLevels: [],
})
)
.then(() => {
expect(store.getActions()).toEqual(expectedActions);
});
Expand All @@ -117,7 +143,12 @@ describe('index', () => {
const store = mockStore({});

return store
.dispatch(fromActions.tDoLoadVisualization())
.dispatch(
fromActions.tDoLoadVisualization({
type: 'test',
id: 1,
})
)
.then(() => {
expect(store.getActions().slice(-1)[0].type).toEqual(
CLEAR_LOAD_ERROR
Expand Down Expand Up @@ -146,7 +177,12 @@ describe('index', () => {
const store = mockStore({});

return store
.dispatch(fromActions.tDoLoadVisualization())
.dispatch(
fromActions.tDoLoadVisualization({
type: 'test',
id: 1,
})
)
.then(() => {
expect(store.getActions()).toEqual(expectedActions);
});
Expand Down
15 changes: 9 additions & 6 deletions packages/app/src/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { sGetVisualization } from '../reducers/visualization';
import { sGetRootOrgUnit, sGetRelativePeriod } from '../reducers/settings';

import history from '../modules/history';
import { convertOuLevelsToUids } from '../modules/orgUnit';

export {
fromVisualization,
Expand All @@ -44,12 +45,14 @@ export const onError = (action, error) => {

// visualization, current, ui

export const tDoLoadVisualization = (type, id, interpretationId) => async (
dispatch,
getState
) => {
const onSuccess = model => {
const visualization = model.toJSON();
export const tDoLoadVisualization = ({
type,
id,
interpretationId,
ouLevels,
}) => async (dispatch, getState) => {
const onSuccess = async model => {
const visualization = convertOuLevelsToUids(ouLevels, model.toJSON());

if (interpretationId) {
const interpretation = visualization.interpretations.find(
Expand Down
40 changes: 2 additions & 38 deletions packages/app/src/api/organisationUnits.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,49 +14,13 @@ export const apiFetchOrganisationUnitRoot = () => {
.catch(onError);
};

/**
* Fetch organisation units
* @returns {Promise<T | never>}
*/
export const apiFetchOrganisationUnits = displayNameProperty => {
const fields = [
'id',
'path',
`${displayNameProperty}~rename(displayName)`,
'children::isNotEmpty',
];

return getInstance().then(d2 =>
d2.models.organisationUnits.list({
paging: false,
level: 1,
fields: fields.join(','),
})
);
};

/**
* Fetch organisation unit groups
* @returns {*}
*/
export const apiFetchOrganisationUnitGroups = displayNameProperty => {
const endPoint = '/organisationUnitGroups';
const fields = ['id', `${displayNameProperty}~rename(displayName)`, 'name'];
const url = `${endPoint}?paging=false&fields=${fields.join(',')}`;

return getInstance()
.then(d2 => d2.Api.getApi().get(url))
.then(({ organisationUnitGroups }) => organisationUnitGroups)
.catch(onError);
};

/**
* Fetch organisation unit levels
* @returns {*}
* @returns {Promise}
*/
export const apiFetchOrganisationUnitLevels = () => {
const endPoint = '/organisationUnitLevels';
const fields = ['id', 'displayName', 'name', 'level'];
const fields = ['id', 'name', 'displayName', 'level'];
const url = `${endPoint}?paging=false&fields=${fields.join(',')}`;

return getInstance()
Expand Down
9 changes: 5 additions & 4 deletions packages/app/src/components/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,12 @@ export class App extends Component {

if (!urlContainsCurrentAOKey && this.refetch(location)) {
await store.dispatch(
fromActions.tDoLoadVisualization(
this.props.apiObjectName,
fromActions.tDoLoadVisualization({
type: this.props.apiObjectName,
id,
interpretationId
)
interpretationId,
ouLevels: this.props.ouLevels,
})
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';

import debounce from 'lodash-es/debounce';
import isEqual from 'lodash-es/isEqual';

Expand All @@ -13,6 +12,7 @@ import {
DynamicDimension,
PeriodDimension,
OrgUnitDimension,
ouIdHelper,
DIMENSION_ID_DATA,
DIMENSION_ID_PERIOD,
DIMENSION_ID_ORGUNIT,
Expand Down Expand Up @@ -42,10 +42,7 @@ import { sGetDimensions } from '../../../reducers/dimensions';
import { sGetMetadata } from '../../../reducers/metadata';
import { sGetSettingsDisplayNameProperty } from '../../../reducers/settings';
import { apiFetchRecommendedIds } from '../../../api/dimensions';
import {
getOrgUnitsFromIds,
removeLastPathSegment,
} from '../../../modules/orgUnit';
import { removeLastPathSegment, getOuPath } from '../../../modules/orgUnit';

export class DialogManager extends Component {
state = {
Expand Down Expand Up @@ -90,8 +87,9 @@ export class DialogManager extends Component {
const forParentGraphMap = {};

items.forEach(ou => {
forMetadata[ou.id] = {
id: ou.id,
const id = ouIdHelper.removePrefix(ou.id);
forMetadata[id] = {
id,
name: ou.name || ou.displayName,
displayName: ou.displayName,
};
Expand Down Expand Up @@ -136,6 +134,18 @@ export class DialogManager extends Component {
: [];
};

getOrgUnitsFromIds = (ids, metadata, parentGraphMap) =>
ids
.filter(id => metadata[ouIdHelper.removePrefix(id)] !== undefined)
.map(id => {
const ouUid = ouIdHelper.removePrefix(id);
return {
id,
name: metadata[ouUid].displayName || metadata[ouUid].name,
path: getOuPath(ouUid, metadata, parentGraphMap),
};
});

// The OU content is persisted as mounted in order
// to cache the org unit tree data
renderPersistedContent = dimensionProps => {
Expand All @@ -148,7 +158,11 @@ export class DialogManager extends Component {
} = this.props;

if (this.state.ouMounted) {
const ouItems = getOrgUnitsFromIds(ouIds, metadata, parentGraphMap);
const ouItems = this.getOrgUnitsFromIds(
ouIds,
metadata,
parentGraphMap
);

const display =
DIMENSION_ID_ORGUNIT === dialogId ? 'block' : 'none';
Expand Down
15 changes: 6 additions & 9 deletions packages/app/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import metadataMiddleware from './middleware/metadata';
import App from './components/App';
import muiTheme from './modules/theme';
import { extractUserSettings } from './modules/settings';
import { apiFetchOrganisationUnitLevels } from './api/organisationUnits';

const apiObjectName = 'chart';

Expand All @@ -32,7 +33,7 @@ const configI18n = async userSettings => {
i18n.changeLanguage(uiLocale);
};

const render = (location, baseUrl, d2, userSettings) => {
const render = props => {
const store = configureStore(metadataMiddleware);

if (window.Cypress) {
Expand All @@ -42,13 +43,7 @@ const render = (location, baseUrl, d2, userSettings) => {
ReactDOM.render(
<Provider store={store}>
<MuiThemeProvider theme={muiTheme}>
<App
location={location}
baseUrl={baseUrl}
d2={d2}
userSettings={userSettings}
apiObjectName={apiObjectName}
/>
<App apiObjectName={apiObjectName} {...props} />
</MuiThemeProvider>
</Provider>,
document.getElementById('root')
Expand Down Expand Up @@ -78,7 +73,9 @@ const init = async () => {
baseUrl: config.baseUrl,
});

render(history.location, baseUrl, d2, userSettings);
const ouLevels = await apiFetchOrganisationUnitLevels();

render({ location: history.location, baseUrl, d2, userSettings, ouLevels });
};

init();
Loading

0 comments on commit e5e0a7b

Please sign in to comment.