Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions web/client/components/data/featuregrid/toolbars/Toolbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ const standardButtons = {
visible={mode === "VIEW" && showAdvancedFilterButton}
onClick={events.showQueryPanel}
glyph="filter"/>),
zoomAll: ({disabled, disableZoomAll = false, mode, events = {}}) => (<TButton
zoomAll: ({disabled, disableZoomAll = false, mode, events = {}, hideSpatialFunctionalityTools = false}) => (<TButton
id="zoom-all"
keyProp="zoom-all"
tooltipId="featuregrid.toolbar.zoomAll"
disabled={disabled || disableZoomAll}
visible={mode === "VIEW"}
visible={mode === "VIEW" && !hideSpatialFunctionalityTools}
onClick={events.zoomAll}
glyph="zoom-to"/>),
backToViewMode: ({disabled, mode, hasChanges, hasNewFeatures, events = {}}) => (<TButton
Expand All @@ -72,12 +72,12 @@ const standardButtons = {
visible={mode === "EDIT" && !hasNewFeatures && !hasChanges && hasSupportedGeometry}
onClick={events.createFeature}
glyph="row-add"/>),
drawFeature: ({isDrawing = false, disabled, isSimpleGeom, mode, selectedCount, hasGeometry, hasSupportedGeometry = true, events = {}}) => (<TButton
drawFeature: ({isDrawing = false, disabled, isSimpleGeom, mode, selectedCount, hasGeometry, hasSupportedGeometry = true, events = {}, hideSpatialFunctionalityTools = false}) => (<TButton
id="draw-feature"
keyProp="draw-feature"
tooltipId={getDrawFeatureTooltip(isDrawing, isSimpleGeom)}
disabled={disabled}
visible={mode === "EDIT" && selectedCount === 1 && (!hasGeometry || hasGeometry && !isSimpleGeom) && hasSupportedGeometry}
visible={mode === "EDIT" && selectedCount === 1 && (!hasGeometry || hasGeometry && !isSimpleGeom) && hasSupportedGeometry && !hideSpatialFunctionalityTools}
onClick={events.startDrawingFeature}
active={isDrawing}
glyph="pencil-add"/>),
Expand Down Expand Up @@ -111,12 +111,12 @@ const standardButtons = {
visible={mode === "EDIT" && hasChanges || hasNewFeatures}
onClick={events.clearFeatureEditing}
glyph="remove-square"/>),
deleteGeometry: ({disabled, mode, hasGeometry, selectedCount, hasSupportedGeometry = true, events = {}}) => (<TButton
deleteGeometry: ({disabled, mode, hasGeometry, selectedCount, hasSupportedGeometry = true, events = {}, hideSpatialFunctionalityTools = false}) => (<TButton
id="delete-geometry"
keyProp="delete-geometry"
tooltipId="featuregrid.toolbar.deleteGeometry"
disabled={disabled}
visible={mode === "EDIT" && hasGeometry && selectedCount === 1 && hasSupportedGeometry}
visible={mode === "EDIT" && hasGeometry && selectedCount === 1 && hasSupportedGeometry && !hideSpatialFunctionalityTools}
onClick={events.deleteGeometry}
glyph="polygon-trash"/>),
gridSettings: ({disabled, isColumnsOpen, selectedCount, mode, events = {}}) => (<TButton
Expand All @@ -128,13 +128,13 @@ const standardButtons = {
visible={selectedCount <= 1 && mode === "VIEW"}
onClick={events.settings}
glyph="features-grid-set"/>),
syncGridFilterToMap: ({disabled, isSyncActive = false, showSyncOnMapButton = true, events = {}, syncPopover = {}, showPopoverSync, hideSyncPopover}) => (<TButton
syncGridFilterToMap: ({disabled, isSyncActive = false, showSyncOnMapButton = true, events = {}, syncPopover = { dockSize: "32.2%" }, showPopoverSync, hideSyncPopover, hideSpatialFunctionalityTools = false}) => (<TButton
id="grid-map-filter"
keyProp="grid-map-filter"
tooltipId="featuregrid.toolbar.syncOnMap"
disabled={disabled}
active={isSyncActive}
visible={showSyncOnMapButton}
visible={showSyncOnMapButton && !hideSpatialFunctionalityTools}
onClick={events.sync}
glyph="map-filter"
renderPopover={showPopoverSync}
Expand Down Expand Up @@ -175,11 +175,11 @@ const standardButtons = {
active={timeSync}
onClick={() => events.setTimeSync && events.setTimeSync(!timeSync)}
glyph="time" />),
snapToFeature: ({snapping, availableSnappingLayers = [], isSnappingLoading, snappingConfig, mode, mapType, editorHeight, pluginCfg, events = {}}) => (<TSplitButton
snapToFeature: ({snapping, availableSnappingLayers = [], isSnappingLoading, snappingConfig, mode, mapType, editorHeight, pluginCfg, events = {}, hideSpatialFunctionalityTools = false}) => (<TSplitButton
id="snap-button"
keyProp="snap-button"
tooltipId={snapping ? "featuregrid.toolbar.disableSnapping" : "featuregrid.toolbar.enableSnapping"}
visible={mode === "EDIT" && (pluginCfg?.snapTool ?? true) && mapType === MapLibraries.OPENLAYERS}
visible={mode === "EDIT" && (pluginCfg?.snapTool ?? true) && mapType === MapLibraries.OPENLAYERS && !hideSpatialFunctionalityTools}
onClick={() => {
events.toggleSnapping && events.toggleSnapping(!snapping);
}}
Expand Down Expand Up @@ -259,11 +259,11 @@ const standardButtons = {
<span className="clearfix" />
</FormGroup>
</TSplitButton>),
viewportFilter: ({viewportFilter, isFilterByViewportSupported, pluginCfg, events = {}}) => (<TButton
viewportFilter: ({viewportFilter, isFilterByViewportSupported, pluginCfg, events = {}, hideSpatialFunctionalityTools = false}) => (<TButton
id="viewportFilter-button"
keyProp="viewportFilter-button"
tooltipId={viewportFilter ? "featuregrid.toolbar.disableViewportFilter" : "featuregrid.toolbar.enableViewportFilter"}
visible={(pluginCfg?.showFilterByViewportTool ?? true) && isFilterByViewportSupported}
visible={(pluginCfg?.showFilterByViewportTool ?? true) && isFilterByViewportSupported && !hideSpatialFunctionalityTools}
onClick={() => {
events.setViewportFilter && events.setViewportFilter(!viewportFilter);
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -456,4 +456,70 @@ describe('Featuregrid toolbar component', () => {
expect(el).toExist();
});
});
describe('hideSpatialFunctionalityTools', () => {
it('hides all spatial tools in VIEW mode when hideSpatialFunctionalityTools is true', () => {
ReactDOM.render(<Toolbar mode="VIEW" hideSpatialFunctionalityTools disableZoomAll />, document.getElementById("container"));
const el = document.getElementsByClassName("featuregrid-toolbar")[0];
expect(el).toExist();
// Check zoomAll button is hidden
expect(isVisibleButton(document.getElementById("fg-zoom-all"))).toBe(false);
// Check syncGridFilterToMap button is hidden
expect(isVisibleButton(document.getElementById("fg-grid-map-filter"))).toBe(false);
// Check viewportFilter button is hidden
expect(isVisibleButton(document.getElementById("fg-viewportFilter-button"))).toBe(false);
});
it('hides all spatial tools in EDIT mode when hideSpatialFunctionalityTools is true', () => {
ReactDOM.render(<Toolbar
mode="EDIT"
hideSpatialFunctionalityTools
mapType="openlayers"
pluginCfg={{ snapTool: true, showFilterByViewportTool: true }}
isFilterByViewportSupported
selectedCount={1}
hasGeometry
hasSupportedGeometry
disableZoomAll
/>, document.getElementById("container"));
const el = document.getElementsByClassName("featuregrid-toolbar")[0];
expect(el).toExist();
// Check drawFeature button is hidden
expect(isVisibleButton(document.getElementById("fg-draw-feature"))).toBe(false);
// Check deleteGeometry button is hidden
expect(isVisibleButton(document.getElementById("fg-delete-geometry"))).toBe(false);
// Check snapToFeature button is hidden
expect(document.getElementById("snap-button")).toNotExist();
// Check syncGridFilterToMap button is hidden
expect(isVisibleButton(document.getElementById("fg-grid-map-filter"))).toBe(false);
// Check viewportFilter button is hidden
expect(isVisibleButton(document.getElementById("fg-viewportFilter-button"))).toBe(false);
});
it('shows non-spatial tools even when hideSpatialFunctionalityTools is true', () => {
const events = {
switchEditMode: () => {},
showQueryPanel: () => {},
settings: () => {}
};
ReactDOM.render(<Toolbar
mode="VIEW"
hideSpatialFunctionalityTools
isEditingAllowed
isSearchAllowed
layer={{type: "wms", disableFeaturesEditing: false}}
selectedCount={0}
disableZoomAll
events={events}
/>, document.getElementById("container"));
const el = document.getElementsByClassName("featuregrid-toolbar")[0];
expect(el).toExist();
// Check editMode button is still visible
expect(isVisibleButton(document.getElementById("fg-edit-mode"))).toBe(true);
// Check filter button is still visible
expect(isVisibleButton(document.getElementById("fg-search"))).toBe(true);
// Check gridSettings button is still visible
expect(isVisibleButton(document.getElementById("fg-grid-settings"))).toBe(true);
// Verify spatial tools are hidden
expect(isVisibleButton(document.getElementById("fg-zoom-all"))).toBe(false);
expect(isVisibleButton(document.getElementById("fg-grid-map-filter"))).toBe(false);
});
});
});
21 changes: 16 additions & 5 deletions web/client/plugins/featuregrid/FeatureEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,20 @@ import BorderLayout from '../../components/layout/BorderLayout';
import { toChangesMap} from '../../utils/FeatureGridUtils';
import { setUp, setSyncTool } from '../../actions/featuregrid';
import {paginationInfo, describeSelector, attributesJSONSchemaSelector, wfsURLSelector, typeNameSelector, isSyncWmsActive} from '../../selectors/query';
import {modeSelector, changesSelector, newFeaturesSelector, hasChangesSelector, selectedLayerFieldsSelector, selectedFeaturesSelector} from '../../selectors/featuregrid';
import {modeSelector, changesSelector, newFeaturesSelector, hasChangesSelector, selectedLayerFieldsSelector, selectedFeaturesSelector, hasNoGeometry as hasNoGeometrySelector} from '../../selectors/featuregrid';

import {getPanels, getHeader, getFooter, getDialogs, getEmptyRowsView, getFilterRenderers} from './panels/index';
import {gridTools, gridEvents, pageEvents, toolbarEvents} from './index';
import {gridTools as defaultGridTools, gridEvents, pageEvents, toolbarEvents} from './index';
import useFeatureValidation from './hooks/useFeatureValidation';
import withResize from './hoc/withResize';

const EMPTY_ARR = [];
const EMPTY_OBJ = {};

const filterGeometryToolColumn = (tools = EMPTY_ARR, hide = false) => {
return hide ? tools.filter((t) => t?.key !== 'geometry') : tools;
};

/**
* @name FeatureEditor
* @memberof plugins
Expand Down Expand Up @@ -174,6 +178,12 @@ const Editor = (props = {
return getFilterRenderers(props.describe, props.fields, props.isWithinAttrTbl);
}, [props.describe, props.fields]);

// If the dataset has no geometry, hide the geometry tool column
const hideGeometryColumn = props?.hasNoGeometry;
const gridTools = useMemo(() =>
filterGeometryToolColumn(props.gridTools, hideGeometryColumn),
[props.gridTools, hideGeometryColumn]);

// changes compute using useMemo to reduce the re-render of the component
const changes = useMemo(() => toChangesMap(props.changes), [props.changes]);

Expand Down Expand Up @@ -228,7 +238,7 @@ const Editor = (props = {
describeFeatureType={props.describe}
features={props.features}
minHeight={600}
tools={props.gridTools}
tools={gridTools}
pagination={props.pagination}
pages={props.pages}
virtualScroll={virtualScroll}
Expand Down Expand Up @@ -273,7 +283,8 @@ export const selector = createStructuredSelector({
enableColumnFilters: state => get(state, 'featuregrid.enableColumnFilters'),
pagination: createStructuredSelector(paginationInfo),
pages: state => get(state, 'featuregrid.pages'),
size: state => get(state, 'featuregrid.pagination.size')
size: state => get(state, 'featuregrid.pagination.size'),
hasNoGeometry: hasNoGeometrySelector
});

const EditorPlugin = compose(
Expand Down Expand Up @@ -315,7 +326,7 @@ const EditorPlugin = compose(
gridEvents: bindActionCreators(gridEvents, dispatch),
pageEvents: bindActionCreators(pageEvents, dispatch),
toolbarEvents: bindActionCreators(toolbarEvents, dispatch),
gridTools: gridTools.map((t) => ({
gridTools: defaultGridTools.map((t) => ({
...t,
events: bindActionCreators(t.events, dispatch)
}))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ describe('FeatureEditor plugin component', () => {
enableColumnFilters: true,
pagination: { startIndex: undefined, maxFeatures: undefined, resultSize: undefined, totalFeatures: undefined },
pages: undefined,
size: 20
size: 20,
hasNoGeometry: true
};
it('base state', () => {
expect(BASE_EXPECTED).toEqual(BASE_EXPECTED);
Expand Down
6 changes: 4 additions & 2 deletions web/client/plugins/featuregrid/panels/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ import {
timeSyncActive,
isViewportFilterActive,
isFilterByViewportSupported,
selectedLayerSelector
selectedLayerSelector,
hasNoGeometry
} from '../../../selectors/featuregrid';
import {isCesium, mapTypeSelector} from '../../../selectors/maptype';
import {
Expand Down Expand Up @@ -103,7 +104,8 @@ const Toolbar = connect(
mapType: mapTypeSelector,
viewportFilter: isViewportFilterActive,
isFilterByViewportSupported,
layer: selectedLayerSelector
layer: selectedLayerSelector,
hideSpatialFunctionalityTools: hasNoGeometry
}),
(dispatch) => ({events: bindActionCreators(toolbarEvents, dispatch)})
)(ToolbarComp);
Expand Down
33 changes: 32 additions & 1 deletion web/client/selectors/__tests__/featuregrid-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ import {
isFilterByViewportSupported,
selectedLayerFieldsSelector,
editingAllowedGroupsSelector,
isEditingAllowedSelector
isEditingAllowedSelector,
hasNoGeometry
} from '../featuregrid';

const idFt1 = "idFt1";
Expand Down Expand Up @@ -788,4 +789,34 @@ describe('Test featuregrid selectors', () => {
})).toBeTruthy();
});
});
describe('hasNoGeometry', () => {
it('returns false when describe metadata has geometry', () => {
expect(hasNoGeometry(initialState)).toBe(false);
});
it('returns false when features contain geometry and no describe metadata', () => {
const state = {
featuregrid: {
features: [{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [0, 0]
}
}]
}
};
expect(hasNoGeometry(state)).toBe(false);
});
it('returns true when neither describe metadata nor features expose geometry', () => {
const state = {
featuregrid: {
features: [{
type: 'Feature',
geometry: null
}]
}
};
expect(hasNoGeometry(state)).toBe(true);
});
});
});
13 changes: 13 additions & 0 deletions web/client/selectors/featuregrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,16 @@ export const viewportFilter = createShallowSelectorCreator(isEqual)(
} : {};
}
);

/**
* Returns true when neither the DescribeFeatureType metadata nor the
* loaded features expose a geometry field.
*/
export const hasNoGeometry = (state) => {
const describe = describeSelector(state);
if (describe && findGeometryProperty(describe)) {
return false;
}
const features = get(state, "featuregrid.features", []);
return !(features || []).some(({ geometry }) => geometry);
};