Skip to content

Commit 15868c2

Browse files
committed
Some minor fixes and improvements
- Now the color selection works also for lines and bars - Wizard button moved to the top - Improved error management. Now a chart that returns error can not be completed.
1 parent 756a4d9 commit 15868c2

19 files changed

Lines changed: 207 additions & 53 deletions

File tree

web/client/actions/widgets.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const uuid = require('uuid/v1');
99
const INSERT = "WIDGETS:INSERT";
1010
const NEW = "WIGETS:NEW";
1111
const EDIT = "WIDGETS:EDIT";
12-
const EDIT_NEW = "WIGETS:EDIT_NEW";
12+
const EDIT_NEW = "WIDGETS:EDIT_NEW";
1313
const EDITOR_CHANGE = "WIDGETS:EDITOR_CHANGE";
1414
const EDITOR_SETTING_CHANGE = "WIGETS:EDITOR_SETTING_CHANGE";
1515
const UPDATE = "WIDGETS:UPDATE";

web/client/components/charts/Bar.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ const React = require('react');
99
const {BarChart, Bar} = require('recharts');
1010
const {renderCartesianTools} = require('./cartesian');
1111

12-
module.exports = ({width = 600, height = 300, data, series =[], colorGenerator, ...props} = {}) => {
12+
module.exports = ({width = 600, height = 300, data, series =[], colorGenerator, autoColorOptions, ...props} = {}) => {
1313
const seriesArray = (Array.isArray(series) ? series : [series]);
1414
const COLORS = colorGenerator(seriesArray.length);
15-
return (<BarChart width={width} height={height} data={data}>
15+
// WORKAROUND: rechart do not rerender line and bar charts when change colors.
16+
const key = (COLORS || ["linechart"]).join("");
17+
return (<BarChart key={key} autoColorOptions={autoColorOptions} width={width} height={height} data={data}>
1618
{seriesArray.map(({color, ...serie} = {}, i) => <Bar key={`bar-${i}`} fill={COLORS[i]} {...serie}/>)}
1719
{renderCartesianTools(props)}
1820
{props.children}

web/client/components/charts/Line.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ const {renderCartesianTools} = require('./cartesian');
1212
module.exports = ({width = 600, height = 300, data, series =[], colorGenerator, autoColorOptions, isAnimationActive, ...props} = {}) => {
1313
const seriesArray = (Array.isArray(series) ? series : [series]);
1414
const COLORS = colorGenerator(seriesArray.length, autoColorOptions);
15-
return (<LineChart width={width} height={height} data={data}>
15+
// WORKAROUND: rechart do not rerender line and bar charts when change colors.
16+
const key = (COLORS || ["linechart"]).join("");
17+
return (<LineChart key={key} width={width} height={height} data={data}>
1618
{seriesArray.map(({color, ...serie}, i) => <Line key={`line-${i}`} isAnimationActive={isAnimationActive} stroke={COLORS[i]} {...serie} />)}
1719
{renderCartesianTools(props)}
1820
{props.children}

web/client/components/charts/SimpleChart.jsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@ const AUTOCOLOR_DEFAULTS = {
3434
*/
3535
const SimpleChart = ({type="line", tooltip = {}, legend = {}, autoColorOptions = AUTOCOLOR_DEFAULTS, colorGenerator, ...props} = {}) => {
3636
const Component = charts[type];
37-
const {base, range, ...opts} = autoColorOptions;
38-
const defaultColorGenerator = (total) => {
39-
return (sameToneRangeColors(base, range, total + 1, opts) || []).slice(1);
37+
38+
const defaultColorGenerator = (total, colorOptions = autoColorOptions) => {
39+
const {base, range, ...opts} = colorOptions;
40+
return (sameToneRangeColors(base, range, total + 1, opts) || [0]).slice(1);
4041
};
4142
return (<Component margin={{top: 5, right: 30, left: 20, bottom: 5}} colorGenerator={colorGenerator || defaultColorGenerator} autoColorOptions={autoColorOptions} {...props} {...{legend, tooltip}}>
4243
{tooltip !== false ? <Tooltip {...tooltip}/> : null}

web/client/components/style/ColorRangeSelector.jsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,6 @@ class ColorRangeSelector extends React.Component {
4343
options: {base: 190, range: 340, options: {base: 10, range: 360, s: 0.67, v: 0.67}}
4444
}]
4545
};
46-
47-
componentWillMount() {
48-
this.setState({
49-
ramp: this.props.value
50-
});
51-
}
5246
getValue = () => {
5347
this.getItems().filter( (i = {}) => i === this.props.value || i.name === (this.props.value && this.props.value.name));
5448
}
@@ -61,11 +55,12 @@ class ColorRangeSelector extends React.Component {
6155
}
6256

6357
render() {
58+
const items = this.getItems();
6459
return (
6560
<DropdownList
6661
className="color-range-selector"
67-
data={this.getItems()}
68-
valueComponent={ColorRampItem}
62+
data={items}
63+
valueComponent={(props) => <ColorRampItem {...props} data={items} />}
6964
itemComponent={ColorRampItem}
7065
value={this.getValue()}
7166
onChange={(ramp) => {

web/client/components/style/EqualIntervalComponents/ColorRampItem.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class ColorRampItem extends React.Component {
88
};
99

1010
render() {
11-
let ramp = this.props.item && this.props.item.ramp || colors[this.props.item.name] && colors[this.props.item.name][5] || [];
11+
let ramp = this.props.item && (this.props.item.ramp || colors[this.props.item.name] && colors[this.props.item.name][5]) || [];
1212
return (<div className="color-ramp-item">
1313
{ramp.map(cell => <div className="color-cell" key={this.props.item && this.props.item.name + "-" + cell} style={{backgroundColor: cell}}/>)}
1414
<div className="colorname-cell">

web/client/components/widgets/builder/BuilderHeader.jsx

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,37 @@ const { Button, Row, Col, Glyphicon } = require('react-bootstrap');
1010
const Message = require('../../I18N/Message');
1111
const Toolbar = require('../../misc/toolbar/Toolbar');
1212

13-
module.exports = ({onClose = () => {}, openFilterEditor = () => {}} = {}) =>
13+
const getBackTooltipId = step => {
14+
switch (step) {
15+
case 1:
16+
return "widgets.builder.wizard.backToTypeSelection";
17+
case 2:
18+
return "widgets.builder.wizard.backToChartOptions";
19+
default:
20+
return "back";
21+
22+
}
23+
};
24+
25+
const getNextTooltipId = step => {
26+
switch (step) {
27+
case 0:
28+
return "widgets.builder.wizard.configureChartOptions";
29+
case 1:
30+
return "widgets.builder.wizard.configureWidgetOptions";
31+
default:
32+
return "next";
33+
}
34+
};
35+
36+
const getSaveTooltipId = (step, {id} = {}) => {
37+
if (id) {
38+
return "widgets.builder.wizard.updateWidget";
39+
}
40+
return "widgets.builder.wizard.addToTheMap";
41+
};
42+
43+
module.exports = ({onClose = () => {}, openFilterEditor = () => {}, step = 0, editorData = {}, valid, setPage = () => {}, onFinish = () => {}} = {}) =>
1444
(<div className="mapstore-flex-container">
1545
<div className="m-header">
1646
<Row>
@@ -31,9 +61,25 @@ module.exports = ({onClose = () => {}, openFilterEditor = () => {}} = {}) =>
3161
bsSize: "sm"
3262
}}
3363
buttons={[{
64+
onClick: () => setPage(Math.max(0, step - 1)),
65+
visible: step > 0,
66+
glyph: "arrow-left",
67+
tooltipId: getBackTooltipId(step)
68+
}, {
3469
onClick: openFilterEditor,
3570
glyph: "filter",
3671
tooltipId: "widgets.builder.setupFilter"
72+
}, {
73+
onClick: () => setPage(Math.min(step + 1, 2)),
74+
visible: !!(step === 0 && (!editorData.type || editorData.type.indexOf("WI") !== 0)) || step === 1,
75+
disabled: step === 1 && !valid,
76+
glyph: "arrow-right",
77+
tooltipId: getNextTooltipId(step)
78+
}, {
79+
onClick: () => onFinish(Math.min(step + 1, 1)),
80+
visible: step === 2,
81+
glyph: "floppy-disk",
82+
tooltipId: getSaveTooltipId(step, editorData)
3783
}]} />
3884
</div>
3985
</Row>

web/client/components/widgets/builder/ChartWizard.jsx

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
* LICENSE file in the root directory of this source tree.
77
*/
88
const React = require('react');
9+
910
const {wizardHanlders} = require('../../misc/wizard/enhancers');
1011
const loadingState = require('../../misc/enhancers/loadingState')(({loading, data}) => loading || !data, {width: 500, height: 200});
1112

12-
const Wizard = wizardHanlders(require('../../misc/wizard/WizardContainer'));
1313
const ChartType = require('./wizard/chart/ChartType');
1414
const wfsChartOptions = require('./wizard/chart/wfsChartOptions');
1515
const ChartOptions = wfsChartOptions(require('./wizard/chart/ChartOptions'));
@@ -19,7 +19,7 @@ const wpsChart = require('../enhancers/wpsChart');
1919
const dependenciesToFilter = require('../enhancers/dependenciesToFilter');
2020
const emptyChartState = require('../enhancers/emptyChartState');
2121
const errorChartState = require('../enhancers/errorChartState');
22-
const {compose} = require('recompose');
22+
const {compose, lifecycle} = require('recompose');
2323
const enhanchePreview = compose(
2424
dependenciesToFilter,
2525
wpsChart,
@@ -38,9 +38,14 @@ const sampleProps = {
3838

3939
const isChartOptionsValid = (options = {}) => options.aggregateFunction && options.aggregationAttribute && options.groupByAttributes;
4040

41-
const renderPreview = ({data = {}, layer, dependencies={}}) => isChartOptionsValid(data.options)
41+
const Wizard = wizardHanlders(require('../../misc/wizard/WizardContainer'));
42+
43+
44+
const renderPreview = ({data = {}, layer, dependencies={}, setValid = () => {}}) => isChartOptionsValid(data.options)
4245
? (<PreviewChart
4346
key="preview-chart"
47+
onLoad={() => setValid(true)}
48+
onLoadError={() => setValid(false)}
4449
isAnimationActive={false}
4550
dependencies={dependencies}
4651
{...sampleProps}
@@ -61,15 +66,19 @@ const renderPreview = ({data = {}, layer, dependencies={}}) => isChartOptionsVal
6166
autoColorOptions={data.autoColorOptions}
6267
legend={data.legend} />);
6368

64-
65-
module.exports = ({onChange = () => {}, onFinish = () => {}, setPage= () => {}, data = {}, layer ={}, step=0, types, featureTypeProperties, dependencies}) =>
69+
const enhanceWizard = compose(lifecycle({
70+
componentWillReceiveProps: ({data = {}, valid, setValid = () => {}} = {}) => {
71+
if (valid && !isChartOptionsValid(data.options)) {
72+
setValid(false);
73+
}
74+
}})
75+
);
76+
module.exports = enhanceWizard(({onChange = () => {}, onFinish = () => {}, setPage= () => {}, setValid, data = {}, layer ={}, step=0, types, featureTypeProperties, dependencies}) =>
6677
(<Wizard
6778
step={step}
6879
setPage={setPage}
69-
onFinish={() => {
70-
onFinish({layer: data.layer || layer, url: layer.url, ...data});
71-
}}
72-
isStepValid={ n => n === 1 ? isChartOptionsValid(data.options) : true} skipButtonsOnSteps={[0]}>
80+
onFinish={onFinish}
81+
isStepValid={ n => n === 1 ? isChartOptionsValid(data.options) : true} hideButtons>
7382
<ChartType
7483
key="type"
7584
type={data.type}
@@ -83,13 +92,13 @@ module.exports = ({onChange = () => {}, onFinish = () => {}, setPage= () => {},
8392
data={data}
8493
onChange={onChange}
8594
layer={data.layer || layer}
86-
sampleChart={renderPreview({data, layer: data.layer || layer, dependencies})}
95+
sampleChart={renderPreview({data, layer: data.layer || layer, dependencies, setValid: v => setValid(v && isChartOptionsValid(data.options))})}
8796
/>
8897
<WidgetOptions
8998
key="widget-options"
9099
data={data}
91100
onChange={onChange}
92101
layer={data.layer || layer}
93-
sampleChart={renderPreview({data, layer: data.layer || layer})}
102+
sampleChart={renderPreview({data, layer: data.layer || layer, dependencies, setValid: v => setValid(v && isChartOptionsValid(data.options))})}
94103
/>
95-
</Wizard>);
104+
</Wizard>));

web/client/components/widgets/builder/WidgetsBuilder.jsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ const React = require('react');
99

1010
const ChartWizard = require('./ChartWizard');
1111
module.exports = ({
12-
settings = {step: 0},
13-
insertWidget = () => {},
12+
step=0,
13+
valid,
14+
onFinish = () => {},
15+
setValid = () => {},
1416
onEditorChange = () => {},
1517
setPage = () => {},
1618
layer,
@@ -21,11 +23,13 @@ module.exports = ({
2123
) =>
2224
(<ChartWizard
2325
dependencies={dependencies}
26+
valid={valid}
2427
types={types}
2528
featureTypeProperties={featureTypeProperties}
26-
step={settings.step}
29+
step={step}
2730
layer={layer}
2831
data={editorData}
29-
onFinish={insertWidget}
32+
setValid={setValid}
33+
onFinish={onFinish}
3034
setPage={setPage}
3135
onChange={onEditorChange}/>);

web/client/components/widgets/builder/__tests__/BuilderHeader-test.jsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,41 @@ describe('BuilderHeader component', () => {
4747
ReactTestUtils.Simulate.click(btn); // <-- trigger event callback
4848
expect(spy).toHaveBeenCalled();
4949
});
50+
it('Test BuilderHeader nextButton', () => {
51+
const actions = {
52+
setPage: () => {}
53+
};
54+
const spysetPage = expect.spyOn(actions, 'setPage' );
55+
ReactDOM.render(<BuilderHeader step={1} valid setPage={actions.setPage} editorData={{type: "bar"}}/>, document.getElementById("container"));
56+
const btn = document.querySelector('.glyphicon-arrow-right');
57+
expect(btn).toExist();
58+
const prev = document.querySelector('.glyphicon-arrow-left');
59+
expect(prev).toExist();
60+
ReactTestUtils.Simulate.click(btn); // <-- trigger event callback
61+
expect(spysetPage).toHaveBeenCalled();
62+
});
63+
it('Test BuilderHeader prevButton', () => {
64+
const actions = {
65+
setPage: () => {}
66+
};
67+
const spysetPage = expect.spyOn(actions, 'setPage' );
68+
ReactDOM.render(<BuilderHeader step={1} valid setPage={actions.setPage} editorData={{type: "bar"}}/>, document.getElementById("container"));
69+
const btn = document.querySelector('.glyphicon-arrow-right');
70+
expect(btn).toExist();
71+
const prev = document.querySelector('.glyphicon-arrow-left');
72+
expect(prev).toExist();
73+
ReactTestUtils.Simulate.click(prev); // <-- trigger event callback
74+
expect(spysetPage).toHaveBeenCalled();
75+
});
76+
it('Test BuilderHeader save', () => {
77+
const actions = {
78+
onFinish: () => {}
79+
};
80+
const spyonFinish = expect.spyOn(actions, 'onFinish' );
81+
ReactDOM.render(<BuilderHeader step={2} valid onFinish={actions.onFinish} editorData={{type: "bar"}}/>, document.getElementById("container"));
82+
const btn = document.querySelector('.glyphicon-floppy-disk');
83+
expect(btn).toExist();
84+
ReactTestUtils.Simulate.click(btn); // <-- trigger event callback
85+
expect(spyonFinish).toHaveBeenCalled();
86+
});
5087
});

0 commit comments

Comments
 (0)