Commit 91aaf4d1 authored by Matija Obreza's avatar Matija Obreza

KPI UI updates

- Execution dimension alias added
- Execution group-by support added
- Run results ordered by dimensions
parent 732169ab
......@@ -1239,17 +1239,22 @@
"COUNT": "Count",
"AVERAGE": "Average",
"SUM": "Sum"
},
"group": {
"field": "Field",
"op": "Operation",
"alias": "Name"
}
},
"executionCard": {
"dimensionField": "Field",
"dimensionLink": "Link",
"dimensionsInfo": "Dimension info",
"dimensionsInfo": "Dimensions",
"mainInformation": "General info",
"parameterCondition": "Condition",
"parameterDescription": "Description",
"parameterEntity": "Entity",
"parameterInfo": "Parameter info",
"parameterInfo": "KPI Parameter",
"property": "Property",
"type": "Type"
},
......@@ -1258,9 +1263,11 @@
"selectDimension": "Select dimension"
},
"dimensions": "Dimensions",
"group": "Group by",
"type": "Type",
"field": "Field",
"link": "Link",
"alias": "Alias",
"parameter": "Parameter",
"parameterSelector": {
"selectParameter": "Select parameter"
......
......@@ -13,17 +13,22 @@
"COUNT": "Count",
"AVERAGE": "Average",
"SUM": "Sum"
},
"group": {
"field": "Field",
"op": "Operation",
"alias": "Name"
}
},
"executionCard": {
"dimensionField": "Field",
"dimensionLink": "Link",
"dimensionsInfo": "Dimension info",
"dimensionsInfo": "Dimensions",
"mainInformation": "General info",
"parameterCondition": "Condition",
"parameterDescription": "Description",
"parameterEntity": "Entity",
"parameterInfo": "Parameter info",
"parameterInfo": "KPI Parameter",
"property": "Property",
"type": "Type"
},
......@@ -32,9 +37,11 @@
"selectDimension": "Select dimension"
},
"dimensions": "Dimensions",
"group": "Group by",
"type": "Type",
"field": "Field",
"link": "Link",
"alias": "Alias",
"parameter": "Parameter",
"parameterSelector": {
"selectParameter": "Select parameter"
......
......@@ -130,19 +130,22 @@ class ExecutionDisplay extends React.Component<IExecutionProps, any> {
</PageSection>
</Grid>
{ execution.executionDimensions && execution.executionDimensions.length > 0 &&
<Grid item sm={ 12 } md={ 6 }>
<PageSection title={ t('kpi.admin.c.executionCard.dimensionsInfo') }>
{ execution.executionDimensions.map((dimension) => (
<Properties key={ dimension.id }>
<PropertiesItem title={ t('common:label.name') }>{ dimension.dimension.title }</PropertiesItem>
{ dimension.field && <PropertiesItem title={ t('kpi.admin.c.executionCard.dimensionField') }>{ execution.parameter.entity }.{ dimension.field }</PropertiesItem> }
{ dimension.link && <PropertiesItem title={ t('kpi.admin.c.executionCard.dimensionLink') }>{ execution.parameter.entity }.{ dimension.link }</PropertiesItem> }
</Properties>
)) }
</PageSection>
</Grid>
}
<Grid item sm={ 12 } md={ 6 }>
<PageSection title={ t('kpi.admin.c.executionCard.dimensionsInfo') }>
{ execution.executionDimensions && execution.executionDimensions.map((dimension) => (
<Properties key={ dimension.id }>
<PropertiesItem title={ t('common:label.name') }>{ dimension.dimension.title }</PropertiesItem>
{ dimension.field && <PropertiesItem title={ t('kpi.admin.c.executionCard.dimensionField') }>{ execution.parameter.entity }{ dimension.link && `.${dimension.link}` }.{ dimension.field }</PropertiesItem> }
</Properties>
)) }
{ execution.groups && execution.groups.map((group, index) => (
<Properties key={ `eg-${index}` }>
<PropertiesItem title={ t('kpi.admin.c.execution.group.alias') }>{ group.alias }</PropertiesItem>
<PropertiesItem title={ t('kpi.admin.c.execution.group.field') }>{ group.op && `${group.op} of ` }{ group.field }</PropertiesItem>
</Properties>
)) }
</PageSection>
</Grid>
<Grid item sm={ 12 } md={ 6 }>
<PageSection title={ currentRun === null ? t('kpi.admin.p.executionDisplay.lastRun') : <span>{ t('kpi.admin.p.executionDisplay.runFrom') }<PrettyDate value={ currentRun.timestamp }/></span> }>
......
......@@ -2,6 +2,7 @@ import * as React from 'react';
import withStyles from '@material-ui/core/styles/withStyles';
import Number from 'ui/common/Number';
import Observation from 'model/kpi/Observation';
const styles = (theme) => ({
root: {
......@@ -24,6 +25,18 @@ const styles = (theme) => ({
/*tslint:enable*/
});
const COMPARE_OBSERVATIONS = (a: Observation, b: Observation) => {
if (a.dimensions && b.dimensions && a.dimensions.length <= b.dimensions.length) {
for (let i = 0; i < a.dimensions.length; i++) {
const comp = a.dimensions[i].value.localeCompare(b.dimensions[i].value);
if (comp !== 0) {
return comp;
}
}
}
return Math.sign(b.value - a.value);
};
class RunTable extends React.Component<any> {
public render() {
......@@ -33,24 +46,24 @@ class RunTable extends React.Component<any> {
{ runInfo &&
<thead className={ `${classes.header} back-green` }>
<tr>
{ execution.executionDimensions.map((ed, i) => (
<td key={ ed.id }>
{ execution.parameter.entity } { ed.link } { ed.field }
{ runInfo && runInfo.observations && runInfo.observations[0] && runInfo.observations[0].dimensions && runInfo.observations[0].dimensions.map((dim) => (
<td key={ dim.name }>
{ dim.name }
</td>
)) }
<td>{ execution.type }</td>
{ execution.type === 'AVERAGE' && <td>Std. dev</td> }
<td className="text-right">{ execution.type }</td>
{ execution.type === 'AVERAGE' && <td className="text-right">STDDEV</td> }
</tr>
</thead>
}
<tbody className={ classes.body }>
{ runInfo && runInfo.observations.sort((a, b) => b.value - a.value).map((obs, i) => (
{ runInfo && runInfo.observations.sort((a, b) => COMPARE_OBSERVATIONS(a, b)).map((obs, i) => (
<tr key={ obs.id }>
{ obs.dimensions.map((dim, i) => (
<td key={ i }>{ dim.value }</td>
)) }
<td><Number value={ obs.value }/></td>
{ obs.stdDev && <td><Number value={ obs.stdDev }/></td> }
<td className="text-right"><Number value={ obs.value }/></td>
{ obs.stdDev !== null && <td className="text-right"><Number value={ obs.stdDev }/></td> }
</tr>
)) }
</tbody>
......
......@@ -27,7 +27,7 @@ class ExecutionDimensionForm extends React.Component<IStringListProps> {
<div>
{ renderList && renderList.length > 0 && renderList.map((renderItem, index) => (
<Grid key={ `executionDimensions-${index}` } container spacing={ 8 } style={ {display: 'flex', alignItems: 'baseline'} }>
<Grid item xs={ 6 }>
<Grid item xs={ 3 }>
<div style={ {margin: '.2rem 0', padding: '.2rem 1rem', backgroundColor: '#e8e5e1', color: '#202222'} } key={ renderItem.dimension.name }>
{ renderItem.dimension.title }
<div className="font-bold float-right" onClick={ () => removeByIndex(index) }>X</div>
......@@ -50,6 +50,14 @@ class ExecutionDimensionForm extends React.Component<IStringListProps> {
validate={ [Validators.required] }
/>
</Grid>
<Grid item xs={ 3 }>
<Field
name={ `executionDimensions[${index}].alias` }
component={ TextField }
type="text"
label={ `kpi.admin.c.executionForm.alias` }
/>
</Grid>
</Grid>
)) }
</div>
......
import * as React from 'react';
import {translate} from 'react-i18next';
import {Field} from 'redux-form';
import ExecutionGroup from 'model/kpi/ExecutionGroup';
import Grid from '@material-ui/core/Grid';
import { TextField } from 'ui/common/text-field';
import Validators from 'utilities/Validators';
import ItemsEditor from 'ui/common/ItemsEditor';
const execGroupField = (member, index, fields, itemLabel) => (
<Grid key={ `executionGroups-${index}` } container spacing={ 8 } style={ {display: 'flex', alignItems: 'baseline'} }>
<Grid item xs={ 6 }>
<Field
name={ `${member}.field` }
required
component={ TextField }
type="text"
label={ `kpi.admin.c.execution.group.field` }
validators={ [ Validators.required ] }
/>
</Grid>
<Grid item xs={ 2 }>
<Field
name={ `${member}.op` }
component={ TextField }
type="text"
label={ `kpi.admin.c.execution.group.op` }
/>
</Grid>
<Grid item xs={ 4 }>
<Field
name={ `${member}.alias` }
required
component={ TextField }
type="text"
label={ `kpi.admin.c.execution.group.alias` }
validators={ [ Validators.required ] }
/>
</Grid>
</Grid>
);
interface IExecutionGroupsFieldProps extends React.ClassAttributes<any> {
t: any;
label?: string;
groups: ExecutionGroup[];
}
class ExecutionGroupsField extends React.Component<IExecutionGroupsFieldProps> {
private onAddGroup = () => {
console.log('Adding exec group');
}
private onDeleteGroup = (x) => {
console.log('Removing exec group', x);
}
public render() {
const { label } = this.props;
return(
<ItemsEditor name="groups" itemLabel={ label } addItem={ this.onAddGroup } removeItem={ this.onDeleteGroup } component={ execGroupField } />
);
}
}
export default translate()(ExecutionGroupsField);
......@@ -15,6 +15,7 @@ import RadioGroup from '@material-ui/core/RadioGroup';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import FormLabel from '@material-ui/core/FormLabel';
import FormControl from '@material-ui/core/FormControl';
import GroupListField from './GroupListField';
const ExecutionTypeSelector = ({input, meta, t, ...rest}) => {
console.log('Execsel', input, rest);
......@@ -92,6 +93,11 @@ class ExecutionForm extends React.Component<any, void> {
label={ t(`kpi.admin.c.executionForm.dimensions`) }
validate={ [Validators.required] }
/>
<GroupListField
name={ `groups` }
label={ t(`kpi.admin.c.executionForm.group`) }
/>
</div>
{ error && <div style={ {color: 'red'} }>{ error }</div> }
<Button variant="contained" type="submit" style={ {marginRight: '1rem', marginTop: '1rem'} } disabled={ submitting || invalid }>{ t('common:action.save') }</Button>
......
import ExecutionDimension from 'model/kpi/ExecutionDimension';
import KPIParameter from 'model/kpi/KPIParameter';
import ExecutionGroup from './ExecutionGroup';
/*
* Defined in Swagger as '#/definitions/Execution'
......@@ -9,6 +10,7 @@ class Execution {
public createdBy: number;
public createdDate: Date;
public executionDimensions: ExecutionDimension[];
public groups: ExecutionGroup[];
public id: number;
public lastModifiedBy: number;
public lastModifiedDate: Date;
......
/*
* Defined in Swagger as '#/definitions/ExecutionGroup'
*/
class ExecutionGroup {
public field: string;
public op: string;
public alias: string;
}
export default ExecutionGroup;
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment