Skip to content

Commit

Permalink
#4720 - #4719 User Extensions - TOC plugins (#4723)
Browse files Browse the repository at this point in the history
  • Loading branch information
offtherailz authored Jan 17, 2020
1 parent febc757 commit 4525991
Show file tree
Hide file tree
Showing 23 changed files with 649 additions and 117 deletions.
11 changes: 11 additions & 0 deletions web/client/actions/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,14 @@ export const CLEAR_CONTEXT = 'CONTEXT:CLEAR_CONTEXT';
* Clears current context state
*/
export const clearContext = () => ({ type: CLEAR_CONTEXT });

export const UPDATE_USER_PLUGIN = "CONTEXT:UPDATE_USER_PLUGIN";
/**
* Updates a value for a user plugin. It can be used to activate/deactivate user plugins, or to set specific
* properties.
* @param {string} name the name of the plugin
* @param {object} values key-values map to update.
* @example
* updateUserPlugin("Annotations", {active: true})
*/
export const updateUserPlugin = (name, values) => ({ type: UPDATE_USER_PLUGIN, name, values});
2 changes: 1 addition & 1 deletion web/client/examples/featuregrid/plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module.exports = {
LayerSelectorPlugin: require('./plugins/LayerSelector'),
MapPlugin: require('../../plugins/Map'),
WFSDownload: require('../../plugins/WFSDownload'),
FeatureEditor: require('../../plugins/FeatureEditor'),
FeatureEditor: require('../../plugins/FeatureEditor').default,
QueryPanel: require('../../plugins/QueryPanel'),
Notifications: require('../../plugins/Notifications')
},
Expand Down
13 changes: 3 additions & 10 deletions web/client/localConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,17 +342,10 @@
}, {
"name": "TOC",
"cfg": {
"activateQueryTool": true,
"activateAddLayerButton": true,
"activateAddGroupButton": true,
"activateMetedataTool": false,
"addLayersPermissions": true,
"removeLayersPermissions": true,
"sortingPermissions": true,
"addGroupsPermissions": true,
"removeGroupsPermissions": true
"activateMetedataTool": false
}
},
"FilterLayer",
"AddGroup",
"TOCItemsSettings",
"Tutorial", "MapFooter", {
Expand Down Expand Up @@ -632,7 +625,7 @@
}, "Login", "Language", "NavMenu", "DashboardSave", "DashboardSaveAs", "Attribution", "Home", {
"name": "DashboardEditor",
"cfg": {
"catalog": {
"catalog": {
"url": "https://gs-stable.geo-solutions.it/geoserver/csw",
"type": "csw",
"title": "GeoSolutions GeoServer CSW",
Expand Down
13 changes: 12 additions & 1 deletion web/client/plugins/AddGroup.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,17 @@ const AddGroupPlugin = connect((state) => ({
onAdd: addGroup
})(AddGroup);

/**
* AddGrouo. Add to the TOC the possibility to add layer group.
* @memberof plugins
* @requires plugins.TOC
*/
export default createPlugin('AddGroup', {
component: AddGroupPlugin
component: AddGroupPlugin,
containers: {
TOC: {
doNotHide: true,
name: "AddGroup"
}
}
});
60 changes: 37 additions & 23 deletions web/client/plugins/FeatureEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,33 @@
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
const React = require('react');
const {connect} = require('react-redux');
const {createSelector, createStructuredSelector} = require('reselect');
const {bindActionCreators} = require('redux');
const { get, pick } = require('lodash');
import React from 'react';
import {connect} from 'react-redux';
import {createSelector, createStructuredSelector} from 'reselect';
import {bindActionCreators} from 'redux';
import { get, pick } from 'lodash';
import {compose, lifecycle} from 'recompose';
import ReactDock from 'react-dock';

const {compose, lifecycle} = require('recompose');
const Grid = require('../components/data/featuregrid/FeatureGrid');
const {paginationInfo, describeSelector, wfsURLSelector, typeNameSelector} = require('../selectors/query');
const {modeSelector, changesSelector, newFeaturesSelector, hasChangesSelector, selectedFeaturesSelector, getDockSize} = require('../selectors/featuregrid');
const { toChangesMap} = require('../utils/FeatureGridUtils');
const {getPanels, getHeader, getFooter, getDialogs, getEmptyRowsView, getFilterRenderers} = require('./featuregrid/panels/index');
const BorderLayout = require('../components/layout/BorderLayout');
import { createPlugin } from '../utils/PluginsUtils';

import * as epics from '../epics/featuregrid';
import * as featuregrid from '../reducers/featuregrid';

import Grid from '../components/data/featuregrid/FeatureGrid';
import {paginationInfo, describeSelector, wfsURLSelector, typeNameSelector} from '../selectors/query';
import {modeSelector, changesSelector, newFeaturesSelector, hasChangesSelector, selectedFeaturesSelector, getDockSize} from '../selectors/featuregrid';
import { toChangesMap} from '../utils/FeatureGridUtils';
import {getPanels, getHeader, getFooter, getDialogs, getEmptyRowsView, getFilterRenderers} from './featuregrid/panels/index';
import BorderLayout from '../components/layout/BorderLayout';
const EMPTY_ARR = [];
const EMPTY_OBJ = {};
const {gridTools, gridEvents, pageEvents, toolbarEvents} = require('./featuregrid/index');
const { initPlugin, sizeChange, setUp} = require('../actions/featuregrid');
const ContainerDimensions = require('react-container-dimensions').default;
const {mapLayoutValuesSelector} = require('../selectors/maplayout');
import {gridTools, gridEvents, pageEvents, toolbarEvents} from './featuregrid/index';
import { initPlugin, sizeChange, setUp} from '../actions/featuregrid';
import ContainerDimensions from 'react-container-dimensions';
import {mapLayoutValuesSelector} from '../selectors/maplayout';


const Dock = connect(createSelector(
getDockSize,
state => mapLayoutValuesSelector(state, {transform: true}),
Expand All @@ -32,7 +40,7 @@ const Dock = connect(createSelector(
dockStyle
})
)
)(require('react-dock').default);
)(ReactDock);
/**
* @name FeatureEditor
* @memberof plugins
Expand Down Expand Up @@ -242,11 +250,17 @@ const EditorPlugin = compose(
})
)(FeatureDock);


module.exports = {
FeatureEditorPlugin: EditorPlugin,
epics: require('../epics/featuregrid'),
export default createPlugin('FeatureEditor', {
component: EditorPlugin,
epics,
reducers: {
featuregrid: require('../reducers/featuregrid')
featuregrid
},
containers: {
TOC: {
doNotHide: true,
name: "FeatureEditor"
}
}
};
});

29 changes: 29 additions & 0 deletions web/client/plugins/FilterLayer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2019, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

import { createPlugin } from '../utils/PluginsUtils';

// dummy plugin
const FilterLayer = () => null;

/**
* Plugin that activate the FilterLayer button in the TOC.
* Requires the QueryPanel Plugin To Work
* @memberof plugins
* @requires plugins.QueryPanel
*/
export default createPlugin('FilterLayer',
{
component: FilterLayer,
containers: {
TOC: {
name: "FilterLayer"
}
}
}
);
17 changes: 4 additions & 13 deletions web/client/plugins/MetadataExplorer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -252,25 +252,16 @@ const API = {
*/
module.exports = {
MetadataExplorerPlugin: assign(MetadataExplorerPlugin, {
Toolbar: {
name: 'metadataexplorer',
position: 10,
exclusive: true,
panel: true,
tooltip: "catalog.tooltip",
wrap: true,
title: 'catalog.title',
help: <Message msgId="helptexts.metadataexplorer"/>,
icon: <Glyphicon glyph="folder-open" />,
priority: 1
},
BurgerMenu: {
name: 'metadataexplorer',
position: 5,
text: <Message msgId="catalog.title"/>,
icon: <Glyphicon glyph="folder-open"/>,
action: setControlProperty.bind(null, "metadataexplorer", "enabled", true, true),
priority: 2,
doNotHide: true
},
TOC: {
name: 'MetadataExplorer',
doNotHide: true
}
}),
Expand Down
106 changes: 82 additions & 24 deletions web/client/plugins/TOC.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const PropTypes = require('prop-types');
const React = require('react');
const {connect} = require('react-redux');
const {createSelector} = require('reselect');
const { compose, branch, withPropsOnChange} = require('recompose');

const {Glyphicon} = require('react-bootstrap');

const {changeLayerProperties, changeGroupProperties, toggleNode, contextNode,
Expand All @@ -35,7 +37,7 @@ const assign = require('object-assign');

const layersIcon = require('./toolbar/assets/img/layers.png');

const {isObject, head} = require('lodash');
const {isObject, head, find} = require('lodash');

const { setControlProperties} = require('../actions/controls');
const {createWidget} = require('../actions/widgets');
Expand Down Expand Up @@ -144,6 +146,7 @@ const DefaultLayerOrGroup = require('../components/TOC/DefaultLayerOrGroup');
class LayerTree extends React.Component {
static propTypes = {
id: PropTypes.number,
items: PropTypes.array,
buttonContent: PropTypes.node,
groups: PropTypes.array,
settings: PropTypes.object,
Expand Down Expand Up @@ -227,6 +230,7 @@ class LayerTree extends React.Component {
};

static defaultProps = {
items: [],
groupPropertiesChangeHandler: () => {},
layerPropertiesChangeHandler: () => {},
retrieveLayerData: () => {},
Expand Down Expand Up @@ -258,7 +262,7 @@ class LayerTree extends React.Component {
activateQueryTool: true,
activateDownloadTool: false,
activateWidgetTool: false,
activateLayerFilterTool: true,
activateLayerFilterTool: false,
maxDepth: 3,
visibilityCheckType: "glyph",
settingsOptions: {
Expand Down Expand Up @@ -479,28 +483,78 @@ class LayerTree extends React.Component {
}
}

const securityEnhancer = (Component) => (props) => {
const { addLayersPermissions = true,
removeLayersPermissions = true,
sortingPermissions = true,
addGroupsPermissions = true,
removeGroupsPermissions = true, user, ...other} = props;
/**
* enhances the TOC to check `Permissions` properties and enable/disable
* the proper tools.
* @memberof plugins.TOC
*/
const securityEnhancer = withPropsOnChange(
[
"user",
"addLayersPermissions", "activateAddLayerButton",
"removeLayersPermissions", "activateRemoveLayer",
"sortingPermission", "activateRemoveLayer",
"addGroupsPermissions", "activateAddGroupButton",
"removeGroupsPermissions", "activateRemoveGroup"
],
(props) => {
const {
addLayersPermissions = true,
removeLayersPermissions = true,
sortingPermissions = true,
addGroupsPermissions = true,
removeGroupsPermissions = true,
activateAddLayerButton,
activateRemoveLayer,
activateSortLayer,
activateAddGroupButton,
activateRemoveGroup,
user
} = props;

const activateParameter = (allow, activate) => {
const isUserAdmin = user && user.role === 'ADMIN' || false;
return (allow || isUserAdmin) ? activate : false;
};
const activateParameter = (allow, activate) => {
const isUserAdmin = user && user.role === 'ADMIN' || false;
return (allow || isUserAdmin) ? activate : false;
};

const activateProps = {
activateAddLayerButton: activateParameter(addLayersPermissions, props.activateAddLayerButton),
activateRemoveLayer: activateParameter(removeLayersPermissions, props.activateRemoveLayer),
activateSortLayer: activateParameter(sortingPermissions, props.activateSortLayer),
activateAddGroupButton: activateParameter(addGroupsPermissions, props.activateAddGroupButton),
activateRemoveGroup: activateParameter(removeGroupsPermissions, props.activateRemoveGroup)
};
return {
activateAddLayerButton: activateParameter(addLayersPermissions, activateAddLayerButton),
activateRemoveLayer: activateParameter(removeLayersPermissions, activateRemoveLayer),
activateSortLayer: activateParameter(sortingPermissions, activateSortLayer),
activateAddGroupButton: activateParameter(addGroupsPermissions, activateAddGroupButton),
activateRemoveGroup: activateParameter(removeGroupsPermissions, activateRemoveGroup)
};
});

return <Component {...other} {...activateProps}/>;
};

/**
* enhances the TOC to check the presence of TOC plugins to display/add buttons to the toolbar.
* NOTE: the flags are required because of old configurations about permissions.
* TODO: delegate button rendering and actions to the plugins (now this is only a check and some plugins are dummy, only to allow plug/unplug). Also permissions should be delegated to the related plugins
* @memberof plugins.TOC
*/
const checkPluginsEnhancer = branch(
({ checkPlugins = true }) => checkPlugins,
withPropsOnChange(
["items", "activateAddLayerButton", "activateAddGroupButton", "activateLayerFilterTool", "activateSettingsTool", "FeatureEditor"],
({
items = [],
activateAddLayerButton = true,
activateAddGroupButton = true,
activateQueryTool = true,
activateSettingsTool = true,
activateLayerFilterTool = true,
activateWidgetTool = true
}) => ({
activateAddLayerButton: activateAddLayerButton && !!find(items, { name: "MetadataExplorer" }) || false, // requires MetadataExplorer (Catalog)
activateAddGroupButton: activateAddGroupButton && !!find(items, { name: "AddGroup" }) || false,
activateSettingsTool: activateSettingsTool && !!find(items, { name: "TOCItemsSettings"}) || false,
activateQueryTool: activateQueryTool && !!find(items, {name: "FeatureEditor"}) || false,
activateLayerFilterTool: activateLayerFilterTool && !!find(items, {name: "FilterLayer"}) || false,
activateWidgetTool: activateWidgetTool && !!find(items, { name: "WidgetBuilder" }) // NOTE: activateWidgetTool is already controlled by a selector. TODO: Simplify investigating on the best approch
})
)
);


/**
Expand All @@ -520,8 +574,9 @@ const securityEnhancer = (Component) => (props) => {
* @prop {boolean} cfg.activateQueryTool: activate query tool options, default `false`
* @prop {boolean} cfg.activateDownloadTool: activate a button to download layer data through wfs, default `false`
* @prop {boolean} cfg.activateSortLayer: activate drag and drop to sort layers, default `true`
* @prop {boolean} cfg.activateAddLayerButton: activate a button to open the catalog, default `false`
* @prop {boolean} cfg.activateAddGroupButton: activate a button to add a new group, default `false`
* @prop {boolean} cfg.checkPlugins if true, check if AddLayer, AddGroup ... plugins are present to auto-configure the toolbar
* @prop {boolean} cfg.activateAddLayerButton: activate a button to open the catalog, default `true`
* @prop {boolean} cfg.activateAddGroupButton: activate a button to add a new group, default `true`
* @prop {boolean} cfg.showFullTitleOnExpand shows full length title in the legend. default `false`.
* @prop {boolean} cfg.hideOpacityTooltip hide toolip on opacity sliders
* @prop {string[]|string|object|function} cfg.metadataTemplate custom template for displaying metadata
Expand Down Expand Up @@ -644,7 +699,10 @@ const TOCPlugin = connect(tocSelector, {
hideLayerMetadata,
onNewWidget: () => createWidget(),
refreshLayerVersion
})(securityEnhancer(LayerTree));
})(compose(
securityEnhancer,
checkPluginsEnhancer
)(LayerTree));

const API = {
csw: require('../api/CSW'),
Expand Down
Loading

0 comments on commit 4525991

Please sign in to comment.