Skip to content

Commit

Permalink
Some minor fixes and improvements
Browse files Browse the repository at this point in the history
 - 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.
  • Loading branch information
offtherailz committed Nov 21, 2017
1 parent 756a4d9 commit 15868c2
Show file tree
Hide file tree
Showing 19 changed files with 207 additions and 53 deletions.
2 changes: 1 addition & 1 deletion web/client/actions/widgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const uuid = require('uuid/v1');
const INSERT = "WIDGETS:INSERT";
const NEW = "WIGETS:NEW";
const EDIT = "WIDGETS:EDIT";
const EDIT_NEW = "WIGETS:EDIT_NEW";
const EDIT_NEW = "WIDGETS:EDIT_NEW";
const EDITOR_CHANGE = "WIDGETS:EDITOR_CHANGE";
const EDITOR_SETTING_CHANGE = "WIGETS:EDITOR_SETTING_CHANGE";
const UPDATE = "WIDGETS:UPDATE";
Expand Down
6 changes: 4 additions & 2 deletions web/client/components/charts/Bar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ const React = require('react');
const {BarChart, Bar} = require('recharts');
const {renderCartesianTools} = require('./cartesian');

module.exports = ({width = 600, height = 300, data, series =[], colorGenerator, ...props} = {}) => {
module.exports = ({width = 600, height = 300, data, series =[], colorGenerator, autoColorOptions, ...props} = {}) => {
const seriesArray = (Array.isArray(series) ? series : [series]);
const COLORS = colorGenerator(seriesArray.length);
return (<BarChart width={width} height={height} data={data}>
// WORKAROUND: rechart do not rerender line and bar charts when change colors.
const key = (COLORS || ["linechart"]).join("");
return (<BarChart key={key} autoColorOptions={autoColorOptions} width={width} height={height} data={data}>
{seriesArray.map(({color, ...serie} = {}, i) => <Bar key={`bar-${i}`} fill={COLORS[i]} {...serie}/>)}
{renderCartesianTools(props)}
{props.children}
Expand Down
4 changes: 3 additions & 1 deletion web/client/components/charts/Line.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ const {renderCartesianTools} = require('./cartesian');
module.exports = ({width = 600, height = 300, data, series =[], colorGenerator, autoColorOptions, isAnimationActive, ...props} = {}) => {
const seriesArray = (Array.isArray(series) ? series : [series]);
const COLORS = colorGenerator(seriesArray.length, autoColorOptions);
return (<LineChart width={width} height={height} data={data}>
// WORKAROUND: rechart do not rerender line and bar charts when change colors.
const key = (COLORS || ["linechart"]).join("");
return (<LineChart key={key} width={width} height={height} data={data}>
{seriesArray.map(({color, ...serie}, i) => <Line key={`line-${i}`} isAnimationActive={isAnimationActive} stroke={COLORS[i]} {...serie} />)}
{renderCartesianTools(props)}
{props.children}
Expand Down
7 changes: 4 additions & 3 deletions web/client/components/charts/SimpleChart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ const AUTOCOLOR_DEFAULTS = {
*/
const SimpleChart = ({type="line", tooltip = {}, legend = {}, autoColorOptions = AUTOCOLOR_DEFAULTS, colorGenerator, ...props} = {}) => {
const Component = charts[type];
const {base, range, ...opts} = autoColorOptions;
const defaultColorGenerator = (total) => {
return (sameToneRangeColors(base, range, total + 1, opts) || []).slice(1);

const defaultColorGenerator = (total, colorOptions = autoColorOptions) => {
const {base, range, ...opts} = colorOptions;
return (sameToneRangeColors(base, range, total + 1, opts) || [0]).slice(1);
};
return (<Component margin={{top: 5, right: 30, left: 20, bottom: 5}} colorGenerator={colorGenerator || defaultColorGenerator} autoColorOptions={autoColorOptions} {...props} {...{legend, tooltip}}>
{tooltip !== false ? <Tooltip {...tooltip}/> : null}
Expand Down
11 changes: 3 additions & 8 deletions web/client/components/style/ColorRangeSelector.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,6 @@ class ColorRangeSelector extends React.Component {
options: {base: 190, range: 340, options: {base: 10, range: 360, s: 0.67, v: 0.67}}
}]
};

componentWillMount() {
this.setState({
ramp: this.props.value
});
}
getValue = () => {
this.getItems().filter( (i = {}) => i === this.props.value || i.name === (this.props.value && this.props.value.name));
}
Expand All @@ -61,11 +55,12 @@ class ColorRangeSelector extends React.Component {
}

render() {
const items = this.getItems();
return (
<DropdownList
className="color-range-selector"
data={this.getItems()}
valueComponent={ColorRampItem}
data={items}
valueComponent={(props) => <ColorRampItem {...props} data={items} />}
itemComponent={ColorRampItem}
value={this.getValue()}
onChange={(ramp) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class ColorRampItem extends React.Component {
};

render() {
let ramp = this.props.item && this.props.item.ramp || colors[this.props.item.name] && colors[this.props.item.name][5] || [];
let ramp = this.props.item && (this.props.item.ramp || colors[this.props.item.name] && colors[this.props.item.name][5]) || [];
return (<div className="color-ramp-item">
{ramp.map(cell => <div className="color-cell" key={this.props.item && this.props.item.name + "-" + cell} style={{backgroundColor: cell}}/>)}
<div className="colorname-cell">
Expand Down
48 changes: 47 additions & 1 deletion web/client/components/widgets/builder/BuilderHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,37 @@ const { Button, Row, Col, Glyphicon } = require('react-bootstrap');
const Message = require('../../I18N/Message');
const Toolbar = require('../../misc/toolbar/Toolbar');

module.exports = ({onClose = () => {}, openFilterEditor = () => {}} = {}) =>
const getBackTooltipId = step => {
switch (step) {
case 1:
return "widgets.builder.wizard.backToTypeSelection";
case 2:
return "widgets.builder.wizard.backToChartOptions";
default:
return "back";

}
};

const getNextTooltipId = step => {
switch (step) {
case 0:
return "widgets.builder.wizard.configureChartOptions";
case 1:
return "widgets.builder.wizard.configureWidgetOptions";
default:
return "next";
}
};

const getSaveTooltipId = (step, {id} = {}) => {
if (id) {
return "widgets.builder.wizard.updateWidget";
}
return "widgets.builder.wizard.addToTheMap";
};

module.exports = ({onClose = () => {}, openFilterEditor = () => {}, step = 0, editorData = {}, valid, setPage = () => {}, onFinish = () => {}} = {}) =>
(<div className="mapstore-flex-container">
<div className="m-header">
<Row>
Expand All @@ -31,9 +61,25 @@ module.exports = ({onClose = () => {}, openFilterEditor = () => {}} = {}) =>
bsSize: "sm"
}}
buttons={[{
onClick: () => setPage(Math.max(0, step - 1)),
visible: step > 0,
glyph: "arrow-left",
tooltipId: getBackTooltipId(step)
}, {
onClick: openFilterEditor,
glyph: "filter",
tooltipId: "widgets.builder.setupFilter"
}, {
onClick: () => setPage(Math.min(step + 1, 2)),
visible: !!(step === 0 && (!editorData.type || editorData.type.indexOf("WI") !== 0)) || step === 1,
disabled: step === 1 && !valid,
glyph: "arrow-right",
tooltipId: getNextTooltipId(step)
}, {
onClick: () => onFinish(Math.min(step + 1, 1)),
visible: step === 2,
glyph: "floppy-disk",
tooltipId: getSaveTooltipId(step, editorData)
}]} />
</div>
</Row>
Expand Down
33 changes: 21 additions & 12 deletions web/client/components/widgets/builder/ChartWizard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
* LICENSE file in the root directory of this source tree.
*/
const React = require('react');

const {wizardHanlders} = require('../../misc/wizard/enhancers');
const loadingState = require('../../misc/enhancers/loadingState')(({loading, data}) => loading || !data, {width: 500, height: 200});

const Wizard = wizardHanlders(require('../../misc/wizard/WizardContainer'));
const ChartType = require('./wizard/chart/ChartType');
const wfsChartOptions = require('./wizard/chart/wfsChartOptions');
const ChartOptions = wfsChartOptions(require('./wizard/chart/ChartOptions'));
Expand All @@ -19,7 +19,7 @@ const wpsChart = require('../enhancers/wpsChart');
const dependenciesToFilter = require('../enhancers/dependenciesToFilter');
const emptyChartState = require('../enhancers/emptyChartState');
const errorChartState = require('../enhancers/errorChartState');
const {compose} = require('recompose');
const {compose, lifecycle} = require('recompose');
const enhanchePreview = compose(
dependenciesToFilter,
wpsChart,
Expand All @@ -38,9 +38,14 @@ const sampleProps = {

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

const renderPreview = ({data = {}, layer, dependencies={}}) => isChartOptionsValid(data.options)
const Wizard = wizardHanlders(require('../../misc/wizard/WizardContainer'));


const renderPreview = ({data = {}, layer, dependencies={}, setValid = () => {}}) => isChartOptionsValid(data.options)
? (<PreviewChart
key="preview-chart"
onLoad={() => setValid(true)}
onLoadError={() => setValid(false)}
isAnimationActive={false}
dependencies={dependencies}
{...sampleProps}
Expand All @@ -61,15 +66,19 @@ const renderPreview = ({data = {}, layer, dependencies={}}) => isChartOptionsVal
autoColorOptions={data.autoColorOptions}
legend={data.legend} />);


module.exports = ({onChange = () => {}, onFinish = () => {}, setPage= () => {}, data = {}, layer ={}, step=0, types, featureTypeProperties, dependencies}) =>
const enhanceWizard = compose(lifecycle({
componentWillReceiveProps: ({data = {}, valid, setValid = () => {}} = {}) => {
if (valid && !isChartOptionsValid(data.options)) {
setValid(false);
}
}})
);
module.exports = enhanceWizard(({onChange = () => {}, onFinish = () => {}, setPage= () => {}, setValid, data = {}, layer ={}, step=0, types, featureTypeProperties, dependencies}) =>
(<Wizard
step={step}
setPage={setPage}
onFinish={() => {
onFinish({layer: data.layer || layer, url: layer.url, ...data});
}}
isStepValid={ n => n === 1 ? isChartOptionsValid(data.options) : true} skipButtonsOnSteps={[0]}>
onFinish={onFinish}
isStepValid={ n => n === 1 ? isChartOptionsValid(data.options) : true} hideButtons>
<ChartType
key="type"
type={data.type}
Expand All @@ -83,13 +92,13 @@ module.exports = ({onChange = () => {}, onFinish = () => {}, setPage= () => {},
data={data}
onChange={onChange}
layer={data.layer || layer}
sampleChart={renderPreview({data, layer: data.layer || layer, dependencies})}
sampleChart={renderPreview({data, layer: data.layer || layer, dependencies, setValid: v => setValid(v && isChartOptionsValid(data.options))})}
/>
<WidgetOptions
key="widget-options"
data={data}
onChange={onChange}
layer={data.layer || layer}
sampleChart={renderPreview({data, layer: data.layer || layer})}
sampleChart={renderPreview({data, layer: data.layer || layer, dependencies, setValid: v => setValid(v && isChartOptionsValid(data.options))})}
/>
</Wizard>);
</Wizard>));
12 changes: 8 additions & 4 deletions web/client/components/widgets/builder/WidgetsBuilder.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ const React = require('react');

const ChartWizard = require('./ChartWizard');
module.exports = ({
settings = {step: 0},
insertWidget = () => {},
step=0,
valid,
onFinish = () => {},
setValid = () => {},
onEditorChange = () => {},
setPage = () => {},
layer,
Expand All @@ -21,11 +23,13 @@ module.exports = ({
) =>
(<ChartWizard
dependencies={dependencies}
valid={valid}
types={types}
featureTypeProperties={featureTypeProperties}
step={settings.step}
step={step}
layer={layer}
data={editorData}
onFinish={insertWidget}
setValid={setValid}
onFinish={onFinish}
setPage={setPage}
onChange={onEditorChange}/>);
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,41 @@ describe('BuilderHeader component', () => {
ReactTestUtils.Simulate.click(btn); // <-- trigger event callback
expect(spy).toHaveBeenCalled();
});
it('Test BuilderHeader nextButton', () => {
const actions = {
setPage: () => {}
};
const spysetPage = expect.spyOn(actions, 'setPage' );
ReactDOM.render(<BuilderHeader step={1} valid setPage={actions.setPage} editorData={{type: "bar"}}/>, document.getElementById("container"));
const btn = document.querySelector('.glyphicon-arrow-right');
expect(btn).toExist();
const prev = document.querySelector('.glyphicon-arrow-left');
expect(prev).toExist();
ReactTestUtils.Simulate.click(btn); // <-- trigger event callback
expect(spysetPage).toHaveBeenCalled();
});
it('Test BuilderHeader prevButton', () => {
const actions = {
setPage: () => {}
};
const spysetPage = expect.spyOn(actions, 'setPage' );
ReactDOM.render(<BuilderHeader step={1} valid setPage={actions.setPage} editorData={{type: "bar"}}/>, document.getElementById("container"));
const btn = document.querySelector('.glyphicon-arrow-right');
expect(btn).toExist();
const prev = document.querySelector('.glyphicon-arrow-left');
expect(prev).toExist();
ReactTestUtils.Simulate.click(prev); // <-- trigger event callback
expect(spysetPage).toHaveBeenCalled();
});
it('Test BuilderHeader save', () => {
const actions = {
onFinish: () => {}
};
const spyonFinish = expect.spyOn(actions, 'onFinish' );
ReactDOM.render(<BuilderHeader step={2} valid onFinish={actions.onFinish} editorData={{type: "bar"}}/>, document.getElementById("container"));
const btn = document.querySelector('.glyphicon-floppy-disk');
expect(btn).toExist();
ReactTestUtils.Simulate.click(btn); // <-- trigger event callback
expect(spyonFinish).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe('WidgetsBuilder component', () => {
expect(container.querySelector('.chart-options-form')).toNotExist();
});
it('WidgetsBuilder rendering chart options', () => {
ReactDOM.render(<WidgetsBuilder settings={{step: 1}} />, document.getElementById("container"));
ReactDOM.render(<WidgetsBuilder step={1} />, document.getElementById("container"));
const container = document.getElementById('container');
const el = container.querySelector('.chart-options-form');
expect(el).toExist();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ module.exports = ({data = {options: {}}, onChange = () => {}, options=[], aggreg
<Col sm={6}>
<ColorRangeSelector
items={getColorRangeItems(data.type)}
value={head(getColorRangeItems(data.type).filter(c => c.name === data.colorRangeName))}
value={head(getColorRangeItems(data.type).filter(c => data.autoColorOptions && c.name === data.autoColorOptions.name ))}
samples={data.type === "pie" ? 5 : 1}
onChange={v => {onChange("autoColorOptions", v.options); onChange("colorRangeName", v.name); }}/>
onChange={v => {onChange("autoColorOptions", {...v.options, name: v.name}); }}/>
</Col>
</FormGroup>
<FormGroup controlId="mapSync" className="mapstore-block-width">
Expand Down
14 changes: 7 additions & 7 deletions web/client/components/widgets/enhancers/wpsChart.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const dataStreamFactory = ($props) =>
&& sameOptions(options, newProps.options)
&& sameFilter(filter, newProps.filter))
.switchMap(
({layer={}, options, filter}) =>
({layer={}, options, filter, onLoad = () => {}, onLoadError = () => {}}) =>
wpsAggregate(getLayerUrl(layer), {featureType: layer.name, ...options, filter}, {
timeout: 15000
}).map((response) => ({
Expand All @@ -54,13 +54,13 @@ const dataStreamFactory = ($props) =>
data: wpsAggregateToChartData(response.data),
series: [{dataKey: `${response.data.AggregationFunctions[0]}(${response.data.AggregationAttribute})`}],
xAxis: {dataKey: response.data.GroupByAttributes[0]}
}))
})).do(onLoad)
.catch((e) => Rx.Observable.of({
loading: false,
error: e,
data: []
}))
.startWith({loading: true})
loading: false,
error: e,
data: []
}).do(onLoadError)
).startWith({loading: true})
);
module.exports = compose(
withProps( () => ({
Expand Down
Loading

0 comments on commit 15868c2

Please sign in to comment.