From 1981bd9c01edbe4fd142a9850af315a5099b74ed Mon Sep 17 00:00:00 2001 From: Renaud009 Date: Wed, 10 Oct 2018 20:48:24 +0100 Subject: [PATCH 01/15] prototype writing a shapefile to geoserver --- package-lock.json | 30 +++++++++++++++++++ package.json | 1 + .../WidgetDrawFeatures/WidgetDrawFeatures.js | 29 ++++++++++++++++-- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 63316d6..6557b63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3800,6 +3800,14 @@ "meow": "3.7.0" } }, + "dbf": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/dbf/-/dbf-0.1.4.tgz", + "integrity": "sha1-Fi8Nj9HbN8l2RYrG/m9VtIxy9GY=", + "requires": { + "jdataview": "2.5.0" + } + }, "debounce": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.1.0.tgz", @@ -7614,6 +7622,11 @@ } } }, + "jdataview": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/jdataview/-/jdataview-2.5.0.tgz", + "integrity": "sha1-MIGz/qZR+TF+xr1P6y3cmKpB1ZU=" + }, "jquery": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz", @@ -7916,6 +7929,14 @@ "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=", "dev": true }, + "jszip": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-2.5.0.tgz", + "integrity": "sha1-dET9hVHd8+XacZj+oMkbyDCMwnQ=", + "requires": { + "pako": "0.2.9" + } + }, "karma": { "version": "0.13.22", "resolved": "https://registry.npmjs.org/karma/-/karma-0.13.22.tgz", @@ -13711,6 +13732,15 @@ } } }, + "shp-write": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/shp-write/-/shp-write-0.3.2.tgz", + "integrity": "sha1-ysPoS8/clTxPwnOhsvKEPW249p0=", + "requires": { + "dbf": "0.1.4", + "jszip": "2.5.0" + } + }, "shuffle-seed": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/shuffle-seed/-/shuffle-seed-1.1.6.tgz", diff --git a/package.json b/package.json index 89b062f..993dbc9 100644 --- a/package.json +++ b/package.json @@ -138,6 +138,7 @@ "redux-thunk": "^2.0.0", "rimraf": "^2.5.1", "sass-loader": "^3.0.0", + "shp-write": "^0.3.2", "style-loader": "^0.13.0", "url": "^0.11.0", "url-loader": "^0.5.6", diff --git a/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js b/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js index d1ffd94..26a30b9 100644 --- a/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js +++ b/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js @@ -11,6 +11,7 @@ import FormControl from '@material-ui/core/FormControl'; import TextField from '@material-ui/core/TextField'; import Typography from '@material-ui/core/Typography'; import { GeoJSON } from 'ol/format'; +import shpwrite from 'shp-write'; const styles = theme => ({ root: { @@ -51,9 +52,33 @@ class WidgetDrawFeatures extends React.Component { }; onSaveDrawnLayer = () => { - const geoJSONriter= new GeoJSON(); - const geoJSONString = geoJSONriter.writeFeatures(this.props.layerCustomFeature.drawnCustomFeatures); + const geoJSONWriter= new GeoJSON(); + const geoJSONString = geoJSONWriter.writeFeatures(this.props.layerCustomFeature.drawnCustomFeatures); this.props.layerCustomFeatureActions.setGeoJSONDrawnFeatures(geoJSONString); + + // (optional) set names for feature types and zipped folder + var options = { + folder: 'myshapes', + types: { + point: 'mypoints', + polygon: 'mypolygons', + line: 'mylines' + } + }; + const buffer = shpwrite.zip(JSON.parse(geoJSONString), options); + fetch(`${__PAVICS_GEOSERVER_API_PATH__}/test/datastores/test/file.shp`, { // Your POST endpoint + method: 'PUT', + headers: { + "Content-Type": "application/zip" + }, + body: buffer // This is your file object + }).then( + response => response.json() // if the response is a JSON object + ).then( + success => alert(success) // Handle the success response object + ).catch( + error => alert(error) // Handle the error response object + ); }; onHandleTextChanged = field => event => { From f0bdadee694a2650d4548c36cb9a3703253c330a Mon Sep 17 00:00:00 2001 From: Renaud009 Date: Mon, 22 Oct 2018 21:52:03 +0100 Subject: [PATCH 02/15] Uploading custom and local shapefile to geoserver --- config/index.js | 2 +- package-lock.json | 10 + package.json | 1 + src/components/Visualize/Visualize.js | 2 +- .../WidgetDrawFeatures/WidgetDrawFeatures.js | 337 +++++++++++++----- src/redux/modules/LayerCustomFeature.js | 62 ++++ 6 files changed, 313 insertions(+), 101 deletions(-) diff --git a/config/index.js b/config/index.js index df71426..19cbccc 100644 --- a/config/index.js +++ b/config/index.js @@ -38,7 +38,7 @@ const config = { // ---------------------------------- pavics_malleefowl_path: malleefowlHost, pavics_phoenix_path: `${URL_BASE}:8443`, - pavics_geoserver_path: `${URL_BASE}/geoserver`, + pavics_geoserver_path: process.env.PAVICS_GEOSERVER_URL || `${URL_BASE}/geoserver`, pavics_geoserver_api_path: process.env.PAVICS_GEOSERVER_API || `${URL_BASE}/twitcher/ows/proxy/geoserver-api`, pavics_geoserver_workspaces_service_name: process.env.PAVICS_GEOSERVER_WORKSPACES_SERVICE_NAME || 'geoserver-api', pavics_ncwms_path: ncwmsHost, diff --git a/package-lock.json b/package-lock.json index 6557b63..608e908 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13739,6 +13739,16 @@ "requires": { "dbf": "0.1.4", "jszip": "2.5.0" + }, + "dependencies": { + "jszip": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-2.5.0.tgz", + "integrity": "sha1-dET9hVHd8+XacZj+oMkbyDCMwnQ=", + "requires": { + "pako": "0.2.9" + } + } } }, "shuffle-seed": { diff --git a/package.json b/package.json index 993dbc9..246f9dd 100644 --- a/package.json +++ b/package.json @@ -108,6 +108,7 @@ "ip": "^1.1.2", "jquery": "^3.0.0", "json-loader": "^0.5.4", + "jszip": "^2.5.0", "koa": "^2.0.0-alpha.3", "koa-connect-history-api-fallback": "^0.3.0", "koa-convert": "^1.2.0", diff --git a/src/components/Visualize/Visualize.js b/src/components/Visualize/Visualize.js index d3be61a..e4f9146 100644 --- a/src/components/Visualize/Visualize.js +++ b/src/components/Visualize/Visualize.js @@ -74,7 +74,7 @@ const styles = { opacity: OPACITY }, customRegions: { - height: '420px', + height: '500px', overflow: 'auto', width: '400px', opacity: OPACITY diff --git a/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js b/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js index 26a30b9..38d1775 100644 --- a/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js +++ b/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { withStyles } from '@material-ui/core/styles'; -import { VISUALIZE_DRAW_MODES } from './../../constants'; +import {withStyles} from '@material-ui/core/styles'; +import {VISUALIZE_DRAW_MODES} from './../../constants'; import Divider from'@material-ui/core/Divider'; import Button from'@material-ui/core/Button'; import InputLabel from '@material-ui/core/InputLabel'; @@ -10,13 +10,24 @@ import MenuItem from '@material-ui/core/MenuItem'; import FormControl from '@material-ui/core/FormControl'; import TextField from '@material-ui/core/TextField'; import Typography from '@material-ui/core/Typography'; -import { GeoJSON } from 'ol/format'; +import Tab from '@material-ui/core/Tab'; +import Tabs from '@material-ui/core/Tabs'; +import DrawIcon from '@material-ui/icons/Edit'; +import FileUpload from '@material-ui/icons/FileUpload'; +import AppBar from '@material-ui/core/AppBar'; +import Card from '@material-ui/core/Card'; +import CardHeader from '@material-ui/core/CardHeader'; +import CardContent from '@material-ui/core/CardContent'; +import Avatar from '@material-ui/core/Avatar'; +import FolderIcon from '@material-ui/icons/Folder'; +import {GeoJSON} from 'ol/format'; import shpwrite from 'shp-write'; +import prj from 'shp-write/src/prj'; +import geojson from 'shp-write/src/geojson'; +import JSZip from 'jszip'; const styles = theme => ({ - root: { - - } + root: {} }); class WidgetDrawFeatures extends React.Component { @@ -25,17 +36,21 @@ class WidgetDrawFeatures extends React.Component { layerCustomFeatureActions: PropTypes.object.isRequired }; - constructor (props) { + constructor(props) { super(props); this.state = { - name: "", - description: "" + name: '', + description: '', + fileName: '', + fileType: '', + fileSize: '', + fileLastModified: 'N/A', }; } - componentWillReceiveProps (nextProps) { - const { currentSelectedDrawnFeatureProperties } = nextProps.layerCustomFeature; - if(currentSelectedDrawnFeatureProperties && currentSelectedDrawnFeatureProperties !== this.props.layerCustomFeature.currentSelectedDrawnFeatureProperties) { + componentWillReceiveProps(nextProps) { + const {currentSelectedDrawnFeatureProperties} = nextProps.layerCustomFeature; + if (currentSelectedDrawnFeatureProperties && currentSelectedDrawnFeatureProperties !== this.props.layerCustomFeature.currentSelectedDrawnFeatureProperties) { this.setState({ name: currentSelectedDrawnFeatureProperties.name, description: currentSelectedDrawnFeatureProperties.description @@ -43,6 +58,51 @@ class WidgetDrawFeatures extends React.Component { } } + createZipFileFromCustomDrawnFeature() { + const geoJSONWriter = new GeoJSON(); + const geoJSONString = geoJSONWriter.writeFeatures(this.props.layerCustomFeature.drawnCustomFeatures); + let geoJSON = JSON.parse(geoJSONString); + geoJSON.features.map(feature => feature.properties = {}); + this.props.layerCustomFeatureActions.setGeoJSONDrawnFeatures(geoJSONString); + + // DEPRECATED, zip contains a folder at root + /*var options = { + folder: 'USER_SHAPEFILES', + types: { + polygon: 'CUSTOM_' + new Date().getTime(), + } + }; + const buffer = shpwrite.zip(geoJSON, options); + shpwrite.download(geoJSON, options);*/ + + // FIXME: FOLLOWING PROCEDURE CREATES ONE MULTIPOLYGON INSTEAD OF MANY POLYGONS + let zip = new JSZip(); + const points = geojson.point(geoJSON); + const lines = geojson.line(geoJSON); + const polygons = geojson.polygon(geoJSON); + const types = [points, lines, polygons]; + console.log(types.length); + types.forEach((layer) => { + if (layer.geometries.length && layer.geometries[0].length) { + shpwrite.write( + // field definitions + layer.properties, + // geometry type + layer.type, + // geometries + layer.geometries, + (err, files) => { + const fileName = 'CUSTOM_' + new Date().getTime(); + zip.file(fileName + '.shp', files.shp.buffer, {binary: true}); + zip.file(fileName + '.shx', files.shx.buffer, {binary: true}); + zip.file(fileName + '.dbf', files.dbf.buffer, {binary: true}); + zip.file(fileName + '.prj', prj); + }); + } + }); + return zip; + } + onSelectedDrawingTool = (event) => { this.props.layerCustomFeatureActions.setCurrentDrawingTool(event.target.value); }; @@ -51,34 +111,21 @@ class WidgetDrawFeatures extends React.Component { this.props.layerCustomFeatureActions.setDrawnCustomFeatures([]); }; - onSaveDrawnLayer = () => { - const geoJSONWriter= new GeoJSON(); - const geoJSONString = geoJSONWriter.writeFeatures(this.props.layerCustomFeature.drawnCustomFeatures); - this.props.layerCustomFeatureActions.setGeoJSONDrawnFeatures(geoJSONString); + onDownloadDrawnLayer = () => { + let zip = this.createZipFileFromCustomDrawnFeature(); + const content = zip.generate({compression: 'STORE'}); + location.href = 'data:application/zip;base64,' + content; + }; - // (optional) set names for feature types and zipped folder - var options = { - folder: 'myshapes', - types: { - point: 'mypoints', - polygon: 'mypolygons', - line: 'mylines' - } - }; - const buffer = shpwrite.zip(JSON.parse(geoJSONString), options); - fetch(`${__PAVICS_GEOSERVER_API_PATH__}/test/datastores/test/file.shp`, { // Your POST endpoint - method: 'PUT', - headers: { - "Content-Type": "application/zip" - }, - body: buffer // This is your file object - }).then( - response => response.json() // if the response is a JSON object - ).then( - success => alert(success) // Handle the success response object - ).catch( - error => alert(error) // Handle the error response object - ); + onUploadDrawnLayer = () => { + // Push to geoserver (Working) + let zip = this.createZipFileFromCustomDrawnFeature(); + const content = zip.generate({type:"blob"}); + this.props.layerCustomFeatureActions.uploadZipShapeFile( + 'CUSTOM_SHAPEFILES', + 'CUSTOM_SHAPEFILES_DS', + content + ); }; onHandleTextChanged = field => event => { @@ -88,79 +135,171 @@ class WidgetDrawFeatures extends React.Component { }; onUploadFromDisk = event => { + const workspace = "CUSTOM_SHAPEFILES"; + const datastore = 'CUSTOM_SHAPEFILES_DS'; // ' USER_SHAPEFILES'; + var blobData = new Blob([this.state.file], {type: 'application/zip'}); + this.props.layerCustomFeatureActions.uploadZipShapeFile(workspace, datastore, blobData); + }; + handleFileSelect = (evt) => { + if (window.File && window.FileReader && window.FileList && window.Blob) { + // Great success! All the File APIs are supported. + } else { + alert('The File APIs are not fully supported in this browser.'); + } + var files = evt.target.files; + // Only a single file actually allowed + var file = files[0]; + this.setState({ + file: file, + fileName: file.name.trim(), + fileType: file.type, + fileSize: file.size, + fileLastModified: file.lastModifiedDate ? file.lastModifiedDate.toLocaleDateString() : 'n/a' + }); }; - render () { - const { currentDrawingTool, currentSelectedDrawnFeatureProperties, drawnCustomFeatures } = this.props.layerCustomFeature; - const { name, description } = this.state; + render() { + const {currentDrawingTool, currentSelectedDrawnFeatureProperties, drawnCustomFeatures} = this.props.layerCustomFeature; + const {name, description} = this.state; return ( -
- - Draw custom regions - - - Drawing tool - - - {/*TODO: Add layer metadata fields*/} - Drawn regions total: {drawnCustomFeatures.length} - - - { - // Setting null afterward in the reducer somehow doesn't work - (currentSelectedDrawnFeatureProperties && currentSelectedDrawnFeatureProperties.name) ? - - - - Selected custom region - - - + + this.setState({tabValue: value})}> + } + label="Draw custom regions"/> + } + label="Upload Shapefile"/> + + + {this.state.tabValue === 0 && +
+ + Draw custom regions + + + Drawing tool + + + {/*TODO: Add layer metadata fields*/} + Drawn regions total: {drawnCustomFeatures.length} + + + + { + // Setting null afterward in the reducer somehow doesn't work + (currentSelectedDrawnFeatureProperties && currentSelectedDrawnFeatureProperties.name) ? + + + + Selected custom region + + - : + : + } +
+ } + {this.state.tabValue === 1 && +
+ + This feature allow you to upload a shapefile from your local drive to the remote server. Read ESRI Shapefile Technical Description for more details. + + + + {(this.state.fileName.length) ? - - - Upload a geopackage - + + + + + } + title={this.state.fileName} + subheader={`Modified on: ${this.state.fileLastModified}, Size: ${this.state.fileSize}B`}/> + + {/* + Workspace (TODO) + + */} + - + : null + } +
} -
- ); + + ) } } diff --git a/src/redux/modules/LayerCustomFeature.js b/src/redux/modules/LayerCustomFeature.js index 0fa3031..cec1229 100644 --- a/src/redux/modules/LayerCustomFeature.js +++ b/src/redux/modules/LayerCustomFeature.js @@ -9,8 +9,44 @@ export const constants = { SET_CURRENT_SELECTED_DRAWN_FEATURE: 'DRAW_FEATURE_SET_CURRENT_SELECTED_DRAWN_FEATURE', SET_GEO_JSON_DRAWN_FEATURE: 'DRAW_FEATURE_SET_GEO_JSON_DRAWN_FEATURE', SET_DRAWN_CUSTOM_FEATURES: 'DRAW_FEATURE_SET_DRAWN_CUSTOM_FEATURES', + UPLOAD_SHAPEFILE_REQUEST: 'DRAW_FEATURE_SET_DRAWN_CUSTOM_FEATURES.UPLOAD_SHAPEFILE_REQUEST', + UPLOAD_SHAPEFILE_FAILURE: 'DRAW_FEATURE_SET_DRAWN_CUSTOM_FEATURES.UPLOAD_SHAPEFILE_FAILURE', + UPLOAD_SHAPEFILE_SUCCESS: 'DRAW_FEATURE_SET_DRAWN_CUSTOM_FEATURES.UPLOAD_SHAPEFILE_SUCCESS', }; +function requestUploadShapefile () { + return { + type: constants.UPLOAD_SHAPEFILE_REQUEST, + uploadedShapefile: { + requestedAt: Date.now(), + isFetching: true, + response: '' + } + }; +} +export function receiveUploadShapefileFailure (error) { + return { + type: constants.UPLOAD_SHAPEFILE_FAILURE, + uploadedShapefile: { + receivedAt: Date.now(), + isFetching: false, + response: '', + error: error + } + }; +} +export function receiveUploadShapefileSuccess (response) { + return { + type: constants.UPLOAD_SHAPEFILE_SUCCESS, + uploadedShapefile: { + receivedAt: Date.now(), + isFetching: false, + response: response, + error: null + } + }; +} + // Action Creators export const actions = { setCurrentDrawingTool: function (tool) { @@ -36,6 +72,32 @@ export const actions = { type: constants.SET_GEO_JSON_DRAWN_FEATURE, geoJSONDrawnFeature: featuresString }; + }, + uploadZipShapeFile: function (workspace, datastore, blobData){ + return function (dispatch, getState) { + dispatch(requestUploadShapefile()); + const url = `${__PAVICS_GEOSERVER_API_PATH__}/workspaces/${workspace}/datastore/${datastore}/file.shp`; + let headers = new Headers(); + headers.append('Content-Type', 'application/zip'); + headers.append('Content-Length', blobData.size); + headers.append('Accept', 'application/zip') + + fetch(url, { + method: 'PUT', + headers: headers, + body: blobData + }).then(function (response) { + if(response.ok) { + receiveUploadShapefileSuccess(response.statusText) + } else { + receiveUploadShapefileFailure(response) + } + console.log(result.statusText) + }) + .catch(function (error) { + receiveUploadShapefileFailure(error) + }); + }; } }; From 17d1f9857ab55eb01c3143c78e5355c692ad1086 Mon Sep 17 00:00:00 2001 From: Renaud009 Date: Wed, 24 Oct 2018 14:36:12 +0100 Subject: [PATCH 03/15] Working version with notification messages --- package-lock.json | 18 +- package.json | 2 +- src/components/SpeedDialMenu/SpeedDialMenu.js | 2 +- src/components/Visualize/Visualize.js | 8 +- .../WidgetDrawFeatures/WidgetDrawFeatures.js | 286 ++++++++++-------- .../WidgetLayerSwitcher.js | 93 +++--- src/redux/modules/LayerCustomFeature.js | 21 +- src/redux/modules/Widgets.js | 4 +- 8 files changed, 250 insertions(+), 184 deletions(-) diff --git a/package-lock.json b/package-lock.json index 608e908..3a444f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -146,11 +146,23 @@ } }, "@material-ui/icons": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-1.1.0.tgz", - "integrity": "sha512-Z4Xo/EYXuVqCIOjLw7AeBJPtJZsgy9dMAdqu6uYr7gxAefFA8L/QukLv/XE5ByxKYvRhzFG/AjA2OKXwKqfXBQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-1.1.1.tgz", + "integrity": "sha512-d7I2P1Td4S/1zMAYCIrVQVf+6NUZC5fcIuo0wTrKe/mKxYo9eQ+83lPesI9aBAh+ZTQTjPTqoIvm0WD5e+0uKQ==", "requires": { + "@babel/runtime": "7.0.0-beta.42", "recompose": "0.26.0" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.0.0-beta.42", + "resolved": "http://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0-beta.42.tgz", + "integrity": "sha512-iOGRzUoONLOtmCvjUsZv3mZzgCT6ljHQY5fr1qG1QIiJQwtM7zbPWGGpa3QWETq+UqwWyJnoi5XZDZRwZDFciQ==", + "requires": { + "core-js": "2.5.6", + "regenerator-runtime": "0.11.1" + } + } } }, "@material-ui/lab": { diff --git a/package.json b/package.json index 246f9dd..b882dc8 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "private": true, "dependencies": { "@material-ui/core": "^1.2.1", - "@material-ui/icons": "^1.1.0", + "@material-ui/icons": "^1.1.1", "@material-ui/lab": "^1.0.0-alpha.5", "ajv": "^5.2.0", "babel-cli": "^6.5.1", diff --git a/src/components/SpeedDialMenu/SpeedDialMenu.js b/src/components/SpeedDialMenu/SpeedDialMenu.js index 23325bb..e747660 100644 --- a/src/components/SpeedDialMenu/SpeedDialMenu.js +++ b/src/components/SpeedDialMenu/SpeedDialMenu.js @@ -12,7 +12,7 @@ import ChartIcon from '@material-ui/icons/Timeline'; import LayersIcon from '@material-ui/icons/Layers'; import MapControlsIcon from '@material-ui/icons/MyLocation'; import InfoIcon from '@material-ui/icons/Description'; -import DrawIcon from '@material-ui/icons/Edit' +import DrawIcon from '@material-ui/icons/FormatShapes' const styles = theme => { // console.log(theme) diff --git a/src/components/Visualize/Visualize.js b/src/components/Visualize/Visualize.js index e4f9146..88e5605 100644 --- a/src/components/Visualize/Visualize.js +++ b/src/components/Visualize/Visualize.js @@ -9,7 +9,7 @@ import LayersIcon from '@material-ui/icons/Layers'; import MapControlsIcon from '@material-ui/icons/MyLocation'; import InfoIcon from '@material-ui/icons/Description'; import ChartIcon from '@material-ui/icons/Timeline'; -import DrawIcon from '@material-ui/icons/Edit'; +import DrawIcon from '@material-ui/icons/FormatShapes'; import VisualizeWidget from './../VisualizeWidget'; import BigColorPaletteContainer from './../../containers/BigColorPalette'; import WidgetDrawFeaturesContainer from './../../containers/WidgetDrawFeatures'; @@ -59,7 +59,7 @@ const styles = { bottom: 0, textAlign: 'left', opacity: OPACITY, - height: '436px' + height: '400px' }, chart: { opacity: OPACITY, @@ -74,8 +74,8 @@ const styles = { opacity: OPACITY }, customRegions: { - height: '500px', - overflow: 'auto', + height: '400px', + // overflow: 'auto', width: '400px', opacity: OPACITY } diff --git a/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js b/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js index 38d1775..4a06c5c 100644 --- a/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js +++ b/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js @@ -12,22 +12,31 @@ import TextField from '@material-ui/core/TextField'; import Typography from '@material-ui/core/Typography'; import Tab from '@material-ui/core/Tab'; import Tabs from '@material-ui/core/Tabs'; -import DrawIcon from '@material-ui/icons/Edit'; +import DrawIcon from '@material-ui/icons/FormatShapes'; import FileUpload from '@material-ui/icons/FileUpload'; import AppBar from '@material-ui/core/AppBar'; import Card from '@material-ui/core/Card'; import CardHeader from '@material-ui/core/CardHeader'; import CardContent from '@material-ui/core/CardContent'; +import Paper from '@material-ui/core/Paper'; import Avatar from '@material-ui/core/Avatar'; import FolderIcon from '@material-ui/icons/Folder'; import {GeoJSON} from 'ol/format'; import shpwrite from 'shp-write'; -import prj from 'shp-write/src/prj'; import geojson from 'shp-write/src/geojson'; import JSZip from 'jszip'; +// http://epsg.io/3857.geoserver +const PROJ_3857 = '3857=PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],PROJECTION["Mercator_1SP"],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["X",EAST],AXIS["Y",NORTH],EXTENSION["PROJ4","+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"],AUTHORITY["EPSG","3857"]' + const styles = theme => ({ - root: {} + form: { + height: '100%', + overflowY: 'auto' + }, + container: { + height: '350px', + } }); class WidgetDrawFeatures extends React.Component { @@ -39,8 +48,11 @@ class WidgetDrawFeatures extends React.Component { constructor(props) { super(props); this.state = { + tabValue: 0, name: '', description: '', + regionIdentifier: '', + featureIdentifier: '', fileName: '', fileType: '', fileSize: '', @@ -49,19 +61,22 @@ class WidgetDrawFeatures extends React.Component { } componentWillReceiveProps(nextProps) { - const {currentSelectedDrawnFeatureProperties} = nextProps.layerCustomFeature; + /*const {currentSelectedDrawnFeatureProperties} = nextProps.layerCustomFeature; if (currentSelectedDrawnFeatureProperties && currentSelectedDrawnFeatureProperties !== this.props.layerCustomFeature.currentSelectedDrawnFeatureProperties) { this.setState({ name: currentSelectedDrawnFeatureProperties.name, description: currentSelectedDrawnFeatureProperties.description }) - } + }*/ } createZipFileFromCustomDrawnFeature() { const geoJSONWriter = new GeoJSON(); + // FIXME: drawnCustomFeatures is way too large to be in redux + console.log(this.props.layerCustomFeature.drawnCustomFeatures); const geoJSONString = geoJSONWriter.writeFeatures(this.props.layerCustomFeature.drawnCustomFeatures); let geoJSON = JSON.parse(geoJSONString); + // Clear features or get a corrupted file and upload won't actually work for now geoJSON.features.map(feature => feature.properties = {}); this.props.layerCustomFeatureActions.setGeoJSONDrawnFeatures(geoJSONString); @@ -82,6 +97,8 @@ class WidgetDrawFeatures extends React.Component { const polygons = geojson.polygon(geoJSON); const types = [points, lines, polygons]; console.log(types.length); + // TODO: MultiPolygon checkbox, when unchecked push one shapefile for each feature + // EXPLORE: POLYGON + LINE => Valid Multipolygon ? types.forEach((layer) => { if (layer.geometries.length && layer.geometries[0].length) { shpwrite.write( @@ -92,11 +109,11 @@ class WidgetDrawFeatures extends React.Component { // geometries layer.geometries, (err, files) => { - const fileName = 'CUSTOM_' + new Date().getTime(); + const fileName = (this.state.regionIdentifier)? this.state.regionIdentifier: 'CUSTOM_' + new Date().getTime(); zip.file(fileName + '.shp', files.shp.buffer, {binary: true}); zip.file(fileName + '.shx', files.shx.buffer, {binary: true}); zip.file(fileName + '.dbf', files.dbf.buffer, {binary: true}); - zip.file(fileName + '.prj', prj); + zip.file(fileName + '.prj', PROJ_3857); }); } }); @@ -121,24 +138,31 @@ class WidgetDrawFeatures extends React.Component { // Push to geoserver (Working) let zip = this.createZipFileFromCustomDrawnFeature(); const content = zip.generate({type:"blob"}); - this.props.layerCustomFeatureActions.uploadZipShapeFile( + this.props.layerCustomFeatureActions.uploadZipShapefile( 'CUSTOM_SHAPEFILES', 'CUSTOM_SHAPEFILES_DS', content ); }; - onHandleTextChanged = field => event => { + onHandleTextChangedOld = field => event => { let cpy = Object.assign({}, this.props.layerCustomFeature.currentSelectedDrawnFeatureProperties); cpy[field] = event.target.value; this.props.layerCustomFeatureActions.setCurrentSelectedDrawnFeature(cpy); + // Then retrieve values for re-rendering in componentWillReceiveProps -> setState() + }; + + onHandleTextChanged = field => event => { + let newState = {}; + newState[field] = event.target.value; + this.setState(newState); }; onUploadFromDisk = event => { const workspace = "CUSTOM_SHAPEFILES"; const datastore = 'CUSTOM_SHAPEFILES_DS'; // ' USER_SHAPEFILES'; var blobData = new Blob([this.state.file], {type: 'application/zip'}); - this.props.layerCustomFeatureActions.uploadZipShapeFile(workspace, datastore, blobData); + this.props.layerCustomFeatureActions.uploadZipShapefile(workspace, datastore, blobData); }; handleFileSelect = (evt) => { @@ -161,7 +185,8 @@ class WidgetDrawFeatures extends React.Component { render() { const {currentDrawingTool, currentSelectedDrawnFeatureProperties, drawnCustomFeatures} = this.props.layerCustomFeature; - const {name, description} = this.state; + // const {name, description} = this.state; + const {featureIdentifier, regionIdentifier} = this.state; return ( @@ -175,129 +200,142 @@ class WidgetDrawFeatures extends React.Component { } - label="Draw custom regions"/> + label="Draw custom region"/> } label="Upload Shapefile"/> - {this.state.tabValue === 0 && -
- - Draw custom regions - - - Drawing tool - - - {/*TODO: Add layer metadata fields*/} - Drawn regions total: {drawnCustomFeatures.length} - - - - { - // Setting null afterward in the reducer somehow doesn't work - (currentSelectedDrawnFeatureProperties && currentSelectedDrawnFeatureProperties.name) ? - - - - Selected custom region - - +
+ {this.state.tabValue === 0 && +
+ + Drawing tool + + + {/*TODO: Add layer metadata fields*/} + + + Drawn regions total: {drawnCustomFeatures.length} + + + + { + // Following code helps defining a name and a description to every drawn feature + // It's deprecated since the library only insert a single MultiPolygon containing all polygons, so end-up with one feature only + // Setting null afterward in the reducer somehow doesn't work + /*(currentSelectedDrawnFeatureProperties && currentSelectedDrawnFeatureProperties.name) ? + + + + Selected custom region + + - : + value={currentSelectedDrawnFeatureProperties.description} + onChange={this.onHandleTextChangedOld('description')} + label="Region's description"/> + : null*/ + } +
} -
- } - {this.state.tabValue === 1 && -
- - This feature allow you to upload a shapefile from your local drive to the remote server. Read ESRI Shapefile Technical Description for more details. - - - - {(this.state.fileName.length) ? - - - - - - } - title={this.state.fileName} - subheader={`Modified on: ${this.state.fileLastModified}, Size: ${this.state.fileSize}B`}/> - - {/* - Workspace (TODO) - - */} - - - : null + + {(this.state.fileName.length) ? + + + + + + } + title={this.state.fileName} + subheader={`Modified on: ${this.state.fileLastModified}, Size: ${this.state.fileSize}B`}/> + + {/* + Workspace (TODO) + + */} + + + : null + } +
} -
- } + +
) } diff --git a/src/components/WidgetLayerSwitcher/WidgetLayerSwitcher.js b/src/components/WidgetLayerSwitcher/WidgetLayerSwitcher.js index c393b41..e7b8148 100644 --- a/src/components/WidgetLayerSwitcher/WidgetLayerSwitcher.js +++ b/src/components/WidgetLayerSwitcher/WidgetLayerSwitcher.js @@ -32,8 +32,19 @@ const AVAILABLE_COLOR_PALETTES = [ 'default' ]; const styles = { - list: { - height: '300px', + container: { + // height: '350px' + }, + regionList: { + height: '292px', + overflowY: 'auto' + }, + datasetList: { + height: '256px', + overflowY: 'auto' + }, + baseMapList: { + height: '350px', overflowY: 'auto' }, topBar: { @@ -157,7 +168,7 @@ export default class WidgetLayerSwitcher extends React.Component { makeFeatureLayersList () { return ( - +
- + { Object.keys(this.state.filteredLayers).map((workspaceName, j) => { const workspaceLayers = this.state.filteredLayers[workspaceName]; return ( - +
@@ -200,51 +211,53 @@ export default class WidgetLayerSwitcher extends React.Component { ) } - +
); }) }
- +
); } makeBaseMapsList () { return ( - - 2D EPSG:4326 - { - this.props.layerBasemap.baseMaps.map((map, i) => - - - } label={map} /> - - - ) - } - 3D - - - } label="Cesium (prototype)" /> - - - +
+ + 2D EPSG:4326 + { + this.props.layerBasemap.baseMaps.map((map, i) => + + + } label={map} /> + + + ) + } + 3D + + + } label="Cesium (prototype)" /> + + + +
); } makeDatasetsList () { return ( - +
@@ -261,7 +274,7 @@ export default class WidgetLayerSwitcher extends React.Component { {this.makeSlider()} - + { this.props.layerDataset.currentVisualizedDatasets.map((dataset, i) => { let secondaryText = ''; @@ -295,7 +308,7 @@ export default class WidgetLayerSwitcher extends React.Component { }) } - +
); } @@ -352,7 +365,7 @@ export default class WidgetLayerSwitcher extends React.Component { render () { return ( - +
} - +
); } } diff --git a/src/redux/modules/LayerCustomFeature.js b/src/redux/modules/LayerCustomFeature.js index cec1229..241dcfa 100644 --- a/src/redux/modules/LayerCustomFeature.js +++ b/src/redux/modules/LayerCustomFeature.js @@ -1,7 +1,6 @@ import myHttp from '../../util/http'; -import { GeoJSON } from 'ol/format'; +import {VISUALIZE_DRAW_MODES} from './../../constants'; import { NotificationManager } from 'react-notifications'; -import { VISUALIZE_DRAW_MODES } from './../../constants'; // Constants export const constants = { @@ -73,28 +72,32 @@ export const actions = { geoJSONDrawnFeature: featuresString }; }, - uploadZipShapeFile: function (workspace, datastore, blobData){ - return function (dispatch, getState) { + uploadZipShapefile: function (workspace, datastore, blobData){ + return function (dispatch) { dispatch(requestUploadShapefile()); - const url = `${__PAVICS_GEOSERVER_API_PATH__}/workspaces/${workspace}/datastore/${datastore}/file.shp`; + const url = `${__PAVICS_GEOSERVER_API_PATH__}/workspaces/${workspace}/datastores/${datastore}/file.shp`; let headers = new Headers(); headers.append('Content-Type', 'application/zip'); headers.append('Content-Length', blobData.size); - headers.append('Accept', 'application/zip') + headers.append('Accept', 'application/zip'); fetch(url, { method: 'PUT', headers: headers, - body: blobData + body: blobData, + credentials: 'include' }).then(function (response) { if(response.ok) { + NotificationManager.success('Shapefile was uploaded on the server with success.', 'Success', 10000); receiveUploadShapefileSuccess(response.statusText) + // TODO: Select new uploaded region automatically? } else { + NotificationManager.error('An error occurred while uploading the shapefile on the server.', 'Error', 10000); receiveUploadShapefileFailure(response) } - console.log(result.statusText) }) .catch(function (error) { + NotificationManager.error('An error occurred while uploading the shapefile on the server.', 'Error', 10000); receiveUploadShapefileFailure(error) }); }; @@ -120,7 +123,7 @@ const HANDLERS = { // Initial State export const initialState = { drawnCustomFeatures: [], - currentDrawingTool: '', // Disabled by default + currentDrawingTool: VISUALIZE_DRAW_MODES.BBOX.value, // Enabled BBOX by default currentSelectedDrawnFeatureProperties: null, geoJSONDrawnFeature: '' }; diff --git a/src/redux/modules/Widgets.js b/src/redux/modules/Widgets.js index 80f5a0b..f70554e 100644 --- a/src/redux/modules/Widgets.js +++ b/src/redux/modules/Widgets.js @@ -34,10 +34,10 @@ const HANDLERS = { // Initial State export const initialState = { chart: false, - customRegions: false, + customRegions: true, info: false, mapControls: true, - timeSlider: true, + timeSlider: false, layerSwitcher: true }; From 854b0f956f71a10ae4ed5317c654e219e3963b6f Mon Sep 17 00:00:00 2001 From: Renaud009 Date: Wed, 24 Oct 2018 17:04:53 +0100 Subject: [PATCH 04/15] Commented Cesium and dependencies --- .../OLBasemapRenderer/OLBasemapRenderer.js | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/containers/OLBasemapRenderer/OLBasemapRenderer.js b/src/containers/OLBasemapRenderer/OLBasemapRenderer.js index d3e5513..534d9c3 100644 --- a/src/containers/OLBasemapRenderer/OLBasemapRenderer.js +++ b/src/containers/OLBasemapRenderer/OLBasemapRenderer.js @@ -11,12 +11,15 @@ import OSM from 'ol/source/OSM'; // TODO: Cesium shouldn't be a basemap option eventually, should be switch 2d/3d with both same basemaps as options // TODO: Couple more basemap options could be interesting and free to implement (OSM Positron, OSM Landscape, OSM B&W, OSM Mapnik) // TODO: 3D Cesium visualisation also mean that multiple projection options aren't urgent anymore (https://github.com/Ouranosinc/PAVICS-frontend/issues/110) -import Cesium from 'cesium/Cesium'; +// COMMENTED CESIUM +/*import Cesium from 'cesium/Cesium'; window['Cesium'] = Cesium; // expose Cesium to the OL-Cesium library require('cesium/Widgets/widgets.css'); import OLCesium from 'ol-cesium'; -const G_BING_API_KEY = 'AtXX65CBBfZXBxm6oMyf_5idMAMI7W6a5GuZ5acVcrYi6lCQayiiBz7_aMHB7JR7'; Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI4NzJmNzQ5YS1iY2JlLTQwOGYtODlhNS04Yzc2YzRmOWY5YWMiLCJpZCI6Mzc0MCwic2NvcGVzIjpbImFzbCIsImFzciIsImdjIl0sImlhdCI6MTUzODY2NDcwNH0.02vOjG7j1kh75VjgRWn6fUq4ulyPK2IZbFhdyx0SCcE'; +*/ + +const G_BING_API_KEY = 'AtXX65CBBfZXBxm6oMyf_5idMAMI7W6a5GuZ5acVcrYi6lCQayiiBz7_aMHB7JR7'; export class OLBasemapRenderer extends React.Component { static propTypes = { @@ -30,7 +33,8 @@ export class OLBasemapRenderer extends React.Component { super(props); this.source = null; this.layer = null; - this.ol3d = null; + // COMMENTED CESIUM + /*this.ol3d = null;*/ } componentWillReceiveProps (nextProps) { @@ -46,8 +50,9 @@ export class OLBasemapRenderer extends React.Component { init(map) { this.source = new OSM(); - this.ol3d = new OLCesium({map: map}); - this.ol3d.setEnabled(false); + // COMMENTED CESIUM + /*this.ol3d = new OLCesium({map: map}); + this.ol3d.setEnabled(false);*/ } resetBasemap(map, layerBasemap) { @@ -56,12 +61,14 @@ export class OLBasemapRenderer extends React.Component { } if (layerBasemap.selectedBasemap === 'Cesium') { // TODO: Cesium shouldn't be a basemap option eventually - this.layer = this.addCesiumTileLayer(map, layerBasemap.selectedBasemap); + // COMMENTED CESIUM + /*this.layer = this.addCesiumTileLayer(map, layerBasemap.selectedBasemap); let scene = this.ol3d.getCesiumScene(); scene.terrainProvider = Cesium.createWorldTerrain(); - this.ol3d.setEnabled(true); + this.ol3d.setEnabled(true);*/ } else { - this.ol3d.setEnabled(false); + // COMMENTED CESIUM + // this.ol3d.setEnabled(false); this.layer = this.addBingLayer(map, layerBasemap.selectedBasemap, layerBasemap.selectedBasemap); } } From 329c8c83e77ce3a7773ebdf3e630530144a0a775 Mon Sep 17 00:00:00 2001 From: Renaud009 Date: Wed, 24 Oct 2018 17:05:55 +0100 Subject: [PATCH 05/15] Moved most logic code inside redux module --- .../WidgetDrawFeatures/WidgetDrawFeatures.js | 95 ++-------- .../OLDrawFeatures/OLDrawFeatures.js | 36 +++- src/redux/modules/LayerCustomFeature.js | 172 +++++++++++++----- 3 files changed, 169 insertions(+), 134 deletions(-) diff --git a/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js b/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js index 4a06c5c..4099e68 100644 --- a/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js +++ b/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js @@ -21,13 +21,6 @@ import CardContent from '@material-ui/core/CardContent'; import Paper from '@material-ui/core/Paper'; import Avatar from '@material-ui/core/Avatar'; import FolderIcon from '@material-ui/icons/Folder'; -import {GeoJSON} from 'ol/format'; -import shpwrite from 'shp-write'; -import geojson from 'shp-write/src/geojson'; -import JSZip from 'jszip'; - -// http://epsg.io/3857.geoserver -const PROJ_3857 = '3857=PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],PROJECTION["Mercator_1SP"],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["X",EAST],AXIS["Y",NORTH],EXTENSION["PROJ4","+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"],AUTHORITY["EPSG","3857"]' const styles = theme => ({ form: { @@ -45,19 +38,20 @@ class WidgetDrawFeatures extends React.Component { layerCustomFeatureActions: PropTypes.object.isRequired }; + state = { + tabValue: 0, + name: '', + description: '', + regionIdentifier: '', + featureIdentifier: '', + fileName: '', + fileType: '', + fileSize: '', + fileLastModified: 'N/A', + }; + constructor(props) { super(props); - this.state = { - tabValue: 0, - name: '', - description: '', - regionIdentifier: '', - featureIdentifier: '', - fileName: '', - fileType: '', - fileSize: '', - fileLastModified: 'N/A', - }; } componentWillReceiveProps(nextProps) { @@ -70,79 +64,20 @@ class WidgetDrawFeatures extends React.Component { }*/ } - createZipFileFromCustomDrawnFeature() { - const geoJSONWriter = new GeoJSON(); - // FIXME: drawnCustomFeatures is way too large to be in redux - console.log(this.props.layerCustomFeature.drawnCustomFeatures); - const geoJSONString = geoJSONWriter.writeFeatures(this.props.layerCustomFeature.drawnCustomFeatures); - let geoJSON = JSON.parse(geoJSONString); - // Clear features or get a corrupted file and upload won't actually work for now - geoJSON.features.map(feature => feature.properties = {}); - this.props.layerCustomFeatureActions.setGeoJSONDrawnFeatures(geoJSONString); - - // DEPRECATED, zip contains a folder at root - /*var options = { - folder: 'USER_SHAPEFILES', - types: { - polygon: 'CUSTOM_' + new Date().getTime(), - } - }; - const buffer = shpwrite.zip(geoJSON, options); - shpwrite.download(geoJSON, options);*/ - - // FIXME: FOLLOWING PROCEDURE CREATES ONE MULTIPOLYGON INSTEAD OF MANY POLYGONS - let zip = new JSZip(); - const points = geojson.point(geoJSON); - const lines = geojson.line(geoJSON); - const polygons = geojson.polygon(geoJSON); - const types = [points, lines, polygons]; - console.log(types.length); - // TODO: MultiPolygon checkbox, when unchecked push one shapefile for each feature - // EXPLORE: POLYGON + LINE => Valid Multipolygon ? - types.forEach((layer) => { - if (layer.geometries.length && layer.geometries[0].length) { - shpwrite.write( - // field definitions - layer.properties, - // geometry type - layer.type, - // geometries - layer.geometries, - (err, files) => { - const fileName = (this.state.regionIdentifier)? this.state.regionIdentifier: 'CUSTOM_' + new Date().getTime(); - zip.file(fileName + '.shp', files.shp.buffer, {binary: true}); - zip.file(fileName + '.shx', files.shx.buffer, {binary: true}); - zip.file(fileName + '.dbf', files.dbf.buffer, {binary: true}); - zip.file(fileName + '.prj', PROJ_3857); - }); - } - }); - return zip; - } - onSelectedDrawingTool = (event) => { this.props.layerCustomFeatureActions.setCurrentDrawingTool(event.target.value); }; onResetDrawingLayer = () => { - this.props.layerCustomFeatureActions.setDrawnCustomFeatures([]); + this.props.layerCustomFeatureActions.resetGeoJSONDrawnFeatures(); }; onDownloadDrawnLayer = () => { - let zip = this.createZipFileFromCustomDrawnFeature(); - const content = zip.generate({compression: 'STORE'}); - location.href = 'data:application/zip;base64,' + content; + this.props.layerCustomFeatureActions.createDownloadZipShapefile(this.state.regionIdentifier); }; onUploadDrawnLayer = () => { - // Push to geoserver (Working) - let zip = this.createZipFileFromCustomDrawnFeature(); - const content = zip.generate({type:"blob"}); - this.props.layerCustomFeatureActions.uploadZipShapefile( - 'CUSTOM_SHAPEFILES', - 'CUSTOM_SHAPEFILES_DS', - content - ); + this.props.layerCustomFeatureActions.createUploadZipShapefile(this.state.regionIdentifier); }; onHandleTextChangedOld = field => event => { diff --git a/src/containers/OLDrawFeatures/OLDrawFeatures.js b/src/containers/OLDrawFeatures/OLDrawFeatures.js index 1907e5e..d0a1191 100644 --- a/src/containers/OLDrawFeatures/OLDrawFeatures.js +++ b/src/containers/OLDrawFeatures/OLDrawFeatures.js @@ -34,6 +34,10 @@ class OLDrawFeatures extends React.Component { map: PropTypes.instanceOf(Map) }; + state = { + drawnCustomFeatures: [] + }; + constructor(props) { super(props); this.layer = null; @@ -57,8 +61,8 @@ class OLDrawFeatures extends React.Component { if (nextProps.map !== this.props.map) { this.init(nextProps); // Once, when map has been initialised this.initDraw(nextProps); - }else if(layerCustomFeature.drawnCustomFeatures !== this.props.layerCustomFeature.drawnCustomFeatures){ - if (layerCustomFeature.drawnCustomFeatures.length === 0){ + }else if(this.props.layerCustomFeature.geoJSONDrawnFeatures !== layerCustomFeature.geoJSONDrawnFeatures){ + if (layerCustomFeature.geoJSONDrawnFeatures.features.length === 0){ // Triggered when Reset button is clicked in WidgetDrawFeatures this.select.getFeatures().clear(); this.source.clear(); @@ -243,21 +247,33 @@ class OLDrawFeatures extends React.Component { // Listener on drawend this.draw.on('drawend', (e) => { let feature = e.feature; - feature.setProperties({ - name: `feature_${layerCustomFeature.drawnCustomFeatures.length + 1}`, - description: '', - type: layerCustomFeature.currentDrawingTool - }); - map.removeInteraction(this.draw); - map.removeInteraction(this.snap); + console.log( 'drawended'); + // Clear features or get a corrupted file and upload won't actually work for now + // feature.setProperties({ + // name: `feature_${this.state.drawnCustomFeatures.length + 1}`, + // description: '', + // type: layerCustomFeature.currentDrawingTool + // }); + // map.removeInteraction(this.draw); + // map.removeInteraction(this.snap); // Only one selected feature at a time this.select.getFeatures().clear(); this.select.getFeatures().push(feature); + // Not useful anymore, can't edit properties in Customize Regions widget this.props.layerCustomFeatureActions.setCurrentSelectedDrawnFeature(feature.getProperties()); // The action isn't super useful ATM, essentially used to notify when the array becomes empty - this.props.layerCustomFeatureActions.setDrawnCustomFeatures(layerCustomFeature.drawnCustomFeatures.concat([feature])); + // Objects are way to large to be in Redux without performance impact + // this.props.layerCustomFeatureActions.setDrawnCustomFeatures(this.state.drawnCustomFeatures.concat([feature])); + const drawnCustomFeatures = this.state.drawnCustomFeatures.concat([feature]); + this.setState({ + drawnCustomFeatures: drawnCustomFeatures + }); + + const geoJSONWriter = new GeoJSON(); + const geoJSONString = geoJSONWriter.writeFeatures(drawnCustomFeatures); + this.props.layerCustomFeatureActions.setGeoJSONDrawnFeatures(JSON.parse(geoJSONString)); }); } } diff --git a/src/redux/modules/LayerCustomFeature.js b/src/redux/modules/LayerCustomFeature.js index 241dcfa..dd86a17 100644 --- a/src/redux/modules/LayerCustomFeature.js +++ b/src/redux/modules/LayerCustomFeature.js @@ -1,18 +1,120 @@ import myHttp from '../../util/http'; +import shpwrite from 'shp-write'; +import geojson from 'shp-write/src/geojson'; +import JSZip from 'jszip'; import {VISUALIZE_DRAW_MODES} from './../../constants'; import { NotificationManager } from 'react-notifications'; +// http://epsg.io/3857.geoserver +const PROJ_3857 = '3857=PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],PROJECTION["Mercator_1SP"],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["X",EAST],AXIS["Y",NORTH],EXTENSION["PROJ4","+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"],AUTHORITY["EPSG","3857"]' + // Constants export const constants = { - SET_CURRENT_DRAWING_TOOL: 'DRAW_FEATURE_SET_CURRENT_DRAWING_TOOL', - SET_CURRENT_SELECTED_DRAWN_FEATURE: 'DRAW_FEATURE_SET_CURRENT_SELECTED_DRAWN_FEATURE', - SET_GEO_JSON_DRAWN_FEATURE: 'DRAW_FEATURE_SET_GEO_JSON_DRAWN_FEATURE', - SET_DRAWN_CUSTOM_FEATURES: 'DRAW_FEATURE_SET_DRAWN_CUSTOM_FEATURES', - UPLOAD_SHAPEFILE_REQUEST: 'DRAW_FEATURE_SET_DRAWN_CUSTOM_FEATURES.UPLOAD_SHAPEFILE_REQUEST', - UPLOAD_SHAPEFILE_FAILURE: 'DRAW_FEATURE_SET_DRAWN_CUSTOM_FEATURES.UPLOAD_SHAPEFILE_FAILURE', - UPLOAD_SHAPEFILE_SUCCESS: 'DRAW_FEATURE_SET_DRAWN_CUSTOM_FEATURES.UPLOAD_SHAPEFILE_SUCCESS', + SET_CURRENT_DRAWING_TOOL: 'LAYER_CUSTOM_FEATURE.SET_CURRENT_DRAWING_TOOL', + SET_CURRENT_SELECTED_DRAWN_FEATURE: 'LAYER_CUSTOM_FEATURE.SET_CURRENT_SELECTED_DRAWN_FEATURE', + SET_GEO_JSON_DRAWN_FEATURES: 'LAYER_CUSTOM_FEATURE.SET_GEO_JSON_DRAWN_FEATURES', + SET_DRAWN_CUSTOM_FEATURES: 'LAYER_CUSTOM_FEATURE.SET_DRAWN_CUSTOM_FEATURES', + UPLOAD_SHAPEFILE_REQUEST: 'LAYER_CUSTOM_FEATURE.UPLOAD_SHAPEFILE_REQUEST', + UPLOAD_SHAPEFILE_FAILURE: 'LAYER_CUSTOM_FEATURE.UPLOAD_SHAPEFILE_FAILURE', + UPLOAD_SHAPEFILE_SUCCESS: 'LAYER_CUSTOM_FEATURE.UPLOAD_SHAPEFILE_SUCCESS', }; +function createZipFileFromFeature(feature, fileName) { + // Clear features properties or get a corrupted file and upload won't actually work for now + geoJSON.features.map(feature => feature.properties = {}); + this.props.layerCustomFeatureActions.setGeoJSONDrawnFeatures(geoJSONString); + + let zip = new JSZip(); + const points = geojson.point(geoJSON); + const lines = geojson.line(geoJSON); + const polygons = geojson.polygon(geoJSON); + const types = [points, lines, polygons]; + console.log(types.length); + // TODO: MultiPolygon checkbox, when unchecked push one shapefile for each feature + // EXPLORE: POLYGON + LINE => Valid Multipolygon ? + types.forEach((layer) => { + if (layer.geometries.length && layer.geometries[0].length) { + shpwrite.write( + // field definitions + layer.properties, + // geometry type + layer.type, + // geometries + layer.geometries, + (err, files) => { + fileName = fileName || 'CUSTOM_' + new Date().getTime(); + zip.file(fileName + '.shp', files.shp.buffer, {binary: true}); + zip.file(fileName + '.shx', files.shx.buffer, {binary: true}); + zip.file(fileName + '.dbf', files.dbf.buffer, {binary: true}); + zip.file(fileName + '.prj', PROJ_3857); + }); + } + }); + return zip; +} + +// DEPRECATED: this actually triggers one download event for each drawn feature +// Local shapefile can't contains multiple polygons as expected (shp-write limitation) +// So this functionnality should be available for every shapefile available on geoserver instead +function createDownloadZipShapefile (filename, workspace = 'CUSTOM_SHAPEFILES', datastore = 'CUSTOM_SHAPEFILES_DS') { + return function (dispatch, getState) { + const state = getState(); + const features = getState().layerCustomFeature.geoJSONDrawnFeatures; + features.forEach(feature => { + let zip = createZipFileFromFeature(feature, filename, workspace, datastore); + const content = zip.generate({compression: 'STORE'}); + location.href = 'data:application/zip;base64,' + content; + }); + }; +} + +function createUploadZipShapefile (filename, workspace = 'CUSTOM_SHAPEFILES', datastore = 'CUSTOM_SHAPEFILES_DS') { + return function (dispatch, getState) { + const state = getState(); + const features = getState().layerCustomFeature.geoJSONDrawnFeatures; + + // HTTP PUT will append shapefile feature by default if filename already exists + // Since shp-write won't allow to push multiple at once in the shapefile, we'll delegate this functionnaly to geoserver + features.forEach(feature => { + let zip = createZipFileFromFeature(feature, filename); + const content = zip.generate({type:"blob"}); + uploadZipShapefile(workspace, datastore, content); + + }); + }; +} + +// HTTP PUT will append shapefile feature by default if filename exists +function uploadZipShapefile (workspace, datastore, blobData){ + return function (dispatch) { + dispatch(requestUploadShapefile()); + const url = `${__PAVICS_GEOSERVER_API_PATH__}/workspaces/${workspace}/datastores/${datastore}/file.shp`; + let headers = new Headers(); + headers.append('Content-Type', 'application/zip'); + headers.append('Content-Length', blobData.size); + headers.append('Accept', 'application/zip'); + fetch(url, { + method: 'PUT', + headers: headers, + body: blobData, + credentials: 'include' + }).then(function (response) { + if(response.ok) { + NotificationManager.success('Shapefile was uploaded on the server with success.', 'Success', 10000); + receiveUploadShapefileSuccess(response.statusText) + // TODO: Select new uploaded region automatically? + } else { + NotificationManager.error('An error occurred while uploading the shapefile on the server.', 'Error', 10000); + receiveUploadShapefileFailure(response) + } + }) + .catch(function (error) { + NotificationManager.error('An error occurred while uploading the shapefile on the server.', 'Error', 10000); + receiveUploadShapefileFailure(error) + }); + }; +} + function requestUploadShapefile () { return { type: constants.UPLOAD_SHAPEFILE_REQUEST, @@ -23,7 +125,7 @@ function requestUploadShapefile () { } }; } -export function receiveUploadShapefileFailure (error) { +function receiveUploadShapefileFailure (error) { return { type: constants.UPLOAD_SHAPEFILE_FAILURE, uploadedShapefile: { @@ -34,7 +136,7 @@ export function receiveUploadShapefileFailure (error) { } }; } -export function receiveUploadShapefileSuccess (response) { +function receiveUploadShapefileSuccess (response) { return { type: constants.UPLOAD_SHAPEFILE_SUCCESS, uploadedShapefile: { @@ -66,42 +168,24 @@ export const actions = { drawnCustomFeatures: features }; }, - setGeoJSONDrawnFeatures: function (featuresString) { + setGeoJSONDrawnFeatures: function (geoJSONFeatures) { return { - type: constants.SET_GEO_JSON_DRAWN_FEATURE, - geoJSONDrawnFeature: featuresString + type: constants.SET_GEO_JSON_DRAWN_FEATURES, + geoJSONDrawnFeatures: geoJSONFeatures }; }, - uploadZipShapefile: function (workspace, datastore, blobData){ - return function (dispatch) { - dispatch(requestUploadShapefile()); - const url = `${__PAVICS_GEOSERVER_API_PATH__}/workspaces/${workspace}/datastores/${datastore}/file.shp`; - let headers = new Headers(); - headers.append('Content-Type', 'application/zip'); - headers.append('Content-Length', blobData.size); - headers.append('Accept', 'application/zip'); - - fetch(url, { - method: 'PUT', - headers: headers, - body: blobData, - credentials: 'include' - }).then(function (response) { - if(response.ok) { - NotificationManager.success('Shapefile was uploaded on the server with success.', 'Success', 10000); - receiveUploadShapefileSuccess(response.statusText) - // TODO: Select new uploaded region automatically? - } else { - NotificationManager.error('An error occurred while uploading the shapefile on the server.', 'Error', 10000); - receiveUploadShapefileFailure(response) - } - }) - .catch(function (error) { - NotificationManager.error('An error occurred while uploading the shapefile on the server.', 'Error', 10000); - receiveUploadShapefileFailure(error) - }); + resetGeoJSONDrawnFeatures: function () { + return { + type: constants.SET_GEO_JSON_DRAWN_FEATURES, + geoJSONDrawnFeatures: { + type: "FeatureCollection", + features: [] + } }; - } + }, + createUploadZipShapefile: createUploadZipShapefile, + createDownloadZipShapefile: createDownloadZipShapefile, + uploadZipShapefile: uploadZipShapefile }; // Reducer @@ -115,8 +199,8 @@ const HANDLERS = { [constants.SET_CURRENT_SELECTED_DRAWN_FEATURE]: (state, action) => { return ({...state, currentSelectedDrawnFeatureProperties: Object.assign({}, action.currentSelectedDrawnFeatureProperties)}); }, - [constants.SET_GEO_JSON_DRAWN_FEATURE]: (state, action) => { - return ({...state, geoJSONDrawnFeature: action.geoJSONDrawnFeature}); + [constants.SET_GEO_JSON_DRAWN_FEATURES]: (state, action) => { + return ({...state, geoJSONDrawnFeatures: action.geoJSONDrawnFeatures}); } }; @@ -125,7 +209,7 @@ export const initialState = { drawnCustomFeatures: [], currentDrawingTool: VISUALIZE_DRAW_MODES.BBOX.value, // Enabled BBOX by default currentSelectedDrawnFeatureProperties: null, - geoJSONDrawnFeature: '' + geoJSONDrawnFeatures: '' }; export default function (state = initialState, action) { From 67a955f6549ee539121a916784eaced81d72f98f Mon Sep 17 00:00:00 2001 From: Renaud009 Date: Wed, 24 Oct 2018 17:06:19 +0100 Subject: [PATCH 06/15] Refactored Redux action events --- src/redux/modules/LayerRegion.js | 20 ++++---- src/redux/modules/Monitor.js | 60 +++++++++++------------ src/redux/modules/Project.js | 2 +- src/redux/modules/Researcher.js | 82 -------------------------------- src/redux/modules/Section.js | 2 +- src/redux/modules/Session.js | 54 ++++++++++----------- src/redux/modules/Visualize.js | 22 ++++----- src/redux/modules/Widgets.js | 1 - src/redux/modules/Workflow.js | 78 +++++++++++++++--------------- src/store/reducers.js | 2 - 10 files changed, 119 insertions(+), 204 deletions(-) delete mode 100644 src/redux/modules/Researcher.js diff --git a/src/redux/modules/LayerRegion.js b/src/redux/modules/LayerRegion.js index 5056bbb..d548ee0 100644 --- a/src/redux/modules/LayerRegion.js +++ b/src/redux/modules/LayerRegion.js @@ -2,16 +2,16 @@ import myHttp from '../../util/http'; // Constants export const constants = { - SET_SELECTED_FEATURE_LAYER: 'Visualize.SET_SELECTED_FEATURE_LAYER', - RESET_SELECTED_REGIONS: 'REGION_RESET_SELECTED_REGIONS', - ADD_FEATURE_TO_SELECTED_REGIONS: 'REGION_ADD_FEATURE_TO_SELECTED_REGIONS', - REMOVE_FEATURE_FROM_SELECTED_REGIONS: 'REGION_REMOVE_FEATURE_FROM_SELECTED_REGIONS', - FETCH_WORKSPACES_REQUEST: 'Visualize.FETCH_WORKSPACES_REQUEST', - FETCH_WORKSPACES_FAILURE: 'Visualize.FETCH_WORKSPACES_FAILURE', - FETCH_WORKSPACES_SUCCESS: 'Visualize.FETCH_WORKSPACES_SUCCESS', - FETCH_WORKSPACES_LAYERS_REQUEST: 'Visualize.FETCH_WORKSPACES_LAYERS_REQUEST', - FETCH_WORKSPACES_LAYERS_FAILURE: 'Visualize.FETCH_WORKSPACES_LAYERS_FAILURE', - FETCH_WORKSPACES_LAYERS_SUCCESS: 'Visualize.FETCH_WORKSPACES_LAYERS_SUCCESS', + SET_SELECTED_FEATURE_LAYER: 'LAYER_REGION.SET_SELECTED_FEATURE_LAYER', + RESET_SELECTED_REGIONS: 'LAYER_REGION.RESET_SELECTED_REGIONS', + ADD_FEATURE_TO_SELECTED_REGIONS: 'LAYER_REGION.ADD_FEATURE_TO_SELECTED_REGIONS', + REMOVE_FEATURE_FROM_SELECTED_REGIONS: 'LAYER_REGION.REMOVE_FEATURE_FROM_SELECTED_REGIONS', + FETCH_WORKSPACES_REQUEST: 'LAYER_REGION.FETCH_WORKSPACES_REQUEST', + FETCH_WORKSPACES_FAILURE: 'LAYER_REGION.FETCH_WORKSPACES_FAILURE', + FETCH_WORKSPACES_SUCCESS: 'LAYER_REGION.FETCH_WORKSPACES_SUCCESS', + FETCH_WORKSPACES_LAYERS_REQUEST: 'LAYER_REGION.FETCH_WORKSPACES_LAYERS_REQUEST', + FETCH_WORKSPACES_LAYERS_FAILURE: 'LAYER_REGION.FETCH_WORKSPACES_LAYERS_FAILURE', + FETCH_WORKSPACES_LAYERS_SUCCESS: 'LAYER_REGION.FETCH_WORKSPACES_LAYERS_SUCCESS', }; // Actions diff --git a/src/redux/modules/Monitor.js b/src/redux/modules/Monitor.js index 60d2fea..b4fd3d0 100644 --- a/src/redux/modules/Monitor.js +++ b/src/redux/modules/Monitor.js @@ -3,22 +3,22 @@ import myHttp from '../../util/http'; // Constants export const constants = { - MONITOR_FETCH_WPS_JOBS_REQUEST: 'MONITOR_FETCH_WPS_JOBS_REQUEST', - MONITOR_FETCH_WPS_JOBS_FAILURE: 'MONITOR_FETCH_WPS_JOBS_FAILURE', - MONITOR_FETCH_WPS_JOBS_SUCCESS: 'MONITOR_FETCH_WPS_JOBS_SUCCESS', - MONITOR_POLL_WPS_JOBS_SUCCESS: 'MONITOR_POLL_WPS_JOBS_SUCCESS', - MONITOR_PERSIST_TEMPORARY_RESULT_REQUEST: 'MONITOR_PERSIST_TEMPORARY_RESULT_REQUEST', - MONITOR_PERSIST_TEMPORARY_RESULT_FAILURE: 'MONITOR_PERSIST_TEMPORARY_RESULT_FAILURE', - MONITOR_PERSIST_TEMPORARY_RESULT_SUCCESS: 'MONITOR_PERSIST_TEMPORARY_RESULT_SUCCESS', - MONITOR_VISUALIZE_TEMPORARY_RESULT_REQUEST: 'MONITOR_VISUALIZE_TEMPORARY_RESULT_REQUEST', - MONITOR_VISUALIZE_TEMPORARY_RESULT_FAILURE: 'MONITOR_VISUALIZE_TEMPORARY_RESULT_FAILURE', - MONITOR_VISUALIZE_TEMPORARY_RESULT_SUCCESS: 'MONITOR_VISUALIZE_TEMPORARY_RESULT_SUCCESS' + FETCH_WPS_JOBS_REQUEST: 'MONITOR.FETCH_WPS_JOBS_REQUEST', + FETCH_WPS_JOBS_FAILURE: 'MONITOR.FETCH_WPS_JOBS_FAILURE', + FETCH_WPS_JOBS_SUCCESS: 'MONITOR.FETCH_WPS_JOBS_SUCCESS', + POLL_WPS_JOBS_SUCCESS: 'MONITOR.POLL_WPS_JOBS_SUCCESS', + PERSIST_TEMPORARY_RESULT_REQUEST: 'MONITOR.PERSIST_TEMPORARY_RESULT_REQUEST', + PERSIST_TEMPORARY_RESULT_FAILURE: 'MONITOR.PERSIST_TEMPORARY_RESULT_FAILURE', + PERSIST_TEMPORARY_RESULT_SUCCESS: 'MONITOR.PERSIST_TEMPORARY_RESULT_SUCCESS', + VISUALIZE_TEMPORARY_RESULT_REQUEST: 'MONITOR.VISUALIZE_TEMPORARY_RESULT_REQUEST', + VISUALIZE_TEMPORARY_RESULT_FAILURE: 'MONITOR.VISUALIZE_TEMPORARY_RESULT_FAILURE', + VISUALIZE_TEMPORARY_RESULT_SUCCESS: 'MONITOR.VISUALIZE_TEMPORARY_RESULT_SUCCESS' }; //Actions Creators function requestWPSJobs () { return { - type: constants.MONITOR_FETCH_WPS_JOBS_REQUEST, + type: constants.FETCH_WPS_JOBS_REQUEST, jobs: { requestedAt: Date.now(), isFetching: true, @@ -32,7 +32,7 @@ function requestWPSJobs () { function receiveWPSJobsFailure (error) { NotificationManager.error(`Failed at fetching Phoenix Jobs at address ${error.url}. Returned Status ${error.status}: ${error.message}`, 'Error', 10000); return { - type: constants.MONITOR_FETCH_WPS_JOBS_FAILURE, + type: constants.FETCH_WPS_JOBS_FAILURE, jobs: { receivedAt: Date.now(), isFetching: false, @@ -46,7 +46,7 @@ function receiveWPSJobsFailure (error) { function receiveWPSJobs (data) { // NotificationManager.success('Test Success'); return { - type: constants.MONITOR_FETCH_WPS_JOBS_SUCCESS, + type: constants.FETCH_WPS_JOBS_SUCCESS, jobs: { receivedAt: Date.now(), isFetching: false, @@ -59,7 +59,7 @@ function receiveWPSJobs (data) { function requestPersistTemporaryResult () { return { - type: constants.MONITOR_PERSIST_TEMPORARY_RESULT_REQUEST, + type: constants.PERSIST_TEMPORARY_RESULT_REQUEST, persistedTempDataset: { requestedAt: Date.now(), isFetching: true, @@ -72,7 +72,7 @@ function requestPersistTemporaryResult () { function receivePersistTemporaryResultFailure (error) { NotificationManager.error(`Failed at persisting a temporary result. Returned Status ${error.status}: ${error.message}`, 'Error', 10000); return { - type: constants.MONITOR_PERSIST_TEMPORARY_RESULT_FAILURE, + type: constants.PERSIST_TEMPORARY_RESULT_FAILURE, persistedTempDataset: { receivedAt: Date.now(), isFetching: false, @@ -85,7 +85,7 @@ function receivePersistTemporaryResultFailure (error) { function receivePersistTemporaryResult (data) { NotificationManager.success(`Persisted file with success at ${data.url}`, 'Success', 4000); return { - type: constants.MONITOR_PERSIST_TEMPORARY_RESULT_SUCCESS, + type: constants.PERSIST_TEMPORARY_RESULT_SUCCESS, persistedTempDataset: { receivedAt: Date.now(), isFetching: false, @@ -97,7 +97,7 @@ function receivePersistTemporaryResult (data) { function requestVisualizeTemporaryResult () { return { - type: constants.MONITOR_VISUALIZE_TEMPORARY_RESULT_REQUEST, + type: constants.VISUALIZE_TEMPORARY_RESULT_REQUEST, visualizedTempDatasets: { requestedAt: Date.now(), isFetching: true, @@ -111,7 +111,7 @@ function requestVisualizeTemporaryResult () { function receiveVisualizeTemporaryResultFailure (error) { NotificationManager.error(`Failed at visualizing a temporary result. Returned Status ${error.status}: ${error.message}`, 'Error', 10000); return { - type: constants.MONITOR_VISUALIZE_TEMPORARY_RESULT_FAILURE, + type: constants.VISUALIZE_TEMPORARY_RESULT_FAILURE, visualizedTempDatasets: { receivedAt: Date.now(), isFetching: false, @@ -123,7 +123,7 @@ function receiveVisualizeTemporaryResultFailure (error) { function receiveVisualizeTemporaryResult (datasets) { return { - type: constants.MONITOR_VISUALIZE_TEMPORARY_RESULT_SUCCESS, + type: constants.VISUALIZE_TEMPORARY_RESULT_SUCCESS, visualizedTempDatasets: { receivedAt: Date.now(), isFetching: false, @@ -165,7 +165,7 @@ function fetchWPSJobs (projectId, limit = 5, page = 1, sort = 'created') { function receivePollWPSJobs (data) { return { - type: constants.MONITOR_FETCH_WPS_JOBS_SUCCESS, + type: constants.FETCH_WPS_JOBS_SUCCESS, jobs: { receivedAt: Date.now(), isFetching: false, @@ -277,34 +277,34 @@ export const initialState = { // Reducer const MONITOR_HANDLERS = { - [constants.MONITOR_FETCH_WPS_JOBS_REQUEST]: (state, action) => { + [constants.FETCH_WPS_JOBS_REQUEST]: (state, action) => { return ({...state, jobs: action.jobs}); }, - [constants.MONITOR_FETCH_WPS_JOBS_FAILURE]: (state, action) => { + [constants.FETCH_WPS_JOBS_FAILURE]: (state, action) => { return ({...state, jobs: action.jobs}); }, - [constants.MONITOR_FETCH_WPS_JOBS_SUCCESS]: (state, action) => { + [constants.FETCH_WPS_JOBS_SUCCESS]: (state, action) => { return ({...state, jobs: action.jobs}); }, - [constants.MONITOR_POLL_WPS_JOBS_SUCCESS]: (state, action) => { + [constants.POLL_WPS_JOBS_SUCCESS]: (state, action) => { return ({...state, jobs: action.jobs}); }, - [constants.MONITOR_PERSIST_TEMPORARY_RESULT_REQUEST]: (state, action) => { + [constants.PERSIST_TEMPORARY_RESULT_REQUEST]: (state, action) => { return ({...state, persistedTempDataset: action.persistedTempDataset}); }, - [constants.MONITOR_PERSIST_TEMPORARY_RESULT_FAILURE]: (state, action) => { + [constants.PERSIST_TEMPORARY_RESULT_FAILURE]: (state, action) => { return ({...state, persistedTempDataset: action.persistedTempDataset}); }, - [constants.MONITOR_PERSIST_TEMPORARY_RESULT_SUCCESS]: (state, action) => { + [constants.PERSIST_TEMPORARY_RESULT_SUCCESS]: (state, action) => { return ({...state, persistedTempDataset: action.persistedTempDataset}); }, - [constants.MONITOR_VISUALIZE_TEMPORARY_RESULT_REQUEST]: (state, action) => { + [constants.VISUALIZE_TEMPORARY_RESULT_REQUEST]: (state, action) => { return ({...state, visualizedTempDatasets: action.visualizedTempDatasets}); }, - [constants.MONITOR_VISUALIZE_TEMPORARY_RESULT_FAILURE]: (state, action) => { + [constants.VISUALIZE_TEMPORARY_RESULT_FAILURE]: (state, action) => { return ({...state, visualizedTempDatasets: action.visualizedTempDatasets}); }, - [constants.MONITOR_VISUALIZE_TEMPORARY_RESULT_SUCCESS]: (state, action) => { + [constants.VISUALIZE_TEMPORARY_RESULT_SUCCESS]: (state, action) => { return ({...state, visualizedTempDatasets: action.visualizedTempDatasets}); }, }; diff --git a/src/redux/modules/Project.js b/src/redux/modules/Project.js index c0dc557..367342f 100644 --- a/src/redux/modules/Project.js +++ b/src/redux/modules/Project.js @@ -1,6 +1,6 @@ // Constants export const constants = { - PROJECT_SET_CURRENT_PROJECT: 'PROJECT_SET_CURRENT_PROJECT' + PROJECT_SET_CURRENT_PROJECT: 'PROJECT.SET_CURRENT_PROJECT' }; // Actions diff --git a/src/redux/modules/Researcher.js b/src/redux/modules/Researcher.js deleted file mode 100644 index 935a1d9..0000000 --- a/src/redux/modules/Researcher.js +++ /dev/null @@ -1,82 +0,0 @@ -import myHttp from '../../util/http'; -// Constants -export const constants = { - RESEARCHER_SET_CURRENT_RESEARCHER: 'RESEARCHER_SET_CURRENT_RESEARCHER', - RESEARCHER_LOGIN_REQUEST: 'RESEARCHER_LOGIN_REQUEST', - RESEARCHER_LOGIN_SUCCESS: 'RESEARCHER_LOGIN_SUCCESS', - RESEARCHER_LOGIN_FAILURE: 'RESEARCHER_LOGIN_FAILURE', -}; - -// Actions -function loginResearcherRequest() { - return { - type: constants.RESEARCHER_LOGIN_REQUEST, - researcherProjects: { - requestedAt: Date.now(), - isFetching: true, - data: {} - } - }; -} -function loginResearcherSuccess (session) { - return { - type: constants.RESEARCHER_LOGIN_SUCCESS, - researcherProjects: { - receivedAt: Date.now(), - isFetching: false, - data: session, - error: null - } - }; -} -function loginResearcherFailure (error) { - return { - type: constants.RESEARCHER_LOGIN_FAILURE, - session: { - receivedAt: Date.now(), - isFetching: false, - data: {}, - error: error - } - }; -} -export function login (credentials) { - return dispatch => { - dispatch(loginResearcherRequest()); - myHttp.postJson(__PAVICS_PROJECT_API_PATH__ + '/Researcher/login', credentials) - .then(res => res.json()) - .then(json => dispatch(loginResearcherSuccess(json))) - .catch(err => dispatch(loginResearcherFailure(err))); - }; -} - -// Exported Action Creators -export const actions = { - login -}; - -// Handlers -const RESEARCHER_HANDLERS = { - -}; - -// Reducer -export const initialState = { - currentResearcher: { - email: 'renaud.hebert-legault@crim.ca', - id: 1, - username: 'renaud', - password: 'qwerty' - }, - session: { - requestedAt: null, - receivedAt: null, - isFetching: false, - data: {}, - error: null - } -}; -export default function (state = initialState, action) { - const handler = RESEARCHER_HANDLERS[action.type]; - return handler ? handler(state, action) : state; -} diff --git a/src/redux/modules/Section.js b/src/redux/modules/Section.js index cd5f890..d545179 100644 --- a/src/redux/modules/Section.js +++ b/src/redux/modules/Section.js @@ -1,6 +1,6 @@ // Constants export const constants = { - PLATFORM_SET_SECTION: 'SECITON_MANAMGENT.PLATFORM_SET_SECTION' + PLATFORM_SET_SECTION: 'SECTION.PLATFORM_SET_SECTION' }; // Action Creators diff --git a/src/redux/modules/Session.js b/src/redux/modules/Session.js index a93180b..3265436 100644 --- a/src/redux/modules/Session.js +++ b/src/redux/modules/Session.js @@ -3,53 +3,53 @@ import {NotificationManager} from 'react-notifications'; // Constants export const constants = { - ZIGGURAT_LOGIN_REQUEST: 'ZIGGURAT_LOGIN_REQUEST', - ZIGGURAT_LOGIN_FAILURE: 'ZIGGURAT_LOGIN_FAILURE', - ZIGGURAT_LOGIN_SUCCESS: 'ZIGGURAT_LOGIN_SUCCESS', - SESSION_LOGOUT_REQUEST: 'SESSION_LOGOUT_REQUEST', - SESSION_LOGOUT_FAILURE: 'SESSION_LOGOUT_FAILURE', - SESSION_LOGOUT_SUCCESS: 'SESSION_LOGOUT_SUCCESS', - SESSION_CHECK_LOGIN_REQUEST: 'SESSION_CHECK_LOGIN_REQUEST', - SESSION_CHECK_LOGIN_FAILURE: 'SESSION_CHECK_LOGIN_FAILURE', - SESSION_CHECK_LOGIN_SUCCESS: 'SESSION_CHECK_LOGIN_SUCCESS', - SET_SESSION_INFORMATIONS: 'SET_SESSION_INFORMATIONS', - RESET_SESSION_INFORMATIONS: 'RESET_SESSION_INFORMATIONS', - SESSION_LOGOUT: 'SESSION_LOGOUT', + LOGIN_REQUEST: 'SESSION.LOGIN_REQUEST', + LOGIN_FAILURE: 'SESSION.LOGIN_FAILURE', + LOGIN_SUCCESS: 'SESSION.LOGIN_SUCCESS', + LOGOUT_REQUEST: 'SESSION.LOGOUT_REQUEST', + LOGOUT_FAILURE: 'SESSION.LOGOUT_FAILURE', + LOGOUT_SUCCESS: 'SESSION.LOGOUT_SUCCESS', + CHECK_LOGIN_REQUEST: 'SESSION.CHECK_LOGIN_REQUEST', + CHECK_LOGIN_FAILURE: 'SESSION.CHECK_LOGIN_FAILURE', + CHECK_LOGIN_SUCCESS: 'SESSION.CHECK_LOGIN_SUCCESS', + SET_SESSION_INFORMATIONS: 'SESSION.SET_SESSION_INFORMATIONS', + RESET_SESSION_INFORMATIONS: 'SESSION.RESET_SESSION_INFORMATIONS', + LOGOUT: 'SESSION.LOGOUT', }; function zigguratLoginRequest () { return { - type: constants.ZIGGURAT_LOGIN_REQUEST, + type: constants.LOGIN_REQUEST, }; } function zigguratLoginSuccess () { return { - type: constants.ZIGGURAT_LOGIN_SUCCESS, + type: constants.LOGIN_SUCCESS, }; } function zigguratLoginFailure () { return { - type: constants.ZIGGURAT_LOGIN_FAILURE, + type: constants.LOGIN_FAILURE, }; } function checkLoginRequest () { return { - type: constants.SESSION_CHECK_LOGIN_REQUEST, + type: constants.CHECK_LOGIN_REQUEST, }; } function checkLoginSuccess () { return { - type: constants.SESSION_CHECK_LOGIN_SUCCESS, + type: constants.CHECK_LOGIN_SUCCESS, }; } function checkLoginFailure () { return { - type: constants.SESSION_CHECK_LOGIN_FAILURE, + type: constants.CHECK_LOGIN_FAILURE, }; } @@ -65,19 +65,19 @@ function setSessionInformations (user, authenticated, email, groups) { function sessionLogoutRequest () { return { - type: constants.SESSION_LOGOUT_REQUEST, + type: constants.LOGOUT_REQUEST, }; } function sessionLogoutSuccess () { return { - type: constants.SESSION_LOGOUT_SUCCESS, + type: constants.LOGOUT_SUCCESS, }; } function sessionLogoutFailure () { return { - type: constants.SESSION_LOGOUT_FAILURE, + type: constants.LOGOUT_FAILURE, }; } @@ -166,12 +166,12 @@ export const actions = { // Handlers const HANDLERS = { - [constants.ZIGGURAT_LOGIN_REQUEST]: (state, action) => { return state; }, - [constants.ZIGGURAT_LOGIN_SUCCESS]: (state, action) => { return state; }, - [constants.ZIGGURAT_LOGIN_FAILURE]: (state, action) => { return state; }, - [constants.SESSION_CHECK_LOGIN_REQUEST]: (state, action) => { return state; }, - [constants.SESSION_CHECK_LOGIN_SUCCESS]: (state, action) => { return state; }, - [constants.SESSION_CHECK_LOGIN_FAILURE]: (state, action) => { return state; }, + [constants.LOGIN_REQUEST]: (state, action) => { return state; }, + [constants.LOGIN_SUCCESS]: (state, action) => { return state; }, + [constants.LOGIN_FAILURE]: (state, action) => { return state; }, + [constants.CHECK_LOGIN_REQUEST]: (state, action) => { return state; }, + [constants.CHECK_LOGIN_SUCCESS]: (state, action) => { return state; }, + [constants.CHECK_LOGIN_FAILURE]: (state, action) => { return state; }, [constants.SET_SESSION_INFORMATIONS]: (state, action) => { return ({ ...state, sessionStatus: { diff --git a/src/redux/modules/Visualize.js b/src/redux/modules/Visualize.js index 2e8eea8..abb4392 100644 --- a/src/redux/modules/Visualize.js +++ b/src/redux/modules/Visualize.js @@ -4,18 +4,18 @@ import { VISUALIZE_SET_MAP_MANIPULATION_MODE, VISUALIZE_MODE_GRID_VALUES } from // Constants export const constants = { // SYNC - RESET_VISUALIZE_STATE: 'Visualize.RESET_VISUALIZE_STATE', - ADD_SEARCH_CRITERIAS_TO_PROJECTS: 'Visualize.ADD_SEARCH_CRITERIAS_TO_PROJECTS', - REMOVE_SEARCH_CRITERIAS_FROM_PROJECTS: 'Visualize.REMOVE_SEARCH_CRITERIAS_FROM_PROJECTS', - ADD_DATASETS_TO_PROJECTS: 'Visualize.ADD_DATASETS_TO_PROJECTS', - CLICK_TOGGLE_PANEL: 'Visualize.CLICK_TOGGLE_PANEL', + RESET_VISUALIZE_STATE: 'VISUALIZE.RESET_VISUALIZE_STATE', + ADD_SEARCH_CRITERIAS_TO_PROJECTS: 'VISUALIZE.ADD_SEARCH_CRITERIAS_TO_PROJECTS', + REMOVE_SEARCH_CRITERIAS_FROM_PROJECTS: 'VISUALIZE.REMOVE_SEARCH_CRITERIAS_FROM_PROJECTS', + ADD_DATASETS_TO_PROJECTS: 'VISUALIZE.ADD_DATASETS_TO_PROJECTS', + CLICK_TOGGLE_PANEL: 'VISUALIZE.CLICK_TOGGLE_PANEL', // ASYNC - FETCH_PLOTLY_DATA_REQUEST: 'Visualize.FETCH_PLOTLY_DATA_REQUEST', - FETCH_PLOTLY_DATA_FAILURE: 'Visualize.FETCH_PLOTLY_DATA_FAILURE', - FETCH_PLOTLY_DATA_SUCCESS: 'Visualize.FETCH_PLOTLY_DATA_SUCCESS', - FETCH_SCALAR_VALUE_REQUEST: 'Visualize.FETCH_SCALAR_VALUE_REQUEST', - FETCH_SCALAR_VALUE_FAILURE: 'Visualize.FETCH_SCALAR_VALUE_FAILURE', - FETCH_SCALAR_VALUE_SUCCESS: 'Visualize.FETCH_SCALAR_VALUE_SUCCESS' + FETCH_PLOTLY_DATA_REQUEST: 'VISUALIZE.FETCH_PLOTLY_DATA_REQUEST', + FETCH_PLOTLY_DATA_FAILURE: 'VISUALIZE.FETCH_PLOTLY_DATA_FAILURE', + FETCH_PLOTLY_DATA_SUCCESS: 'VISUALIZE.FETCH_PLOTLY_DATA_SUCCESS', + FETCH_SCALAR_VALUE_REQUEST: 'VISUALIZE.FETCH_SCALAR_VALUE_REQUEST', + FETCH_SCALAR_VALUE_FAILURE: 'VISUALIZE.FETCH_SCALAR_VALUE_FAILURE', + FETCH_SCALAR_VALUE_SUCCESS: 'VISUALIZE.FETCH_SCALAR_VALUE_SUCCESS' }; // Action Creators diff --git a/src/redux/modules/Widgets.js b/src/redux/modules/Widgets.js index f70554e..5349cc7 100644 --- a/src/redux/modules/Widgets.js +++ b/src/redux/modules/Widgets.js @@ -11,7 +11,6 @@ export const constants = { // Actions - // Action Creators export const actions = { toggleWidget: function (key) { diff --git a/src/redux/modules/Workflow.js b/src/redux/modules/Workflow.js index 431e8d8..e2cf7ab 100644 --- a/src/redux/modules/Workflow.js +++ b/src/redux/modules/Workflow.js @@ -3,22 +3,22 @@ import myHttp from '../../util/http'; import {InputDefinition} from '../../components/WpsProcessFormInput/InputDefinition'; // Constants export const constants = { - WORKFLOW_CHANGE_STEP: 'WORKFLOW_CHANGE_STEP', - WORKFLOW_SET_PROCESSES: 'WORKFLOW_SET_PROCESSES', - WORKFLOW_SET_PROVIDERS: 'WORKFLOW_SET_PROVIDERS', - WORKFLOW_CHOOSE_PROCESS: 'WORKFLOW_CHOOSE_PROCESS', - WORKFLOW_GET_FIRST_STEP: 'WORKFLOW_GET_FIRST_STEP', - WORKFLOW_GET_LAST_STEP: 'WORKFLOW_GET_LAST_STEP', - WORKFLOW_GET_NEXT_STEP: 'WORKFLOW_GET_NEXT_STEP', - WORKFLOW_STEP_PROCESS: 'WORKFLOW_STEP_PROCESS', - WORKFLOW_STEP_INPUTS: 'WORKFLOW_STEP_INPUTS', - WORKFLOW_STEP_RUN: 'WORKFLOW_STEP_RUN', - WORKFLOW_SET_WPS_PROVIDER: 'WORKFLOW_SET_WPS_PROVIDER', - WORKFLOW_SET_ACTIVE_PROCESS_INPUTS: 'WORKFLOW_SET_ACTIVE_PROCESS_INPUTS', - WORKFLOW_SET_ACTIVE_PROCESS_VALUES: 'WORKFLOW_SET_ACTIVE_PROCESS_VALUES', - WORKFLOW_FETCH_WPS_JOBS_REQUEST: 'WORKFLOW_FETCH_WPS_JOBS_REQUEST', - WORKFLOW_FETCH_WPS_JOBS_FAILURE: 'WORKFLOW_FETCH_WPS_JOBS_FAILURE', - WORKFLOW_FETCH_WPS_JOBS_SUCCESS: 'WORKFLOW_FETCH_WPS_JOBS_SUCCESS' + CHANGE_STEP: 'WORKFLOW.CHANGE_STEP', + SET_PROCESSES: 'WORKFLOW.SET_PROCESSES', + SET_PROVIDERS: 'WORKFLOW.SET_PROVIDERS', + CHOOSE_PROCESS: 'WORKFLOW.CHOOSE_PROCESS', + GET_FIRST_STEP: 'WORKFLOW.GET_FIRST_STEP', + GET_LAST_STEP: 'WORKFLOW.GET_LAST_STEP', + GET_NEXT_STEP: 'WORKFLOW.GET_NEXT_STEP', + STEP_PROCESS: 'WORKFLOW.STEP_PROCESS', + STEP_INPUTS: 'WORKFLOW.STEP_INPUTS', + STEP_RUN: 'WORKFLOW.STEP_RUN', + SET_WPS_PROVIDER: 'WORKFLOW.SET_WPS_PROVIDER', + SET_ACTIVE_PROCESS_INPUTS: 'WORKFLOW.SET_ACTIVE_PROCESS_INPUTS', + SET_ACTIVE_PROCESS_VALUES: 'WORKFLOW.SET_ACTIVE_PROCESS_VALUES', + FETCH_WPS_JOBS_REQUEST: 'WORKFLOW.FETCH_WPS_JOBS_REQUEST', + FETCH_WPS_JOBS_FAILURE: 'WORKFLOW.FETCH_WPS_JOBS_FAILURE', + FETCH_WPS_JOBS_SUCCESS: 'WORKFLOW.FETCH_WPS_JOBS_SUCCESS' }; // Actions @@ -37,14 +37,14 @@ function setSelectedProcess (process) { identifier: processIdentifier }); return { - type: constants.WORKFLOW_CHOOSE_PROCESS, + type: constants.CHOOSE_PROCESS, process: process }; } function setProcesses (processes) { return { - type: constants.WORKFLOW_SET_PROCESSES, + type: constants.SET_PROCESSES, processes: processes }; } @@ -54,28 +54,28 @@ function setProviders (providers) { provider.identifier = provider.url.replace('/processes/list?wps=', ''); }); return { - type: constants.WORKFLOW_SET_PROVIDERS, + type: constants.SET_PROVIDERS, items: providers }; } function setWpsProvider (provider) { return { - type: constants.WORKFLOW_SET_WPS_PROVIDER, + type: constants.SET_WPS_PROVIDER, provider: provider }; } function setProcessInputs (inputs) { return { - type: constants.WORKFLOW_SET_ACTIVE_PROCESS_INPUTS, + type: constants.SET_ACTIVE_PROCESS_INPUTS, inputs: inputs }; } function setSelectedProcessValues (key, value) { return { - type: constants.WORKFLOW_SET_ACTIVE_PROCESS_VALUES, + type: constants.SET_ACTIVE_PROCESS_VALUES, key: key, value: value }; @@ -83,26 +83,26 @@ function setSelectedProcessValues (key, value) { function chooseStep (step) { return { - type: constants.WORKFLOW_CHANGE_STEP, + type: constants.CHANGE_STEP, step: step }; } function getFirstStep () { return { - type: constants.WORKFLOW_GET_FIRST_STEP + type: constants.GET_FIRST_STEP }; } function getLastStep () { return { - type: constants.WORKFLOW_GET_LAST_STEP + type: constants.GET_LAST_STEP }; } function getNextStep () { return { - type: constants.WORKFLOW_GET_NEXT_STEP + type: constants.GET_NEXT_STEP }; } @@ -216,39 +216,39 @@ export const actions = { }; // Handlers -const WORKFLOW_HANDLERS = { - [constants.WORKFLOW_SET_WPS_PROVIDER]: (state, action) => { +const HANDLERS = { + [constants.SET_WPS_PROVIDER]: (state, action) => { return {...state, selectedProvider: action.provider}; }, - [constants.WORKFLOW_CHOOSE_PROCESS]: (state, action) => { + [constants.CHOOSE_PROCESS]: (state, action) => { return {...state, selectedProcess: action.process}; }, - [constants.WORKFLOW_SET_ACTIVE_PROCESS_INPUTS]: (state, action) => { + [constants.SET_ACTIVE_PROCESS_INPUTS]: (state, action) => { return {...state, selectedProcessInputs: action.inputs}; }, - [constants.WORKFLOW_SET_ACTIVE_PROCESS_VALUES]: (state, action) => { + [constants.SET_ACTIVE_PROCESS_VALUES]: (state, action) => { return Object.assign({}, state, { selectedProcessValues: Object.assign({}, state.selectedProcessValues, { [action.key]: action.value }) }); }, - [constants.WORKFLOW_CHANGE_STEP]: (state, action) => { + [constants.CHANGE_STEP]: (state, action) => { return {...state, currentStep: action.step}; }, - [constants.WORKFLOW_GET_FIRST_STEP]: (state) => { + [constants.GET_FIRST_STEP]: (state) => { return {...state, stepIndex: 0}; }, - [constants.WORKFLOW_GET_LAST_STEP]: (state) => { + [constants.GET_LAST_STEP]: (state) => { return {...state, stepIndex: (state.stepIndex - 1)}; }, - [constants.WORKFLOW_GET_NEXT_STEP]: (state) => { + [constants.GET_NEXT_STEP]: (state) => { return {...state, stepIndex: (state.stepIndex + 1)}; }, - [constants.WORKFLOW_SET_PROCESSES]: (state, action) => { + [constants.SET_PROCESSES]: (state, action) => { return {...state, processes: action.processes}; }, - [constants.WORKFLOW_SET_PROVIDERS]: (state, action) => { + [constants.SET_PROVIDERS]: (state, action) => { return Object.assign({}, state, { providers: {...state.providers, items: action.items} }); @@ -266,7 +266,7 @@ export const initialState = { stepIndex: 0, selectedProcessInputs: [], selectedProcessValues: {}, - currentStep: constants.WORKFLOW_STEP_PROCESS, + currentStep: constants.STEP_PROCESS, processes: [], providers: { items: [] @@ -274,6 +274,6 @@ export const initialState = { selectedProvider: '' }; export default function (state = initialState, action) { - const handler = WORKFLOW_HANDLERS[action.type]; + const handler = HANDLERS[action.type]; return handler ? handler(state, action) : state; } diff --git a/src/store/reducers.js b/src/store/reducers.js index 6b04cc1..f5bbe32 100644 --- a/src/store/reducers.js +++ b/src/store/reducers.js @@ -11,7 +11,6 @@ import projectReducer from './../redux/modules/Project'; import { reducers as projectAPIReducer } from '../redux/modules/ProjectAPI'; import researchReducer from './../redux/modules/Research'; import { reducers as ResearchAPIReducer } from '../redux/modules/ResearchAPI'; -import researcherReducer from './../redux/modules/Researcher'; import { reducers as researcherAPIReducer } from '../redux/modules/ResearcherAPI'; import sectionReducer from '../redux/modules/Section'; import workflowReducer from './../redux/modules/Workflow'; @@ -35,7 +34,6 @@ export const makeRootReducer = (asyncReducers) => { 'projectAPI': projectAPIReducer, 'research': researchReducer, 'researchAPI': ResearchAPIReducer, - 'researcher': researcherReducer, 'researcherAPI': researcherAPIReducer, 'workflow': workflowReducer, 'workflowAPI': workflowAPIReducer, From d9f855efb9cf19fd175aaafe46e3cd2a8db431a7 Mon Sep 17 00:00:00 2001 From: Renaud009 Date: Wed, 24 Oct 2018 20:14:05 +0100 Subject: [PATCH 07/15] Major bug fixes --- package-lock.json | 5 +++ package.json | 1 + .../WidgetDrawFeatures/WidgetDrawFeatures.js | 18 +++++++-- .../OLDrawFeatures/OLDrawFeatures.js | 30 +++++++++------ src/redux/modules/LayerCustomFeature.js | 38 +++++++++++-------- 5 files changed, 62 insertions(+), 30 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3a444f7..5c076aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12834,6 +12834,11 @@ } } }, + "redux-devtools-extension": { + "version": "2.13.5", + "resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.5.tgz", + "integrity": "sha512-QQ9BRy77oURHMdGys9rfQcCQDzXZ1T4oW+eUyE5Cg7DNVau69HJzc4YNDMOmpi0Dzpi1zOQgQ2rUpgJta4Lfqg==" + }, "redux-persist": { "version": "4.10.2", "resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-4.10.2.tgz", diff --git a/package.json b/package.json index b882dc8..9f8e1b3 100644 --- a/package.json +++ b/package.json @@ -135,6 +135,7 @@ "react-router": "^3.2.1", "react-router-redux": "^4.0.0", "redux": "^3.0.0", + "redux-devtools-extension": "^2.13.5", "redux-persist": "^4.4.2", "redux-thunk": "^2.0.0", "rimraf": "^2.5.1", diff --git a/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js b/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js index 4099e68..0ba2ad8 100644 --- a/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js +++ b/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import {withStyles} from '@material-ui/core/styles'; +import { NotificationManager } from 'react-notifications'; import {VISUALIZE_DRAW_MODES} from './../../constants'; import Divider from'@material-ui/core/Divider'; import Button from'@material-ui/core/Button'; @@ -77,7 +78,11 @@ class WidgetDrawFeatures extends React.Component { }; onUploadDrawnLayer = () => { - this.props.layerCustomFeatureActions.createUploadZipShapefile(this.state.regionIdentifier); + if (this.state.regionIdentifier.length) { + this.props.layerCustomFeatureActions.createUploadZipShapefile(this.state.regionIdentifier); + } else { + NotificationManager.warning(`Region identifier is required before uploading drawn custom regions.`, 'Warning', 10000); + } }; onHandleTextChangedOld = field => event => { @@ -98,6 +103,13 @@ class WidgetDrawFeatures extends React.Component { const datastore = 'CUSTOM_SHAPEFILES_DS'; // ' USER_SHAPEFILES'; var blobData = new Blob([this.state.file], {type: 'application/zip'}); this.props.layerCustomFeatureActions.uploadZipShapefile(workspace, datastore, blobData); + this.setState({ + file: null, + fileName: '', + fileType: '', + fileSize: 0, + fileLastModified: 'n/a' + }); }; handleFileSelect = (evt) => { @@ -119,7 +131,7 @@ class WidgetDrawFeatures extends React.Component { }; render() { - const {currentDrawingTool, currentSelectedDrawnFeatureProperties, drawnCustomFeatures} = this.props.layerCustomFeature; + const {currentDrawingTool, currentSelectedDrawnFeatureProperties, geoJSONDrawnFeatures} = this.props.layerCustomFeature; // const {name, description} = this.state; const {featureIdentifier, regionIdentifier} = this.state; return ( @@ -173,7 +185,7 @@ class WidgetDrawFeatures extends React.Component { value={featureIdentifier} onChange={this.onHandleTextChanged('featureIdentifier')} label="Feature's identifier"/> - Drawn regions total: {drawnCustomFeatures.length} + Drawn regions total: {geoJSONDrawnFeatures.features.length} + {/* + Download button disabled for now, should be eventually positioned in the the layer-switcher for each geoserver's available layer + */} { // Following code helps defining a name and a description to every drawn feature // It's deprecated since the library only insert a single MultiPolygon containing all polygons, so end-up with one feature only From 2c4d9d00a35cc0fa289cacba1f9c577f2ff37eda Mon Sep 17 00:00:00 2001 From: Renaud009 Date: Thu, 25 Oct 2018 19:58:53 +0100 Subject: [PATCH 11/15] Changed some keys to prevent glitches in drawing mode --- .../WidgetDrawFeatures/WidgetDrawFeatures.js | 9 ++++++--- src/constants.js | 12 ++++++------ src/containers/OLDrawFeatures/OLDrawFeatures.js | 8 +++++--- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js b/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js index d4360a3..ec8a23d 100644 --- a/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js +++ b/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js @@ -277,9 +277,12 @@ class WidgetDrawFeatures extends React.Component { } Tips: -
Press alt and click to delete a point (when region is selected)
-
Hold shift to draw Bounding-Box, Hexagon and Square
-
Hold shift (optionally) for freehand (Polygon and Line)
+
Hold alt-shift keys to draw Bounding Box, Hexagon and Square
+
Hold alt key to draw Polygon and Line
+
Hold alt-shift keys to activate freehand drawing for Polygon and Line
+
Select a region by a single click (one at a time)
+
Drag region points extremities to edit a selected region
+
Hold alt and click a point to delete it (when region is selected)
} diff --git a/src/constants.js b/src/constants.js index f90ebac..18c919d 100644 --- a/src/constants.js +++ b/src/constants.js @@ -22,24 +22,24 @@ export const TIME_SLIDER_WIDGET_TITLE = 'Temporal Slider'; export const VISUALIZE_DRAW_MODES = { BBOX: { value: 'Bbox', - label: 'Bounding Box (hold shift key)' + label: 'Bounding Box (hold alt-shift key)' }, // DEPRECATED: Circle feature geometry will be empty when transformed into GeoJSON format /*CIRCLE: { value: 'Circle', - label: 'Circle (hold shift key)' + label: 'Circle (hold alt-shift key)' },*/ HEXAGON: { value: 'Hexagon', - label: 'Hexagon (hold shift key)' + label: 'Hexagon (hold alt-shift keys)' }, LINE_STRING: { value: 'LineString', - label: 'Line (optionally hold shift for freehand)' + label: 'Line (hold alt key or alt-shift keys for freehand)' }, SQUARE: { value: 'Square', - label: 'Square (hold shift key)' + label: 'Square (hold alt-shift keys)' }, // TODO: Nothing appears on map after click... so disabled for now /* POINT: { @@ -48,7 +48,7 @@ export const VISUALIZE_DRAW_MODES = { },*/ POLYGON: { value: 'Polygon', - label: 'Polygon (optionally hold shift for freehand)' + label: 'Polygon (hold alt key or alt-shift keys for freehand)' } // TODO: https://github.com/Ouranosinc/PAVICS-frontend/issues/134#issuecomment-416724206 // Should be able to define a zonal or meridional globe-wide with only x1/x2 or y1/y2 diff --git a/src/containers/OLDrawFeatures/OLDrawFeatures.js b/src/containers/OLDrawFeatures/OLDrawFeatures.js index a244bf6..4856c8f 100644 --- a/src/containers/OLDrawFeatures/OLDrawFeatures.js +++ b/src/containers/OLDrawFeatures/OLDrawFeatures.js @@ -7,7 +7,7 @@ import { Draw, Modify, Select, Snap } from 'ol/interaction'; import Map from 'ol/Map'; import { GeoJSON, WMSCapabilities } from 'ol/format'; import { createRegularPolygon, createBox } from 'ol/interaction/Draw'; -import { platformModifierKeyOnly, altKeyOnly, shiftKeyOnly, singleClick, doubleClick } from 'ol/events/condition'; +import { platformModifierKeyOnly, altKeyOnly, altShiftKeysOnly, shiftKeyOnly, singleClick, doubleClick } from 'ol/events/condition'; import { Vector as VectorSource } from 'ol/source'; import { Vector as VectorLayer } from 'ol/layer'; import { Circle, Fill, Text, Stroke, Style, RegularShape } from 'ol/style'; @@ -189,7 +189,7 @@ class OLDrawFeatures extends React.Component { /*case VISUALIZE_DRAW_MODES.CIRCLE.value: geometryFunction = null; drawType = VISUALIZE_DRAW_MODES.CIRCLE.value; - condition = shiftKeyOnly; + condition = shiftKeyOnly; break;*/ case VISUALIZE_DRAW_MODES.HEXAGON.value: geometryFunction = createRegularPolygon(5); @@ -199,6 +199,7 @@ class OLDrawFeatures extends React.Component { case VISUALIZE_DRAW_MODES.LINE_STRING.value: geometryFunction = null; drawType = VISUALIZE_DRAW_MODES.LINE_STRING.value; + condition = altKeyOnly; break; case VISUALIZE_DRAW_MODES.SQUARE.value: geometryFunction = createRegularPolygon(4); @@ -214,7 +215,7 @@ class OLDrawFeatures extends React.Component { case VISUALIZE_DRAW_MODES.POLYGON.value: geometryFunction = null; drawType = VISUALIZE_DRAW_MODES.POLYGON.value; - // condition = platformModifierKeyOnly; + condition = altKeyOnly; break; default: // None(empty) already managed by if @@ -239,6 +240,7 @@ class OLDrawFeatures extends React.Component { }),*/ }), condition: condition, + freehandCondition: altShiftKeysOnly, geometryFunction: geometryFunction, type: drawType }); From 9e7da4c0286cd177fc768a42bc1d5b18d98c8603 Mon Sep 17 00:00:00 2001 From: Renaud009 Date: Thu, 25 Oct 2018 20:20:09 +0100 Subject: [PATCH 12/15] Define default workspace and datastore in environement variables --- .eslintrc | 2 ++ config/index.js | 24 +++++++++---------- .../WidgetDrawFeatures/WidgetDrawFeatures.js | 4 ++-- src/redux/modules/LayerCustomFeature.js | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.eslintrc b/.eslintrc index cc207a4..233c072 100644 --- a/.eslintrc +++ b/.eslintrc @@ -20,6 +20,8 @@ "__PAVICS_GEOSERVER_API_PATH__" : false, "__PAVICS_GEOSERVER_WORKSPACES_SERVICE_NAME__" : false, "__PAVICS_PROJECT_API_PATH__" : false, + "__PAVICS_GEOSERVER_CUSTOM_WORKSPACE__": false, + "__PAVICS_GEOSERVER_CUSTOM_DATASTORE__": false, "__MAGPIE_HOST__" : false }, "rules": { diff --git a/config/index.js b/config/index.js index 19cbccc..bffec32 100644 --- a/config/index.js +++ b/config/index.js @@ -15,12 +15,6 @@ const birdhouseHost = process.env.BIRDHOUSE_HOST || 'pluvier.crim.ca'; const ncwmsHost = process.env.NCWMS_HOST || `https://${birdhouseHost}/twitcher/ows/proxy/ncWMS2/wms`; const catalogHost = process.env.CATALOG_HOST || `https://${birdhouseHost}/twitcher/ows/proxy/catalog/pywps`; const malleefowlHost = process.env.MALLEEFOWL_HOST || `https://${birdhouseHost}/twitcher/ows/proxy/malleefowl/wps`; -const PAVICS_WORKFLOW_PROVIDER = process.env.PAVICS_WORKFLOW_PROVIDER || 'malleefowl'; -const PAVICS_RUN_WORKFLOW_IDENTIFIER = process.env.PAVICS_RUN_WORKFLOW_IDENTIFIER || 'custom_workflow'; -const PAVICS_VISUALIZE_IDENTIFIER = process.env.PAVICS_VISUALIZE_IDENTIFIER || 'TODO'; -const PAVICS_PERSIST_IDENTIFIER = process.env.PAVICS_PERSIST_IDENTIFIER || 'TODO'; -const PAVICS_PUBLISH_IDENTIFIER = process.env.PAVICS_PUBLISH_IDENTIFIER || 'TODO'; -const PAVICS_DEFAULT_WORKSPACE_FOLDER = process.env.PAVICS_DEFAULT_WORKSPACE_FOLDER || 'workspaces'; const serverPort = process.env.PORT || 3000; const serverExternalPort = process.env.PAVICS_FRONTEND_PORT || serverPort; const URL_BASE = `${serverProto}://${birdhouseHost}`; @@ -47,12 +41,14 @@ const config = { // pavics_project_api_internal_url is needed in dev mode since centos vm etc/hosts hasn't its value modified but windows host has (pluvier -­> dev IP) pavics_project_api_internal_url: process.env.PAVICS_PROJECT_API_INTERNAL_URL || `${URL_BASE}/project-api/api`, // DEV pavics_magpie_host: `${URL_BASE}/magpie`, - PAVICS_WORKFLOW_PROVIDER: PAVICS_WORKFLOW_PROVIDER, - PAVICS_RUN_WORKFLOW_IDENTIFIER: PAVICS_RUN_WORKFLOW_IDENTIFIER, - PAVICS_VISUALIZE_IDENTIFIER: PAVICS_VISUALIZE_IDENTIFIER, - PAVICS_PERSIST_IDENTIFIER: PAVICS_PERSIST_IDENTIFIER, - PAVICS_PUBLISH_IDENTIFIER: PAVICS_PUBLISH_IDENTIFIER, - PAVICS_DEFAULT_WORKSPACE_FOLDER: PAVICS_DEFAULT_WORKSPACE_FOLDER, + PAVICS_WORKFLOW_PROVIDER: process.env.PAVICS_WORKFLOW_PROVIDER || 'malleefowl', + PAVICS_RUN_WORKFLOW_IDENTIFIER: process.env.PAVICS_RUN_WORKFLOW_IDENTIFIER || 'custom_workflow', + PAVICS_VISUALIZE_IDENTIFIER: process.env.PAVICS_VISUALIZE_IDENTIFIER || 'TODO', + PAVICS_PERSIST_IDENTIFIER: process.env.PAVICS_PERSIST_IDENTIFIER || 'TODO', + PAVICS_PUBLISH_IDENTIFIER: process.env.PAVICS_PUBLISH_IDENTIFIER || 'TODO', + PAVICS_DEFAULT_WORKSPACE_FOLDER: process.env.PAVICS_DEFAULT_WORKSPACE_FOLDER || 'workspaces', + PAVICS_GEOSERVER_CUSTOM_WORKSPACE: process.env.PAVICS_GEOSERVER_CUSTOM_WORKSPACE || 'User_Custom_Regions', + PAVICS_GEOSERVER_CUSTOM_DATASTORE: process.env.PAVICS_GEOSERVER_CUSTOM_DATASTORE || 'User_Custom_Regions', // ---------------------------------- // Project Structure // ---------------------------------- @@ -128,7 +124,9 @@ config.globals = { '__PAVICS_VISUALIZE_IDENTIFIER__': JSON.stringify(config.PAVICS_VISUALIZE_IDENTIFIER), '__PAVICS_PERSIST_IDENTIFIER__': JSON.stringify(config.PAVICS_PERSIST_IDENTIFIER), '__PAVICS_PUBLISH_IDENTIFIER__': JSON.stringify(config.PAVICS_PUBLISH_IDENTIFIER), - '__PAVICS_DEFAULT_WORKSPACE_FOLDER__': JSON.stringify(config.PAVICS_DEFAULT_WORKSPACE_FOLDER) + '__PAVICS_DEFAULT_WORKSPACE_FOLDER__': JSON.stringify(config.PAVICS_DEFAULT_WORKSPACE_FOLDER), + '__PAVICS_GEOSERVER_CUSTOM_WORKSPACE__': JSON.stringify(config.PAVICS_GEOSERVER_CUSTOM_WORKSPACE), + '__PAVICS_GEOSERVER_CUSTOM_DATASTORE__': JSON.stringify(config.PAVICS_GEOSERVER_CUSTOM_DATASTORE), }; // ------------------------------------ // Validate Vendor Dependencies diff --git a/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js b/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js index ec8a23d..1dabb60 100644 --- a/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js +++ b/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js @@ -128,8 +128,8 @@ class WidgetDrawFeatures extends React.Component { }; onUploadFromDisk = event => { - const workspace = "CUSTOM_SHAPEFILES"; - const datastore = 'CUSTOM_SHAPEFILES_DS'; // ' USER_SHAPEFILES'; + const workspace = __PAVICS_GEOSERVER_CUSTOM_WORKSPACE__; + const datastore = __PAVICS_GEOSERVER_CUSTOM_DATASTORE__; var blobData = new Blob([this.state.file], {type: 'application/zip'}); this.props.layerCustomFeatureActions.uploadZipShapefiles(workspace, datastore, this.state.fileName, [blobData]); this.setState({ diff --git a/src/redux/modules/LayerCustomFeature.js b/src/redux/modules/LayerCustomFeature.js index f715eac..0084f7e 100644 --- a/src/redux/modules/LayerCustomFeature.js +++ b/src/redux/modules/LayerCustomFeature.js @@ -76,7 +76,7 @@ function createDownloadZipShapefile (filename) { }; } -function createUploadZipShapefile (fileName, workspace = 'CUSTOM_SHAPEFILES', datastore = 'CUSTOM_SHAPEFILES_DS') { +function createUploadZipShapefile (fileName, workspace = __PAVICS_GEOSERVER_CUSTOM_WORKSPACE__, datastore = __PAVICS_GEOSERVER_CUSTOM_DATASTORE__) { return function (dispatch, getState) { const geoJSON = getState().layerCustomFeature.geoJSONDrawnFeatures; let blobDataArray = []; From c043ab0d7da639dc2029af1d784476ee1fb7f3b5 Mon Sep 17 00:00:00 2001 From: Renaud009 Date: Thu, 25 Oct 2018 20:22:17 +0100 Subject: [PATCH 13/15] Reactivate Cesium prototype --- .../OLBasemapRenderer/OLBasemapRenderer.js | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/containers/OLBasemapRenderer/OLBasemapRenderer.js b/src/containers/OLBasemapRenderer/OLBasemapRenderer.js index 534d9c3..8b72022 100644 --- a/src/containers/OLBasemapRenderer/OLBasemapRenderer.js +++ b/src/containers/OLBasemapRenderer/OLBasemapRenderer.js @@ -11,13 +11,12 @@ import OSM from 'ol/source/OSM'; // TODO: Cesium shouldn't be a basemap option eventually, should be switch 2d/3d with both same basemaps as options // TODO: Couple more basemap options could be interesting and free to implement (OSM Positron, OSM Landscape, OSM B&W, OSM Mapnik) // TODO: 3D Cesium visualisation also mean that multiple projection options aren't urgent anymore (https://github.com/Ouranosinc/PAVICS-frontend/issues/110) -// COMMENTED CESIUM -/*import Cesium from 'cesium/Cesium'; +import Cesium from 'cesium/Cesium'; window['Cesium'] = Cesium; // expose Cesium to the OL-Cesium library require('cesium/Widgets/widgets.css'); import OLCesium from 'ol-cesium'; Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI4NzJmNzQ5YS1iY2JlLTQwOGYtODlhNS04Yzc2YzRmOWY5YWMiLCJpZCI6Mzc0MCwic2NvcGVzIjpbImFzbCIsImFzciIsImdjIl0sImlhdCI6MTUzODY2NDcwNH0.02vOjG7j1kh75VjgRWn6fUq4ulyPK2IZbFhdyx0SCcE'; -*/ + const G_BING_API_KEY = 'AtXX65CBBfZXBxm6oMyf_5idMAMI7W6a5GuZ5acVcrYi6lCQayiiBz7_aMHB7JR7'; @@ -33,8 +32,7 @@ export class OLBasemapRenderer extends React.Component { super(props); this.source = null; this.layer = null; - // COMMENTED CESIUM - /*this.ol3d = null;*/ + this.ol3d = null; } componentWillReceiveProps (nextProps) { @@ -50,9 +48,8 @@ export class OLBasemapRenderer extends React.Component { init(map) { this.source = new OSM(); - // COMMENTED CESIUM - /*this.ol3d = new OLCesium({map: map}); - this.ol3d.setEnabled(false);*/ + this.ol3d = new OLCesium({map: map}); + this.ol3d.setEnabled(false); } resetBasemap(map, layerBasemap) { @@ -61,14 +58,12 @@ export class OLBasemapRenderer extends React.Component { } if (layerBasemap.selectedBasemap === 'Cesium') { // TODO: Cesium shouldn't be a basemap option eventually - // COMMENTED CESIUM - /*this.layer = this.addCesiumTileLayer(map, layerBasemap.selectedBasemap); + this.layer = this.addCesiumTileLayer(map, layerBasemap.selectedBasemap); let scene = this.ol3d.getCesiumScene(); scene.terrainProvider = Cesium.createWorldTerrain(); - this.ol3d.setEnabled(true);*/ + this.ol3d.setEnabled(true); } else { - // COMMENTED CESIUM - // this.ol3d.setEnabled(false); + this.ol3d.setEnabled(false); this.layer = this.addBingLayer(map, layerBasemap.selectedBasemap, layerBasemap.selectedBasemap); } } From ec0e2ed3e327830dd8e03a5b66249a2ac832e698 Mon Sep 17 00:00:00 2001 From: Renaud009 Date: Thu, 25 Oct 2018 20:36:07 +0100 Subject: [PATCH 14/15] Removed FIXME comments --- src/components/CustomIconMenu/CustomIconMenu.js | 2 +- src/components/ProcessMonitoring/ProcessMonitoring.js | 2 +- src/components/WidgetDrawFeatures/WidgetDrawFeatures.js | 3 --- src/components/WpsProcessForm/WpsProcessForm.js | 2 +- src/containers/OLDrawFeatures/OLDrawFeatures.js | 4 +--- src/containers/OLRegionsSelector/OLRegionsSelector.js | 2 +- src/routes/Pavics/containers/Pavics.js | 2 +- 7 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/components/CustomIconMenu/CustomIconMenu.js b/src/components/CustomIconMenu/CustomIconMenu.js index 9bfef8f..2b564bd 100644 --- a/src/components/CustomIconMenu/CustomIconMenu.js +++ b/src/components/CustomIconMenu/CustomIconMenu.js @@ -17,7 +17,7 @@ const styles = theme => ({ Should be used in most one-level lists containing IconButton actions menu Do not use in nested list since calling current methods(mostly onMenuClosed()) from parent with onRef strategy will be a nightmare to manage See ProjectSearchCriterias component for a taste - FIXME: Ideally onMenuClosed() should be called after any children MenuItem.onClick event + TODO: Ideally onMenuClosed() should be called after any children MenuItem.onClick event */ export class CustomIconMenu extends React.Component { static propTypes = { diff --git a/src/components/ProcessMonitoring/ProcessMonitoring.js b/src/components/ProcessMonitoring/ProcessMonitoring.js index 1c9e4f8..74e08b2 100644 --- a/src/components/ProcessMonitoring/ProcessMonitoring.js +++ b/src/components/ProcessMonitoring/ProcessMonitoring.js @@ -206,7 +206,7 @@ class ProcessMonitoring extends React.Component { let newOutputs = []; parralelTask.outputs.forEach(output => { newOutputs = []; - // FIXME: No idea ATM why output.data is sometimes parsed sometimes not + // TODO: No idea ATM why output.data is sometimes parsed sometimes not if(output.mimeType === 'application/json' && typeof output.data === 'string') { output.data = JSON.parse(output.data); } diff --git a/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js b/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js index 1dabb60..babf28e 100644 --- a/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js +++ b/src/components/WidgetDrawFeatures/WidgetDrawFeatures.js @@ -80,9 +80,6 @@ class WidgetDrawFeatures extends React.Component { this.props.layerCustomFeatureActions.resetGeoJSONDrawnFeatures(); }; - /* - FIXME: Only one geometry by shapefile at the moment - */ onDownloadDrawnLayer = () => { this.props.layerCustomFeatureActions.createDownloadZipShapefile(this.state.regionIdentifier); }; diff --git a/src/components/WpsProcessForm/WpsProcessForm.js b/src/components/WpsProcessForm/WpsProcessForm.js index 23dc5ff..73532e0 100644 --- a/src/components/WpsProcessForm/WpsProcessForm.js +++ b/src/components/WpsProcessForm/WpsProcessForm.js @@ -143,7 +143,7 @@ export default class WpsProcessForm extends React.Component { if (oldProps.layerRegion && oldProps.layerRegion.selectedFeatureLayer && oldProps.layerRegion.selectedFeatureLayer['wmsParams'] && oldProps.layerRegion.selectedFeatureLayer['wmsParams']['LAYERS']) { changedState[inputName] = ''; - // FIXME: empty selectedRegions array since value won't fit anymore + // TODO: empty selectedRegions array since value won't fit anymore } } } diff --git a/src/containers/OLDrawFeatures/OLDrawFeatures.js b/src/containers/OLDrawFeatures/OLDrawFeatures.js index 4856c8f..d6460f9 100644 --- a/src/containers/OLDrawFeatures/OLDrawFeatures.js +++ b/src/containers/OLDrawFeatures/OLDrawFeatures.js @@ -127,7 +127,6 @@ class OLDrawFeatures extends React.Component { }); // Activate hand cursor when underlying event - // FIXME: Interfer with public regions layer selections map.on('pointermove', function(e) { if (e.dragging) return; let hit = map.hasFeatureAtPixel(map.getEventPixel(e.originalEvent)); @@ -136,7 +135,6 @@ class OLDrawFeatures extends React.Component { map.addInteraction(this.select); this.select.on('select', (e) => { - //FIXME: Not the right place to valid current layer is the good one, but it would be possible here if (e.selected.length) { // If properties.drawn exist it's because feature is part of out layer const properties = e.selected[0].getProperties(); @@ -206,7 +204,7 @@ class OLDrawFeatures extends React.Component { drawType = 'Circle'; condition = shiftKeyOnly; break; - // FIXME: Not working as expected, but should be fixed eventually + // TODO: Not working as expected, but should be fixed eventually /*case VISUALIZE_DRAW_MODES.POINT.value: geometryFunction = null; drawType = VISUALIZE_DRAW_MODES.POINT.value; diff --git a/src/containers/OLRegionsSelector/OLRegionsSelector.js b/src/containers/OLRegionsSelector/OLRegionsSelector.js index 85bc69b..de4689d 100644 --- a/src/containers/OLRegionsSelector/OLRegionsSelector.js +++ b/src/containers/OLRegionsSelector/OLRegionsSelector.js @@ -142,7 +142,7 @@ export class OLRegionsSelector extends React.Component { queryGeoserverFeatures = (extent, projection = 'EPSG:3857') => { if (this.props.layerRegion.selectedFeatureLayer && this.props.layerRegion.selectedFeatureLayer.wmsParams) { const url = `${__PAVICS_GEOSERVER_PATH__}/wfs?service=WFS&version=1.1.0&request=GetFeature&typename=${this.props.layerRegion.selectedFeatureLayer.wmsParams.LAYERS}&outputFormat=application/json&srsname=${projection}&bbox=${extent},${projection}`; - // FIXME: Move call to redux region Duck + // TODO: Move this call to redux region Duck myHttp.get(url) .then( response => response.json(), diff --git a/src/routes/Pavics/containers/Pavics.js b/src/routes/Pavics/containers/Pavics.js index 95b23f5..71ce6e1 100644 --- a/src/routes/Pavics/containers/Pavics.js +++ b/src/routes/Pavics/containers/Pavics.js @@ -157,7 +157,7 @@ class Pavics extends React.Component { triggerOnProjectCreatedActions(props) { if (props.projectAPI.items.length) { let project = props.projectAPI.items[props.projectAPI.items.length - 1]; - // FIXME, project-api should return project containing permissions, always + // TODO, project-api should return project containing permissions, always project.permissions = ["read", "write"]; this.props.projectActions.setCurrentProject(project); NotificationManager.info(`Project '${project.name}' has been selected as the current project.`, 'Information', 10000); From 4f3b334d1ac0d99e85633af28f8fd070bc9fb170 Mon Sep 17 00:00:00 2001 From: Renaud009 Date: Thu, 25 Oct 2018 21:01:34 +0100 Subject: [PATCH 15/15] v1.1.8 --- Dockerfile | 4 ++-- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4e9c810..7dd2c22 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,9 @@ # PAVICS-Platform # -# VERSION 1.1.7 +# VERSION 1.1.8 FROM node:8.2.1 MAINTAINER Renaud Hébert-Legault -LABEL Description="PAVICS Platform - Based on Node.js, React, Redux, Webpack, OpenLayers, Koa and MaterialUI" Vendor="CRIM" Version="1.1.7" +LABEL Description="PAVICS Platform - Based on Node.js, React, Redux, Webpack, OpenLayers, Koa and MaterialUI" Vendor="CRIM" Version="1.1.8" WORKDIR /frontend ENV NODE_ENV=development diff --git a/package-lock.json b/package-lock.json index 5c076aa..8356618 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "pavics-frontend", - "version": "1.1.7", + "version": "1.1.8", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 9f8e1b3..211ac30 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pavics-frontend", - "version": "1.1.7", + "version": "1.1.8", "description": "PAVICS", "main": "index.js", "engines": {