Add a new plugin extension
This section shows how to add a plugin using the extension support in MapStore without re-compilation of the bundle of the geonode-mapstore-cient applications. This new extensibility should be used for simple plugins.
Setup extension
Navigate to the /opt/geonode-project/my_geonode/src/my_geonode/
directory
cd /opt/geonode-project/my_geonode/src/my_geonode/
Run the create script using the mapstore project
npx @mapstore/project create extension
These are the properties requested by the create script. MyGeoNodeExtension is the name of the extension and it should be a unique identifier
- Name of extension (default Extension): MyGeoNodeExtension
- Name of project (default mapstore-extension): client
- Run npm install after creation setup (yes/no default yes): no
Create an index.json file inside the /opt/geonode-project/my_geonode/src/my_geonode/static/mapstore/extensions
directory
mkdir /opt/geonode-project/my_geonode/src/my_geonode/static/mapstore
mkdir /opt/geonode-project/my_geonode/src/my_geonode/static/mapstore/extensions
touch /opt/geonode-project/my_geonode/src/my_geonode/static/mapstore/extensions/index.json
/opt/geonode-project/my_geonode/src/
|-- ...
|-- my_geonode/
| |-- ...
| |-- client/
| +-- static/
| |-- ...
| +-- mapstore/
| |-- ...
| +-- extensions/
| |-- ...
| +-- index.json
|-- ...
Configure the extensions/index.json
file to include the new extension
vim /opt/geonode-project/my_geonode/src/my_geonode/static/mapstore/extensions/index.json
Paste this configuration inside the index.json
{
"MyGeoNodeExtension": {
"bundle": "MyGeoNodeExtension/index.js",
"translations": "MyGeoNodeExtension/translations",
"assets": "MyGeoNodeExtension/assets"
}
}
Navigate to the extension client folder
cd /opt/geonode-project/my_geonode/src/my_geonode/client/
Add license file if missing LICENSE.txt
Add the postCompile.js
script file to move the compiled bundle in the correct directory
touch /opt/geonode-project/my_geonode/src/my_geonode/client/postCompile.js
vim /opt/geonode-project/my_geonode/src/my_geonode/client/postCompile.js
const fs = require('fs-extra');
const path = require('path');
const extensionsPath = path.join(__dirname, '..', 'static', 'mapstore', 'extensions');
const extensionIndexPath = path.join(extensionsPath, 'index.json');
const extensionIndex = fs.existsSync(extensionIndexPath) ? require(extensionIndexPath) : {};
const EXTENSION_NAME = 'MyGeoNodeExtension';
let error = false;
Object.keys(extensionIndex).forEach(extensionName => {
const endpoints = extensionIndex[extensionName];
Object.keys(endpoints).forEach(key => {
if (endpoints[key].match('http://localhost:8082/extension')) {
error = true;
console.error('');
console.error('//////////////////////////////////////');
console.error('/// Error: dev url ' + key + ': ' + endpoints[key]);
console.error('/// -> please replace http://localhost:8082/extension with /static/mapstore/extensions/' + extensionName);
console.error('//////////////////////////////////////');
console.error('');
}
});
});
if (!error) {
fs.moveSync(path.resolve(__dirname, 'dist'), path.resolve(extensionsPath, EXTENSION_NAME), { overwrite: true });
}
Modify the package.json to use the new postCompile.js script and to target the mapstore version 2022.01.xx.
vim /opt/geonode-project/my_geonode/src/my_geonode/client/package.json
"scripts": {
- "compile": "mapstore-project compile extension",
+ "compile": "mapstore-project compile extension && node ./postCompile.js",
"lint": "eslint js --ext .jsx,.js",
"start": "mapstore-project start extension",
"test": "mapstore-project test extension",
"test:watch": "mapstore-project test:watch extension"
},
...
"dependencies": {
- "mapstore": "git+https://github.com/geosolutions-it/MapStore2.git#master"
+ "mapstore": "git+https://github.com/geosolutions-it/MapStore2.git#2022.01.xx"
},
Install all needed dependencies
cd /opt/geonode-project/my_geonode/src/my_geonode/client/
npm install
Compile the bundle to verify if all the scripts are configured correctly
cd /opt/geonode-project/my_geonode/src/my_geonode/client/
npm run compile
After the compile command executes, a new folder is generated inside the extensions directory
/opt/geonode-project/my_geonode/src/
|-- ...
|-- my_geonode/
| |-- ...
| +-- static/
| |-- ...
| +-- mapstore/
| |-- ...
| +-- extensions/
| |-- MyGeoNodeExtension/
| +-- index.json
|-- ...
Edit the /opt/geonode-project/my_geonode/src/my_geonode/templates/geonode-mapstore-client/_geonode_config.html
template to include this new extension
vim /opt/geonode-project/my_geonode/src/my_geonode/templates/geonode-mapstore-client/_geonode_config.html
<!-- _geonode_config.html file in the my_geonode project -->
{% extends 'geonode-mapstore-client/_geonode_config.html' %}
{% block override_local_config %}
<script>
window.__GEONODE_CONFIG__.overrideLocalConfig = function(localConfig) {
localConfig.plugins.map_viewer.push({ "name": "MyGeoNodeExtension" });
return localConfig;
};
</script>
{% endblock %}
After these steps a box with a message is visible on the map viewer.
Develop the extension
Temporarily edit the /opt/geonode-project/my_geonode/src/my_geonode/static/mapstore/extensions/index.json
file using the dev endpoints instead of the static ones (remember to restore this value to the static one)
vim /opt/geonode-project/my_geonode/src/my_geonode/static/mapstore/extensions/index.json
{
"MyGeoNodeExtension": {
"bundle": "http://localhost:8082/extension/index.js",
"assets": "http://localhost:8082/extension/assets",
"translations": "http://localhost:8082/extension/translations"
}
}
Add the development configuration to the /opt/geonode-project/my_geonode/src/my_geonode/templates/geonode-mapstore-client/_geonode_config.html
template
vim /opt/geonode-project/my_geonode/src/my_geonode/templates/geonode-mapstore-client/_geonode_config.html
{% extends 'geonode-mapstore-client/_geonode_config.html' %}
{% block override_local_config %}
<script>
window.__GEONODE_CONFIG__.overrideLocalConfig = function(localConfig) {
localConfig.plugins.map_viewer.push({ "name": "MyGeoNodeExtension" });
+ // IMPORTANT!!! REMOVE AFTER DEVELOPMENT
+ // temporary changes to develop extension
+ // use absolute extensions folder path to correctly get http://localhost:8082 endpoint
+ localConfig.extensionsFolder = '';
+ // ensure that the http://localhost:8082 endpoint will not use proxy but direct requests
+ localConfig.proxyUrl.useCORS.push('http://localhost:8082');
return localConfig;
};
</script>
{% endblock %}
Navigate to the /opt/geonode-project/my_geonode/src/my_geonode/client/
folder and start the extension endpoints
cd /opt/geonode-project/my_geonode/src/my_geonode/client/
npm start
Replace the content of the /opt/geonode-project/my_geonode/src/my_geonode/client/js/extension/plugins/Extension.jsx
with a new extension. An example could be a floating box that shows the value of the center of the map
vim /opt/geonode-project/my_geonode/src/my_geonode/client/js/extension/plugins/Extension.jsx
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { mapSelector } from '@mapstore/framework/selectors/map';
function MyGeoNodeExtension({
center
}) {
return (
<div
className="shadow"
style={{
position: 'absolute',
zIndex: 100,
bottom: 35,
margin: 8,
left: '50%',
backgroundColor: '#ffffff',
padding: 8,
textAlign: 'center',
transform: 'translateX(-50%)'
}}
>
<div>
<small>
Map Center ({center.crs})
</small>
</div>
<div>
x: <strong>{center?.x?.toFixed(6)}</strong>
{' | '}
y: <strong>{center?.y?.toFixed(6)}</strong>
</div>
</div>
);
}
MyGeoNodeExtension.propTypes = {
center: PropTypes.object
};
MyGeoNodeExtension.defaultProps = {
center: {}
};
const MyGeoNodeExtensionPlugin = connect(
createSelector([
mapSelector
], (map) => ({
center: map?.center
})),
{}
)(MyGeoNodeExtension);
export default {
name: __MAPSTORE_EXTENSION_CONFIG__.name,
component: MyGeoNodeExtensionPlugin,
containers: {},
epics: {},
reducers: {}
};
Build the extension
Restore the /opt/geonode-project/my_geonode/src/my_geonode/static/mapstore/extensions/index.json
points to MyGeoNodeExtension
static path for the extension
vim /opt/geonode-project/my_geonode/src/my_geonode/static/mapstore/extensions/index.json
{
"MyGeoNodeExtension": {
"bundle": "MyGeoNodeExtension/index.js",
"assets": "MyGeoNodeExtension/assets",
"translations": "MyGeoNodeExtension/translations"
}
}
Remove the development configuration from the _geonode_config.html
template
vim /opt/geonode-project/my_geonode/src/my_geonode/templates/geonode-mapstore-client/_geonode_config.html
{% extends 'geonode-mapstore-client/_geonode_config.html' %}
{% block override_local_config %}
<script>
window.__GEONODE_CONFIG__.overrideLocalConfig = function(localConfig) {
localConfig.plugins.map_viewer.push({ "name": "MyGeoNodeExtension" });
- // IMPORTANT!!! REMOVE AFTER DEVELOPMENT
- // temporary changes to develop extension
- // use absolute extensions folder path to correctly get http://localhost:8082 endpoint
- localConfig.extensionsFolder = '';
- // ensure that the http://localhost:8082 endpoint will not use proxy but direct requests
- localConfig.proxyUrl.useCORS.push('http://localhost:8082');
return localConfig;
};
</script>
{% endblock %}
Compile the bundle
cd /opt/geonode-project/my_geonode/src/my_geonode/client/
npm run compile
Now the new extension will be available in the map_viewer page with the changes applied during the development