Skip to content

Commit

Permalink
task: single value chart type (#300)
Browse files Browse the repository at this point in the history
Add support for new SINGLE_VALUE visualization type.

When multiple items are selected for dx, only the first one is used for
rendering the SINGLE_VALUE. A warning icon is shown and the label text
shows that 1 item out of n is used.
The tooltip only lists the one item that is used.

In the data dimension modal when single value
visualization type is used only the first item is used and the others
should be marked as inactive.

In the ItemSelector, when more than 1 item are selected, an info box is shown explaining that only the first item is used.
  • Loading branch information
edoardo committed Aug 21, 2019
1 parent 5dda862 commit c142ffc
Show file tree
Hide file tree
Showing 24 changed files with 408 additions and 78 deletions.
28 changes: 24 additions & 4 deletions packages/app/i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"POT-Creation-Date: 2019-07-02T11:48:24.367Z\n"
"PO-Revision-Date: 2019-07-02T11:48:24.367Z\n"
"POT-Creation-Date: 2019-08-08T13:09:25.099Z\n"
"PO-Revision-Date: 2019-08-08T13:09:25.099Z\n"

msgid "Rename successful"
msgstr ""
Expand Down Expand Up @@ -37,6 +37,11 @@ msgstr ""
msgid "Update"
msgstr ""

msgid ""
"'Single Value' is intended to show a single data item. Only the first item "
"will be used and saved."
msgstr ""

msgid "Hide"
msgstr ""

Expand Down Expand Up @@ -91,7 +96,10 @@ msgstr ""
msgid "Interpretations"
msgstr ""

msgid "selected"
msgid "{{total}} of 1 selected"
msgstr ""

msgid "{{total}} selected"
msgstr ""

msgid "Series"
Expand All @@ -109,6 +117,9 @@ msgstr ""
msgid "None selected"
msgstr ""

msgid "Only '{{name}}' in use"
msgstr ""

msgid "Unsaved chart"
msgstr ""

Expand Down Expand Up @@ -187,7 +198,7 @@ msgstr ""
msgid "Before first"
msgstr ""

msgid "After first"
msgid "After last"
msgstr ""

msgid "Before first and after last"
Expand Down Expand Up @@ -316,6 +327,9 @@ msgstr ""
msgid "Year over year (column)"
msgstr ""

msgid "Single value"
msgstr ""

msgid "Open as Map"
msgstr ""

Expand Down Expand Up @@ -424,6 +438,12 @@ msgstr ""
msgid "Please add {{data}} as a filter dimension"
msgstr ""

msgid "Please add one {{series}} dimension"
msgstr ""

msgid "Please add at least one period as {{filter}}"
msgstr ""

msgid "Today"
msgstr ""

Expand Down
6 changes: 3 additions & 3 deletions packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
"dependencies": {
"@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",
"@dhis2/d2-ui-interpretations": "6.1.0",
"@dhis2/d2-ui-core": "^6.2.1",
"@dhis2/d2-ui-file-menu": "^6.2.1",
"@dhis2/d2-ui-interpretations": "^6.2.1",
"@dhis2/data-visualizer-plugin": "33.0.3",
"@dhis2/ui": "^1.0.0-beta.11",
"@dhis2/ui-core": "^3.4.0",
Expand Down
27 changes: 27 additions & 0 deletions packages/app/src/assets/SingleValueIcon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import SvgIcon from '@material-ui/core/SvgIcon';

const SingleValueIcon = ({
style = { paddingRight: '8px', width: 24, height: 24 },
}) => (
<SvgIcon viewBox="0,0,48,48" style={style}>
<path
d="M45,9.59a2,2,0,0,1,2,2v25a2,2,0,0,1-2,2H3a2,2,0,0,1-2-2v-25a2,2,0,0,1,2-2H45m0-1H3a3,3,0,0,0-3,3v25a3,3,0,0,0,3,3H45a3,3,0,0,0,3-3v-25a3,3,0,0,0-3-3Z"
fill="#9e9e9e"
/>
<path
d="M13.06,31H10.82V20.16L7.51,21.29V19.4l5.26-1.94h.29Z"
fill="#1976d2"
/>
<path
d="M27,31H18V29.46l4.5-4.91a10.45,10.45,0,0,0,1.38-1.81,2.91,2.91,0,0,0,.42-1.46,2.2,2.2,0,0,0-.55-1.56,1.86,1.86,0,0,0-1.46-.59,2.2,2.2,0,0,0-1.7.66,2.65,2.65,0,0,0-.6,1.83H17.69a4.36,4.36,0,0,1,.56-2.22,3.9,3.9,0,0,1,1.6-1.54,5.19,5.19,0,0,1,2.41-.54,4.54,4.54,0,0,1,3.1,1A3.41,3.41,0,0,1,26.5,21a4.66,4.66,0,0,1-.57,2.12,11.88,11.88,0,0,1-1.87,2.52l-3.3,3.53H27Z"
fill="#1976d2"
/>
<path
d="M32.68,23.23h1.38a2.47,2.47,0,0,0,1.64-.54,1.9,1.9,0,0,0,.61-1.53,2.1,2.1,0,0,0-.51-1.5,2,2,0,0,0-1.54-.53,2.13,2.13,0,0,0-1.49.52A1.76,1.76,0,0,0,32.18,21H29.93a3.39,3.39,0,0,1,.55-1.89A3.74,3.74,0,0,1,32,17.79a5.15,5.15,0,0,1,2.21-.47,4.68,4.68,0,0,1,3.18,1,3.57,3.57,0,0,1,1.15,2.83A2.87,2.87,0,0,1,38,22.87a3.53,3.53,0,0,1-1.49,1.21,3.28,3.28,0,0,1,1.69,1.2,3.24,3.24,0,0,1,.58,1.95,3.63,3.63,0,0,1-1.25,2.89,4.82,4.82,0,0,1-3.28,1.08,4.82,4.82,0,0,1-3.19-1,3.44,3.44,0,0,1-1.24-2.77h2.25a1.88,1.88,0,0,0,.6,1.45,2.29,2.29,0,0,0,1.61.56,2.34,2.34,0,0,0,1.65-.56,2.09,2.09,0,0,0,.6-1.61,2.13,2.13,0,0,0-.63-1.65A2.7,2.7,0,0,0,34,25H32.68Z"
fill="#1976d2"
/>
</SvgIcon>
);

export default SingleValueIcon;
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import isEqual from 'lodash-es/isEqual';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';

import i18n from '@dhis2/d2-i18n';
import {
DataDimension,
DynamicDimension,
Expand Down Expand Up @@ -37,12 +38,14 @@ import {
sGetUiItemsByDimension,
sGetUiActiveModalDialog,
sGetUiParentGraphMap,
sGetUiType,
} from '../../../reducers/ui';
import { sGetDimensions } from '../../../reducers/dimensions';
import { sGetMetadata } from '../../../reducers/metadata';
import { sGetSettingsDisplayNameProperty } from '../../../reducers/settings';
import { apiFetchRecommendedIds } from '../../../api/dimensions';
import { removeLastPathSegment, getOuPath } from '../../../modules/orgUnit';
import { isSingleValue } from '../../../modules/chartTypes';

export class DialogManager extends Component {
state = {
Expand Down Expand Up @@ -127,9 +130,14 @@ export class DialogManager extends Component {
return this.props.selectedItems[dialogId]
? this.props.selectedItems[dialogId]
.filter(id => this.props.metadata[id])
.map(id => ({
.map((id, index) => ({
id,
name: this.props.metadata[id].name,
isActive:
dialogId === DIMENSION_ID_DATA &&
isSingleValue(this.props.type)
? index === 0
: true,
}))
: [];
};
Expand Down Expand Up @@ -185,6 +193,7 @@ export class DialogManager extends Component {
const {
displayNameProperty,
dialogId,
type,
dimensions,
removeUiItems,
setUiItems,
Expand All @@ -201,10 +210,18 @@ export class DialogManager extends Component {
const selectedItems = this.getSelectedItems(dialogId);

if (dialogId === DIMENSION_ID_DATA) {
const infoBoxMessage =
isSingleValue(type) && selectedItems.length > 1
? i18n.t(
"'Single Value' is intended to show a single data item. Only the first item will be used and saved."
)
: null;

return (
<DataDimension
displayNameProp={displayNameProperty}
selectedDimensions={selectedItems}
infoBoxMessage={infoBoxMessage}
{...dimensionProps}
/>
);
Expand Down Expand Up @@ -279,6 +296,7 @@ DialogManager.propTypes = {
dimensions: PropTypes.object,
metadata: PropTypes.object,
selectedItems: PropTypes.object,
type: PropTypes.string,
};

DialogManager.defaultProps = {
Expand All @@ -295,6 +313,7 @@ const mapStateToProps = state => ({
dxIds: sGetUiItemsByDimension(state, DIMENSION_ID_DATA),
ouIds: sGetUiItemsByDimension(state, DIMENSION_ID_ORGUNIT),
selectedItems: sGetUiItems(state),
type: sGetUiType(state),
});

export default connect(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ exports[`The DialogManager component renders OUDimension content with display:no
/>
</div>
<DataDimension
infoBoxMessage={null}
onSelect={[Function]}
selectedDimensions={Array []}
/>
Expand Down Expand Up @@ -119,6 +120,7 @@ exports[`The DialogManager component renders the DataDimension content in dialog
open={false}
>
<DataDimension
infoBoxMessage={null}
onSelect={[Function]}
selectedDimensions={Array []}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,5 @@ export const styles = {
display: 'flex',
flexDirection: 'column',
backgroundColor: colors.grey050,
padding: '8px 0 2px 8px',
},
textField: {
paddingBottom: '12px',
width: 'calc(100% - 8px)',
},
};
35 changes: 30 additions & 5 deletions packages/app/src/components/Layout/Chip.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import React from 'react';
import { connect } from 'react-redux';
import i18n from '@dhis2/d2-i18n';
import { FIXED_DIMENSIONS } from '@dhis2/analytics';
import { FIXED_DIMENSIONS, DIMENSION_ID_DATA } from '@dhis2/analytics';
import WarningIcon from '@material-ui/icons/Warning';

import Menu from './Menu';
import Tooltip from './Tooltip';
import { setDataTransfer } from '../../modules/dnd';
import { sGetDimensions } from '../../reducers/dimensions';
import { sGetUiItemsByDimension } from '../../reducers/ui';
import { sGetUiItemsByDimension, sGetUiType } from '../../reducers/ui';
import DynamicDimensionIcon from '../../assets/DynamicDimensionIcon';
import { sGetMetadata } from '../../reducers/metadata';
import { styles } from './styles/Chip.style';
import { isSingleValue } from '../../modules/chartTypes';

const TOOLTIP_ENTER_DELAY = 500;

Expand Down Expand Up @@ -70,10 +72,25 @@ class Chip extends React.Component {
return <DynamicDimensionIcon style={styles.dynamicDimensionIcon} />;
};

renderChip = () => {
const itemsLabel = `: ${this.props.items.length} ${i18n.t('selected')}`;
isSingleValueDataDimension = () =>
isSingleValue(this.props.type) &&
this.props.dimensionId === DIMENSION_ID_DATA &&
this.props.items.length > 1;

const chipLabel = `${this.props.dimensionName}${
renderChip = () => {
const itemsLabel = this.isSingleValueDataDimension()
? i18n.t('{{total}} of 1 selected', {
total: this.props.items.length,
})
: i18n.t('{{total}} selected', {
total: this.props.items.length,
});

const activeItemIds = this.isSingleValueDataDimension()
? this.props.items.slice(0, 1)
: [];

const chipLabel = `${this.props.dimensionName}: ${
this.props.items.length > 0 ? itemsLabel : ''
}`;
const anchorEl = document.getElementById(this.id);
Expand All @@ -82,6 +99,11 @@ class Chip extends React.Component {
...styles.chipWrapper,
...(!this.props.items.length ? styles.chipEmpty : {}),
};
const warningIcon = this.isSingleValueDataDimension() ? (
<div style={styles.warningIconWrapper}>
<WarningIcon style={styles.warningIcon} />
</div>
) : null;

return (
<div
Expand All @@ -99,6 +121,7 @@ class Chip extends React.Component {
>
<div style={styles.iconWrapper}>{icon}</div>
{chipLabel}
{warningIcon}
</div>
<div style={styles.chipRight}>
<Menu
Expand All @@ -109,6 +132,7 @@ class Chip extends React.Component {
{anchorEl && (
<Tooltip
dimensionId={this.props.dimensionId}
activeItemIds={activeItemIds}
open={this.state.tooltipOpen}
anchorEl={anchorEl}
/>
Expand All @@ -126,6 +150,7 @@ const mapStateToProps = (state, ownProps) => ({
dimensionName: (sGetDimensions(state)[ownProps.dimensionId] || {}).name,
items: sGetUiItemsByDimension(state, ownProps.dimensionId) || emptyItems,
metadata: sGetMetadata(state),
type: sGetUiType(state),
});

export default connect(mapStateToProps)(Chip);
3 changes: 3 additions & 0 deletions packages/app/src/components/Layout/Layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { connect } from 'react-redux';
import DefaultLayout from './DefaultLayout/DefaultLayout';
import YearOverYearLayout from './YearOverYearLayout/YearOverYearLayout';
import PieLayout from './PieLayout/PieLayout';
import SingleValueLayout from './SingleValueLayout/SingleValueLayout';
import {
COLUMN,
STACKED_COLUMN,
Expand All @@ -16,6 +17,7 @@ import {
GAUGE,
YEAR_OVER_YEAR_LINE,
YEAR_OVER_YEAR_COLUMN,
SINGLE_VALUE,
} from '../../modules/chartTypes';
import { sGetUiType } from '../../reducers/ui';

Expand All @@ -31,6 +33,7 @@ const layoutMap = {
[GAUGE]: PieLayout,
[YEAR_OVER_YEAR_LINE]: YearOverYearLayout,
[YEAR_OVER_YEAR_COLUMN]: YearOverYearLayout,
[SINGLE_VALUE]: SingleValueLayout,
};

const getLayoutByType = (type, props) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';
import { AXIS_NAME_COLUMNS, AXIS_NAME_FILTERS } from '@dhis2/analytics';

import DefaultAxis from '../DefaultLayout/DefaultAxis';
import defaultAxisStyles from '../DefaultLayout/styles/DefaultAxis.style';
import defaultLayoutStyles from '../DefaultLayout/styles/DefaultLayout.style';

const Layout = () => (
<div id="layout-ct" style={defaultLayoutStyles.ct}>
<div
id="axis-group-1"
style={{
...defaultLayoutStyles.axisGroup,
...defaultLayoutStyles.axisGroupLeft,
}}
>
<DefaultAxis
axisName={AXIS_NAME_COLUMNS}
style={{
...defaultLayoutStyles.filters,
...defaultAxisStyles.axisContainerLeft,
}}
/>
</div>
<div
id="axis-group-2"
style={{
...defaultLayoutStyles.axisGroup,
...defaultLayoutStyles.axisGroupRight,
}}
>
<DefaultAxis
axisName={AXIS_NAME_FILTERS}
style={defaultLayoutStyles.filters}
/>
</div>
</div>
);

export default Layout;
Loading

0 comments on commit c142ffc

Please sign in to comment.