Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for copying and pasting features in the feature grid #10563

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
26 changes: 26 additions & 0 deletions web/client/actions/featuregrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export const TOGGLE_MODE = 'FEATUREGRID:TOGGLE_MODE';
export const TOGGLE_FEATURES_SELECTION = 'FEATUREGRID:TOGGLE_FEATURES_SELECTION';
export const FEATURES_MODIFIED = 'FEATUREGRID:FEATURES_MODIFIED';
export const CREATE_NEW_FEATURE = "FEATUREGRID:NEW_FEATURE";
export const COPY_FEATURES = "FEATUREGRID:COPY_FEATURES"; // added to support copy features
export const PASTE_FEATURES = "FEATUREGRID:PASTE_FEATURES"; // added to support paste features
export const SAVE_CHANGES = 'FEATUREGRID:SAVE_CHANGES';
export const SAVING = 'FEATUREGRID:SAVING';
export const START_EDITING_FEATURE = 'FEATUREGRID:START_EDITING_FEATURE';
Expand Down Expand Up @@ -268,6 +270,30 @@ export function createNewFeatures(features) {
features
};
}

/**
* Copy features to clipboard
* @returns {object} action
*/
export function copyFeatures() {
return {
type: COPY_FEATURES
};
}

/**
* Paste features from clipboard
* @returns {object} action
*/
export function pasteFeatures() {
const stringifiedFeatures = localStorage.getItem('features');
const featuresJSON = JSON.parse(stringifiedFeatures);
return {
type: PASTE_FEATURES,
featuresJSON
};
}

export function saveChanges() {
return {
type: SAVE_CHANGES
Expand Down
27 changes: 27 additions & 0 deletions web/client/components/data/featuregrid/toolbars/Toolbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ const standardButtons = {
visible={mode === "VIEW" && showAdvancedFilterButton}
onClick={events.showQueryPanel}
glyph="filter"/>),
copyFeaturesViewMode: ({disabled, mode, hasGeometry, selectedCount, hasSupportedGeometry = true, events = {}}) => (<TButton
id="copy-features"
keyProp="copy-features"
tooltipId="featuregrid.toolbar.copyFeatures"
disabled={disabled}
visible={mode === "VIEW" && hasGeometry && hasSupportedGeometry && selectedCount > 0}
onClick={events.copyFeatures}
glyph="duplicate"/>),
zoomAll: ({disabled, disableZoomAll = false, mode, events = {}}) => (<TButton
id="zoom-all"
keyProp="zoom-all"
Expand All @@ -61,6 +69,22 @@ const standardButtons = {
visible={mode === "EDIT" && !hasChanges && !hasNewFeatures}
onClick={events.switchViewMode}
glyph="arrow-left"/>),
copyFeaturesEditMode: ({disabled, mode, hasGeometry, hasNewFeatures, hasChanges, selectedCount, hasSupportedGeometry = true, events = {}}) => (<TButton
id="copy-features"
keyProp="copy-features"
tooltipId="featuregrid.toolbar.copyFeatures"
disabled={disabled}
visible={mode === "EDIT" && hasGeometry && !hasNewFeatures && !hasChanges && hasSupportedGeometry && selectedCount > 0}
onClick={events.copyFeatures}
glyph="duplicate"/>),
pasteFeatures: ({disabled, mode, copiedCount, hasNewFeatures, hasChanges, hasSupportedGeometry = true, events = {}}) => (<TButton
id="paste-features"
keyProp="paste-features"
tooltipId="featuregrid.toolbar.pasteFeatures"
disabled={disabled}
visible={mode === "EDIT" && !hasNewFeatures && !hasChanges && hasSupportedGeometry && copiedCount > 0}
onClick={events.pasteFeatures}
glyph="paste"/>),
addFeature: ({disabled, mode, hasNewFeatures, hasChanges, hasSupportedGeometry = true, events = {}}) => (<TButton
id="add-feature"
keyProp="add-feature"
Expand Down Expand Up @@ -276,11 +300,14 @@ const buttons = [
{name: "editMode", Component: standardButtons.editMode}, // EDITOR
{name: "backToViewMode", Component: standardButtons.backToViewMode}, // EDITOR
{name: "addFeature", Component: standardButtons.addFeature}, // EDITOR
{name: "copyFeaturesEditMode", Component: standardButtons.copyFeaturesEditMode}, // GRID
{name: "pasteFeatures", Component: standardButtons.pasteFeatures}, // EDITOR
{name: "drawFeature", Component: standardButtons.drawFeature}, // EDITOR
{name: "removeFeature", Component: standardButtons.removeFeature}, // EDITOR
{name: "saveFeature", Component: standardButtons.saveFeature}, // EDITOR
{name: "cancelEditing", Component: standardButtons.cancelEditing}, // EDITOR
{name: "deleteGeometry", Component: standardButtons.deleteGeometry}, // EDITOR
{name: "copyFeaturesViewMode", Component: standardButtons.copyFeaturesViewMode}, // GRID
{name: "filter", Component: standardButtons.filter}, // GRID (needs query panel plugin)
{name: "viewportFilter", Component: standardButtons.viewportFilter},
{name: "zoomAll", Component: standardButtons.zoomAll}, // GRID (should remove or hide? Is always disabled and not to much useful)
Expand Down
23 changes: 23 additions & 0 deletions web/client/epics/featuregrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ import {
DESELECT_FEATURES,
START_DRAWING_FEATURE,
CREATE_NEW_FEATURE,
COPY_FEATURES,
PASTE_FEATURES,
CLEAR_CHANGES_CONFIRMED,
FEATURE_GRID_CLOSE_CONFIRMED,
openFeatureGrid,
Expand Down Expand Up @@ -872,6 +874,27 @@ export const onFeatureGridGeometryEditing = (action$, store) => action$.ofType(G

return Rx.Observable.of(geometryChanged(changedFeatures)).concat(enableEdit);
});

/**
* copy feature action flow
* @memberof epics.featuregrid
*/
export const copyFeatures = (action$, store) => action$.ofType(COPY_FEATURES)
.switchMap( () => {
const state = store.getState();
// setter
localStorage.setItem('features', JSON.stringify(selectedFeaturesSelector(state)));
return Rx.Observable.empty();
});
/**
* paste geometry action flow
* @memberof epics.featuregrid
*/
export const pasteFeature = (action$) => action$.ofType(PASTE_FEATURES)
.switchMap( () => {
return Rx.Observable.empty();
});

/**
* Manage delete geometry action flow
* @memberof epics.featuregrid
Expand Down
2 changes: 2 additions & 0 deletions web/client/plugins/featuregrid/panels/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
isSavingSelector,
isSimpleGeomSelector,
modeSelector,
copiedFeaturesCount,
selectedFeaturesCount,
selectedLayerNameSelector,
showAgainSelector,
Expand Down Expand Up @@ -79,6 +80,7 @@ const Toolbar = connect(
saved: isSavedSelector,
mode: modeSelector,
hasChanges: hasChangesSelector,
copiedCount: copiedFeaturesCount,
hasNewFeatures: hasNewFeaturesSelector,
hasGeometry: hasGeometrySelector,
syncPopover: (state) => ({
Expand Down
4 changes: 4 additions & 0 deletions web/client/plugins/featuregrid/toolbarEvents.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
setTimeSync,
toggleShowAgain,
createNewFeatures,
copyFeatures,
pasteFeatures,
startEditingFeature,
startDrawingFeature,
deleteGeometry,
Expand All @@ -23,6 +25,8 @@ import {

export default {
createFeature: () => createNewFeatures([{}]),
copyFeatures: () => copyFeatures(),
pasteFeatures: () => pasteFeatures([{}]),
saveChanges: () => saveChanges(),
clearFeatureEditing: () => toggleTool("clearConfirm", true),
deleteGeometry: () => deleteGeometry(),
Expand Down
11 changes: 11 additions & 0 deletions web/client/reducers/featuregrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
SET_FEATURES,
FEATURES_MODIFIED,
CREATE_NEW_FEATURE,
PASTE_FEATURES,
SAVING,
SAVE_SUCCESS,
SAVE_ERROR,
Expand Down Expand Up @@ -284,6 +285,16 @@ function featuregrid(state = emptyResultsState, action) {
}))
});
}
case PASTE_FEATURES: {
let id = uuid.v1();
return assign({}, state, {
newFeatures: action.featuresJSON.map(f => ({...f, _new: true, id: f.id ? f.id : id, type: "Feature",
geometry: f.geometry,
properties: f.properties
})),
select: []
});
}
case SAVE_ERROR: {
return assign({}, state, {
deleteConfirm: false,
Expand Down
1 change: 1 addition & 0 deletions web/client/selectors/featuregrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ export const getCustomizedAttributes = state => {
};
export const modeSelector = state => state && state.featuregrid && state.featuregrid.mode;
export const selectedFeaturesCount = state => (selectedFeaturesSelector(state) || []).length;
export const copiedFeaturesCount = state => state && JSON.parse(localStorage.getItem('features'))?.length;
export const changesMapSelector = state => toChangesMap(changesSelector(state));
export const hasGeometrySelector = state => hasGeometrySelectedFeature(state);
export const showAgainSelector = state => get(state, "featuregrid.showAgain", false);
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.da-DK.json
Original file line number Diff line number Diff line change
Expand Up @@ -1733,6 +1733,8 @@
}
},
"toolbar": {
"copyFeatures": "Copy features",
"pasteFeatures": "Paste features",
"synchPopoverTitle": "Sync map with filter ",
"synchPopoverText": "Use this tool to synchronize the map with the selected filter",
"notShowAgain": " Don't show this message again",
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -1937,6 +1937,8 @@
}
},
"toolbar": {
"copyFeatures": "Funktionen kopieren",
"pasteFeatures": "Funktionen einfügen",
"synchPopoverTitle": "Karte mit Filter synchronisieren ",
"synchPopoverText": "Verwenden Sie dieses Werkzeug, um die Karte mit dem ausgewählten Filter zu synchronisieren",
"notShowAgain": "Diese Nachricht nicht erneut anzeigen",
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -1898,6 +1898,8 @@
}
},
"toolbar": {
"copyFeatures": "Copy features",
"pasteFeatures": "Paste features",
"synchPopoverTitle": "Sync map with filter ",
"synchPopoverText": "Use this tool to synchronize the map with the selected filter",
"notShowAgain": " Don't show this message again",
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.es-ES.json
Original file line number Diff line number Diff line change
Expand Up @@ -1899,6 +1899,8 @@
}
},
"toolbar": {
"copyFeatures": "Copiar entidades",
"pasteFeatures": "Pegar entidades",
"synchPopoverTitle": "Sincronizar mapa con filtro ",
"synchPopoverText": "Utilice esta herramienta para sincronizar el mapa con el filtro seleccionado",
"notShowAgain": " No mostrar este mensaje de nuevo",
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.fi-FI.json
Original file line number Diff line number Diff line change
Expand Up @@ -1397,6 +1397,8 @@
}
},
"toolbar": {
"copyFeatures": "Copy features",
"pasteFeatures": "Paste features",
"synchPopoverTitle": "Synkronoi kartta suodattimen kanssa ",
"synchPopoverText": "Käytä tätä työkalua synkronoidaksesi kartta valitun suodattimen kanssa",
"notShowAgain": "Älä näytä tätä viestiä uudelleen",
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -1899,6 +1899,8 @@
}
},
"toolbar": {
"copyFeatures": "Copier les entités",
"pasteFeatures": "Coller les entités",
"synchPopoverTitle": "Synchroniser la carte avec un filtre ",
"synchPopoverText": "Utilisez cet outil pour synchroniser la carte avec le filtre sélectionné",
"notShowAgain": " Ne plus afficher ce message",
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.hr-HR.json
Original file line number Diff line number Diff line change
Expand Up @@ -1354,6 +1354,8 @@
}
},
"toolbar": {
"copyFeatures": "Copy features",
"pasteFeatures": "Paste features",
"synchPopoverTitle": "Sinkroniziraj kartu sa filtrom ",
"synchPopoverText": "Koristi ovaj alat za sinkronizaciju karte sa odabranim filtrom",
"notShowAgain": " Ne prikazuj više ovu poruku",
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.is-IS.json
Original file line number Diff line number Diff line change
Expand Up @@ -1757,6 +1757,8 @@
}
},
"toolbar": {
"copyFeatures": "Copy features",
"pasteFeatures": "Paste features",
"synchPopoverTitle": "Sync map with filter ",
"synchPopoverText": "Use this tool to synchronize the map with the selected filter",
"notShowAgain": " Don't show this message again",
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.it-IT.json
Original file line number Diff line number Diff line change
Expand Up @@ -1898,6 +1898,8 @@
}
},
"toolbar": {
"copyFeatures": "Copia entità",
"pasteFeatures": "Incolla entità",
"synchPopoverTitle": "Sincronizza la mappa con il filtro ",
"synchPopoverText": "Usa questa icona per sincronizzare la mappa con il filtro selezionato",
"notShowAgain": " Non mostrare più",
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.nl-NL.json
Original file line number Diff line number Diff line change
Expand Up @@ -1891,6 +1891,8 @@
}
},
"toolbar": {
"copyFeatures": "Functies kopiëren",
"pasteFeatures": "Functies plakken",
"synchPopoverTitle": "Synchroniseer kaart met filter ",
"synchPopoverText": "Gebruik deze tool om de kaart te synchroniseren met de geselecteerde filter",
"notShowAgain": " Laat dit bericht niet meer zien",
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.pt-PT.json
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,8 @@
}
},
"toolbar": {
"copyFeatures": "Copiar entidades",
"pasteFeatures": "Colar entidades",
"synchPopoverTitle": "Sync map with filter ",
"synchPopoverText": "Use this tool to synchronize the map with the selected filter",
"notShowAgain": " Don't show this message again",
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.sk-SK.json
Original file line number Diff line number Diff line change
Expand Up @@ -1638,6 +1638,8 @@
}
},
"toolbar": {
"copyFeatures": "Copy features",
"pasteFeatures": "Paste features",
"synchPopoverTitle": "Synchronizovať mapu s filtrom ",
"synchPopoverText": "Použi tento nástroj pre synchronizáciu mapy s vybraným filtrom",
"notShowAgain": " Túto správu už nezobrazovať",
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.sv-SE.json
Original file line number Diff line number Diff line change
Expand Up @@ -1618,6 +1618,8 @@
}
},
"toolbar": {
"copyFeatures": "Copy features",
"pasteFeatures": "Paste features",
"synchPopoverTitle": "Synkronisera karta med filter",
"synchPopoverText": "Använd det här verktyget för att synkronisera kartan med det valda filtret",
"notShowAgain": "Visa inte detta meddelande igen",
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.vi-VN.json
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,8 @@
"resultInfoVirtual": "{total, plural, =0 {không mục nào} =1 {{total} Mục số {total}} other {{total} Mục}}",
"selectall": "Chọn tất cả",
"toolbar": {
"copyFeatures": "Copy features",
"pasteFeatures": "Paste features",
"addGeom": "Thêm một hình cho hình hiện có",
"addNewFeatures": "Thêm tính năng mới",
"advancedFilter": "Tìm kiếm nâng cao",
Expand Down
2 changes: 2 additions & 0 deletions web/client/translations/data.zh-ZH.json
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,8 @@
}
},
"toolbar": {
"copyFeatures": "Copy features",
"pasteFeatures": "Paste features",
"synchPopoverTitle": "Sync map with filter ",
"synchPopoverText": "Use this tool to synchronize the map with the selected filter",
"notShowAgain": " Don't show this message again",
Expand Down