Skip to content

Commit

Permalink
Merge branch 'master' into widgets
Browse files Browse the repository at this point in the history
  • Loading branch information
offtherailz authored Nov 16, 2017
2 parents 8ee504a + dff8fb5 commit 88fc23d
Show file tree
Hide file tree
Showing 15 changed files with 221 additions and 24 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"ag-grid": "3.3.3",
"ag-grid-react": "3.3.1",
"axios": "0.11.1",
"b64-to-blob": "1.2.19",
"babel-polyfill": "6.8.0",
"babel-standalone": "6.7.7",
"bootstrap": "3.3.5",
Expand Down Expand Up @@ -174,7 +175,7 @@
"reselect": "2.5.1",
"rxjs": "5.1.1",
"screenfull": "3.1.0",
"shpjs": "3.3.2",
"shpjs": "3.4.2",
"turf-bbox": "3.0.10",
"turf-buffer": "3.0.10",
"turf-intersect": "3.0.10",
Expand Down
2 changes: 2 additions & 0 deletions web/client/components/TOC/Toolbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class Toolbar extends React.Component {
static propTypes = {
groups: PropTypes.array,
selectedLayers: PropTypes.array,
generalInfoFormat: PropTypes.string,
selectedGroups: PropTypes.array,
onToolsActions: PropTypes.object,
text: PropTypes.object,
Expand Down Expand Up @@ -128,6 +129,7 @@ class Toolbar extends React.Component {
{...this.props.options.settingsOptions}
settings={this.props.settings}
element={this.props.selectedLayers[0]}
generalInfoFormat={this.props.generalInfoFormat}
retrieveLayerData={this.props.onToolsActions.onRetrieveLayerData}
updateSettings={this.props.onToolsActions.onUpdateSettings}
hideSettings={this.props.onToolsActions.onHideSettings}
Expand Down
2 changes: 2 additions & 0 deletions web/client/components/TOC/fragments/SettingsModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class SettingsModal extends React.Component {
updateNode: PropTypes.func,
removeNode: PropTypes.func,
retrieveLayerData: PropTypes.func,
generalInfoFormat: PropTypes.string,
titleText: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
opacityText: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
elevationText: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
Expand Down Expand Up @@ -176,6 +177,7 @@ class SettingsModal extends React.Component {
return (<FeatureInfoFormat
label= {<Message msgId="layerProperties.featureInfoFormatLbl"/>}
element={this.props.element}
generalInfoFormat={this.props.generalInfoFormat}
onInfoFormatChange={(key, value) => this.updateParams({[key]: value}, this.props.realtimeUpdate)} />);
}
}
Expand Down
26 changes: 22 additions & 4 deletions web/client/components/TOC/fragments/settings/FeatureInfoFormat.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
const PropTypes = require('prop-types');
/**
* Copyright 2017, GeoSolutions Sas.
* All rights reserved.
Expand All @@ -8,26 +7,45 @@ const PropTypes = require('prop-types');
*/

const React = require('react');
const PropTypes = require('prop-types');
const {DropdownList} = require('react-widgets');
const MapInfoUtils = require('../../../../utils/MapInfoUtils');


/**
* FeatureInfoFormat shows the infoformat selected for that layer or the default one taken
* from the general settings.
* @class
* @memberof components.toc
* @prop {object} [element] the layer options
* @prop {object} [label] the label shown for the combobox
* @prop {object} [defaultInfoFormat] the object used to show options labels
* @prop {string} [generalInfoFormat] the infoFormat value set in the general settings
* @prop {function} [onInfoFormatChange] it updates the infoFormat and/or viewer for the given layer
*/
module.exports = class extends React.Component {
static propTypes = {
element: PropTypes.object,
label: PropTypes.object,
defaultInfoFormat: PropTypes.object,
generalInfoFormat: PropTypes.string,
onInfoFormatChange: PropTypes.func
};

static defaultProps = {
defaultInfoFormat: MapInfoUtils.getAvailableInfoFormat(),
generalInfoFormat: "text/plain",
onInfoFormatChange: () => {}
};

render() {
const data = Object.keys(this.props.defaultInfoFormat).map((infoFormat) => {
getInfoFormat = (infoFormats) => {
return Object.keys(infoFormats).map((infoFormat) => {
return infoFormat;
});
}
render() {
// the selected value if missing on that layer should be set to the general info format value and not the first one.
const data = this.getInfoFormat(this.props.defaultInfoFormat);
const checkDisabled = !!(this.props.element.featureInfo && this.props.element.featureInfo.viewer);
return (
<div>
Expand All @@ -42,7 +60,7 @@ module.exports = class extends React.Component {
(<DropdownList
key="format-dropdown"
data={data}
value={this.props.element.featureInfo ? this.props.element.featureInfo.format : data[0]}
value={this.props.element.featureInfo ? this.props.element.featureInfo.format : MapInfoUtils.getLabelFromValue(this.props.generalInfoFormat)}
defaultValue={data[0]}
disabled={checkDisabled}
onChange={(value) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,22 @@ describe('test Layer Properties FeatureInfoFormat module component', () => {
li[0].click();
expect(spy.calls.length).toBe(1);
});
it('tests FeatureInfoFormat component for wms using generalInfoFormat', () => {
const l = {
name: 'layer00',
title: 'Layer',
visibility: true,
storeIndex: 9,
type: 'wms',
url: 'fakeurl'
};
const generalInfoFormat = "text/html";
const label = "label";
const comp = ReactDOM.render(<FeatureInfoFormat element={l} label={label} generalInfoFormat={generalInfoFormat} onInfoFormatChange={() => {}}/>, document.getElementById("container"));
expect(comp).toExist();
const div = ReactTestUtils.scryRenderedDOMComponentsWithTag( comp, "div" );
expect(div[2]).toExist();
expect(div[2].textContent).toBe("HTML");

});
});
10 changes: 7 additions & 3 deletions web/client/components/mapcontrols/annotations/Annotations.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ const defaultConfig = require('./AnnotationsConfig');
* @prop {function} onCleanHighlight triggered when the mouse is out of any annotation card
* @prop {function} onDetail triggered when the user clicks on an annotation card
* @prop {function} onFilter triggered when the user enters some text in the filtering widget
* @prop {function} classNameSelector optional selector to assign custom a CSS class to annotations, based on
* the annotation's attributes.
*/
class Annotations extends React.Component {
static propTypes = {
Expand All @@ -72,7 +74,8 @@ class Annotations extends React.Component {
current: PropTypes.string,
config: PropTypes.object,
filter: PropTypes.string,
onFilter: PropTypes.func
onFilter: PropTypes.func,
classNameSelector: PropTypes.func
};

static contextTypes = {
Expand All @@ -81,7 +84,8 @@ class Annotations extends React.Component {

static defaultProps = {
mode: 'list',
config: defaultConfig
config: defaultConfig,
classNameSelector: () => ''
};

getConfig = () => {
Expand Down Expand Up @@ -112,7 +116,7 @@ class Annotations extends React.Component {
};

renderCard = (annotation) => {
return (<div className="mapstore-annotations-panel-card" onMouseOver={() => this.props.onHighlight(annotation.properties.id)} onMouseOut={this.props.onCleanHighlight} onClick={() => this.props.onDetail(annotation.properties.id)}>
return (<div className={"mapstore-annotations-panel-card " + this.props.classNameSelector(annotation)} onMouseOver={() => this.props.onHighlight(annotation.properties.id)} onMouseOut={this.props.onCleanHighlight} onClick={() => this.props.onDetail(annotation.properties.id)}>
<span className="mapstore-annotations-panel-card-thumbnail">{this.renderThumbnail(annotation.style)}</span>
{this.getConfig().fields.map(f => this.renderField(f, annotation))}
</div>);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,4 +186,44 @@ describe("test the Annotations Panel", () => {
expect(TestUtils.scryRenderedDOMComponentsWithClass(annotations, "mapstore-annotations-panel-card").length).toBe(0);
expect(TestUtils.scryRenderedDOMComponentsWithClass(annotations, "myeditor").length).toBe(1);
});

it('test rendering custom class', () => {
const annotationsList = [{
properties: {
title: 'a',
description: 'b'
},
style: {
iconShape: 'square',
iconColor: 'blue'
}
}, {
properties: {
external: true,
title: 'c',
description: 'd'
},
style: {
iconShape: 'square',
iconColor: 'blue'
}
}];

const classNameSelector = (annotation) => {
if (annotation && annotation.properties && annotation.properties.external) {
return 'external';
}
return '';
};

const annotations = ReactDOM.render(<Annotations mode="list" classNameSelector={classNameSelector} annotations={annotationsList} />, document.getElementById("container"));

expect(annotations).toExist();

const cards = TestUtils.scryRenderedDOMComponentsWithClass(annotations, "mapstore-annotations-panel-card");
expect(cards.length).toBe(2);

const cardsExternal = TestUtils.scryRenderedDOMComponentsWithClass(annotations, "mapstore-annotations-panel-card external");
expect(cardsExternal.length).toBe(1);
});
});
27 changes: 23 additions & 4 deletions web/client/components/shapefile/SelectShape.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ const Spinner = require('react-spinkit');

const LocaleUtils = require('../../utils/LocaleUtils');

const JSZip = require('jszip');
const FileUtils = require('../../utils/FileUtils');
const {Promise} = require('es6-promise');

class SelectShape extends React.Component {
static propTypes = {
text: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
Expand Down Expand Up @@ -43,17 +47,32 @@ class SelectShape extends React.Component {
);
}

tryUnzip = (file) => {
return FileUtils.readZip(file).then((buffer) => {
return new JSZip(buffer);
});
};

isZip = (file) => {
return new Promise((resolve, reject) => {
if (file.type === 'application/zip' || file.type === 'application/x-zip-compressed') {
resolve();
} else {
this.tryUnzip(file).then(resolve).catch(reject);
}
});
};

checkfile = (files) => {
const allZip = files.filter((file) => { return file.type !== 'application/zip' && file.type !== 'application/x-zip-compressed'; }).length === 0;
if (allZip) {
Promise.all(files.map(file => this.isZip(file))).then(() => {
if (this.props.error) {
this.props.onShapeError(null);
}
this.props.onShapeChoosen(files);
} else {
}).catch(() => {
const error = LocaleUtils.getMessageById(this.context.messages, this.props.errorMessage);
this.props.onShapeError(error);
}
});
};
}

Expand Down
26 changes: 18 additions & 8 deletions web/client/components/shapefile/__tests__/SelectShape-test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const expect = require('expect');
const React = require('react');
const ReactDOM = require('react-dom');
const SelectShape = require('../SelectShape');
const b64toBlob = require('b64-to-blob');

const TestUtils = require('react-dom/test-utils');

Expand Down Expand Up @@ -43,10 +44,9 @@ describe("Test the select shapefile component", () => {
expect(dom.innerHTML.indexOf('TEST') !== -1).toBe(true);
});

it('upload file', () => {
let dropped = false;
it('upload file', (done) => {
const handler = () => {
dropped = true;
done();
};
const cmp = ReactDOM.render(<SelectShape onShapeChoosen={handler}/>, document.getElementById("container"));
expect(cmp).toExist();
Expand All @@ -59,13 +59,24 @@ describe("Test the select shapefile component", () => {
type: 'application/zip'
}];
TestUtils.Simulate.drop(content, { dataTransfer: { files } });
expect(dropped).toBe(true);
});

it('upload wrong file', () => {
let error = false;
it('upload wrong mime, right file', (done) => {
const handler = () => {
error = true;
done();
};
const cmp = ReactDOM.render(<SelectShape onShapeChoosen={handler}/>, document.getElementById("container"));
expect(cmp).toExist();
const dom = ReactDOM.findDOMNode(cmp);
expect(dom.getElementsByTagName('input').length).toBe(1);
const content = TestUtils.findRenderedDOMComponentWithClass(cmp, 'dropzone-content');
const files = [b64toBlob('UEsDBAoAAAAAACGPaktDvrfoAQAAAAEAAAAKAAAAc2FtcGxlLnR4dGFQSwECPwAKAAAAAAAhj2pLQ7636AEAAAABAAAACgAkAAAAAAAAACAAAAAAAAAAc2FtcGxlLnR4dAoAIAAAAAAAAQAYAGILh+1EWtMBy3f86URa0wHLd/zpRFrTAVBLBQYAAAAAAQABAFwAAAApAAAAAAA=', 'application/pdf')];
TestUtils.Simulate.drop(content, { dataTransfer: { files } });
});

it('upload wrong file', (done) => {
const handler = () => {
done();
};
const cmp = ReactDOM.render(<SelectShape onShapeError={handler}/>, document.getElementById("container"));
expect(cmp).toExist();
Expand All @@ -78,6 +89,5 @@ describe("Test the select shapefile component", () => {
type: 'application/pdf'
}];
TestUtils.Simulate.drop(content, { dataTransfer: { files } });
expect(error).toBe(true);
});
});
12 changes: 9 additions & 3 deletions web/client/plugins/TOC.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ const {createSelector} = require('reselect');
const {Glyphicon} = require('react-bootstrap');

const {changeLayerProperties, changeGroupProperties, toggleNode, contextNode,
sortNode, showSettings, hideSettings, updateSettings, updateNode, removeNode, browseData, selectNode, filterLayers, refreshLayerVersion} = require('../actions/layers');
sortNode, showSettings, hideSettings, updateSettings, updateNode, removeNode,
browseData, selectNode, filterLayers, refreshLayerVersion} = require('../actions/layers');
const {getLayerCapabilities} = require('../actions/layerCapabilities');
const {zoomToExtent} = require('../actions/map');
const {groupsSelector, layersSelector, selectedNodesSelector, layerFilterSelector, layerSettingSelector} = require('../selectors/layers');
const {mapSelector, mapNameSelector} = require('../selectors/map');
const {currentLocaleSelector} = require("../selectors/locale");
const {widgetBuilderAvailable} = require('../selectors/controls');
const {generalInfoFormatSelector} = require("../selectors/mapInfo");

const LayersUtils = require('../utils/LayersUtils');
const mapUtils = require('../utils/MapUtils');
Expand Down Expand Up @@ -71,8 +73,9 @@ const tocSelector = createSelector(
layersSelector,
mapNameSelector,
activeSelector,
widgetBuilderAvailable
], (enabled, groups, settings, map, currentLocale, selectedNodes, filterText, layers, mapName, catalogActive, activateWidgetTool) => ({
widgetBuilderAvailable,
generalInfoFormatSelector
], (enabled, groups, settings, map, currentLocale, selectedNodes, filterText, layers, mapName, catalogActive, activateWidgetTool, generalInfoFormat) => ({
enabled,
groups,
settings,
Expand All @@ -84,6 +87,7 @@ const tocSelector = createSelector(
currentLocale,
selectedNodes,
filterText,
generalInfoFormat,
selectedLayers: layers.filter((l) => head(selectedNodes.filter(s => s === l.id))),
noFilterResults: layers.filter((l) => filterLayersByTitle(l, filterText, currentLocale)).length === 0,
selectedGroups: selectedNodes.map(n => LayersUtils.getNode(groups, n)).filter(n => n && n.nodes),
Expand Down Expand Up @@ -163,6 +167,7 @@ class LayerTree extends React.Component {
currentLocale: PropTypes.string,
onFilter: PropTypes.func,
filterText: PropTypes.string,
generalInfoFormat: PropTypes.string,
selectedLayers: PropTypes.array,
selectedGroups: PropTypes.array,
mapName: PropTypes.string,
Expand Down Expand Up @@ -295,6 +300,7 @@ class LayerTree extends React.Component {
groups={this.props.groups}
selectedLayers={this.props.selectedLayers}
selectedGroups={this.props.selectedGroups}
generalInfoFormat={this.props.generalInfoFormat}
settings={this.props.settings}
activateTool={{
activateToolsContainer: this.props.activateToolsContainer,
Expand Down
Loading

0 comments on commit 88fc23d

Please sign in to comment.