From 7d2872c42f7f4ab4fe10bb5e59703c1c93c8ccf1 Mon Sep 17 00:00:00 2001
From: Mateo Silguero <mfsilguero@gmail.com>
Date: Mon, 12 Nov 2018 14:27:41 -0300
Subject: [PATCH 1/2] user can edit keys and values

---
 src/js/components/DataTypes/Object.js         | 29 +++++++++++
 .../ObjectKeyModal/AddKeyRequest.js           |  1 -
 .../ObjectKeyModal/EditKeyRequest.js          | 52 +++++++++++++++++++
 .../ObjectKeyModal/ObjectKeyModal.js          |  6 ++-
 src/js/components/VariableEditor.js           | 31 ++++++++++-
 src/js/index.js                               | 32 +++++++++---
 src/js/stores/ObjectAttributes.js             | 26 ++++++++--
 src/style/scss/global.scss                    |  5 +-
 .../ObjectKeyModal/EditKeyRequest-test.js     | 38 ++++++++++++++
 9 files changed, 205 insertions(+), 15 deletions(-)
 create mode 100644 src/js/components/ObjectKeyModal/EditKeyRequest.js
 create mode 100644 test/tests/js/components/ObjectKeyModal/EditKeyRequest-test.js

diff --git a/src/js/components/DataTypes/Object.js b/src/js/components/DataTypes/Object.js
index c14a3ff5..474459ea 100644
--- a/src/js/components/DataTypes/Object.js
+++ b/src/js/components/DataTypes/Object.js
@@ -1,6 +1,7 @@
 import React from 'react';
 import {polyfill} from 'react-lifecycles-compat';
 import { toType } from './../../helpers/util';
+import dispatcher from './../../helpers/dispatcher';
 
 //data type components
 import { JsonObject } from './DataTypes';
@@ -15,6 +16,7 @@ import AttributeStore from './../../stores/ObjectAttributes';
 
 //icons
 import { CollapsedIcon, ExpandedIcon } from './../ToggleIcons';
+import { Edit } from './../icons';
 
 //theme
 import Theme from './../../themes/getStyle';
@@ -130,6 +132,32 @@ class RjvObject extends React.PureComponent {
         return <VariableMeta size={size} {...this.props} />;
     }
 
+    getEditIcon = () => {
+        const { theme, name, namespace, src, rjvId } = this.props;        
+        return (
+            <div class="click-to-edit" style={{ verticalAlign: 'top' }} title={"Edit Key"}>
+                <Edit
+                    class="click-to-edit-icon"
+                    {...Theme(theme, 'editVarIcon')}
+                    onClick={(e) => {
+                        e.stopPropagation();
+                        dispatcher.dispatch({
+                            name: 'UPDATE_VARIABLE_KEY_REQUEST',
+                            rjvId: rjvId,
+                            data: {
+                                name,
+                                namespace: namespace.splice(0, namespace.length -1),
+                                existing_value: src,
+                                _removed: false,
+                                key_name: name
+                            }
+                        });
+                    }}
+                />
+            </div>
+        );
+    }
+
     getBraceStart(object_type, expanded) {
         const { src, theme, iconStyle, parent_type } = this.props;
 
@@ -154,6 +182,7 @@ class RjvObject extends React.PureComponent {
                     }}
                     {...Theme(theme, 'brace-row')}
                 >
+                    {this.getEditIcon()}
                     <div
                         class="icon-container"
                         {...Theme(theme, 'icon-container')}
diff --git a/src/js/components/ObjectKeyModal/AddKeyRequest.js b/src/js/components/ObjectKeyModal/AddKeyRequest.js
index c881ca0d..0a0b9a92 100644
--- a/src/js/components/ObjectKeyModal/AddKeyRequest.js
+++ b/src/js/components/ObjectKeyModal/AddKeyRequest.js
@@ -30,7 +30,6 @@ export default class extends React.PureComponent {
         );
         return (
             input != ''
-            && Object.keys(request.existing_value).indexOf(input) === -1
         );
     }
 
diff --git a/src/js/components/ObjectKeyModal/EditKeyRequest.js b/src/js/components/ObjectKeyModal/EditKeyRequest.js
new file mode 100644
index 00000000..5575640b
--- /dev/null
+++ b/src/js/components/ObjectKeyModal/EditKeyRequest.js
@@ -0,0 +1,52 @@
+import React from 'react';
+import dispatcher from './../../helpers/dispatcher';
+import ObjectAttributes from './../../stores/ObjectAttributes';
+import ObjectKeyModal from './ObjectKeyModal';
+
+//global theme
+import Theme from './../../themes/getStyle';
+
+
+//this input appears when adding a new value to an object
+export default class extends React.PureComponent {
+
+    render() {
+        const {active, theme, rjvId } = this.props;
+        const { name } = ObjectAttributes.get(rjvId, 'action', 'edit-key-request') || {};
+
+        return active ? (
+            <ObjectKeyModal
+                rjvId={rjvId}
+                theme={theme}
+                input={name}
+                isValid={this.isValid}
+                submit={this.submit}
+            />
+        ) : null;
+    }
+
+    isValid = (input) => {
+        const {rjvId} = this.props;
+        const request = ObjectAttributes.get(
+            rjvId, 'action', 'edit-key-request'
+        );
+        return (
+            input != ''
+        );
+    }
+
+    submit = (input) => {
+        const { rjvId } = this.props;
+        let request = ObjectAttributes.get(
+            rjvId, 'action', 'edit-key-request'
+        );     
+        request.key_name = input;
+        request.new_value = request.existing_value;
+        request.variable_key_updated = true;
+        dispatcher.dispatch({
+            name: 'VARIABLE_KEY_UPDATED',
+            rjvId: rjvId,
+            data: request
+        });
+    }
+}
diff --git a/src/js/components/ObjectKeyModal/ObjectKeyModal.js b/src/js/components/ObjectKeyModal/ObjectKeyModal.js
index 81f261ff..f698ce03 100644
--- a/src/js/components/ObjectKeyModal/ObjectKeyModal.js
+++ b/src/js/components/ObjectKeyModal/ObjectKeyModal.js
@@ -12,10 +12,14 @@ export default class extends React.PureComponent {
     constructor(props) {
         super(props);
         this.state = {
-            input: props.input ? props.input : ''
+            input: ''
         };
     }
 
+    componentDidMount() {
+        this.setState({ input: this.props.input });
+    }
+
     render() {
         const {theme, rjvId, isValid} = this.props;
         const {input} = this.state;
diff --git a/src/js/components/VariableEditor.js b/src/js/components/VariableEditor.js
index 60497bac..c430c3ac 100644
--- a/src/js/components/VariableEditor.js
+++ b/src/js/components/VariableEditor.js
@@ -66,6 +66,9 @@ class VariableEditor extends React.PureComponent {
                 class="variable-row"
                 key={variable.name}
             >
+                {onEdit !== false && editMode == false
+                    ? this.getEditKeyIcon()
+                    : null}
                 {type == 'array' ? (
                     <span
                         {...Theme(theme, 'array-key')}
@@ -136,7 +139,7 @@ class VariableEditor extends React.PureComponent {
         const { variable, theme } = this.props;
 
         return (
-            <div class="click-to-edit" style={{ verticalAlign: 'top' }}>
+            <div class="click-to-edit" style={{ verticalAlign: 'top' }} title={"Edit Value"}>
                 <Edit
                     class="click-to-edit-icon"
                     {...Theme(theme, 'editVarIcon')}
@@ -148,6 +151,32 @@ class VariableEditor extends React.PureComponent {
         );
     }
 
+    getEditKeyIcon = () => {
+        const { variable: { name, value }, theme, namespace, rjvId } = this.props;        
+        return (
+            <div class="click-to-edit" style={{ verticalAlign: 'top' }} title={"Edit Key"}>
+                <Edit
+                    class="click-to-edit-icon"
+                    {...Theme(theme, 'editVarIcon')}
+                    onClick={(e) => {
+                        e.stopPropagation();
+                        dispatcher.dispatch({
+                            name: 'UPDATE_VARIABLE_KEY_REQUEST',
+                            rjvId: rjvId,
+                            data: {
+                                name,
+                                namespace: namespace,
+                                existing_value: value,
+                                variable_removed: false,
+                                key_name: name
+                            }
+                        });
+                    }}
+                />
+            </div>
+        );
+    }
+
     prepopInput = variable => {
         if (this.props.onEdit !== false) {
             const stringifiedValue = stringifyVariable(variable.value);
diff --git a/src/js/index.js b/src/js/index.js
index 64773a3a..23ff2cce 100644
--- a/src/js/index.js
+++ b/src/js/index.js
@@ -2,6 +2,7 @@ import React from 'react';
 import {polyfill} from 'react-lifecycles-compat';
 import JsonViewer from './components/JsonViewer';
 import AddKeyRequest from './components/ObjectKeyModal/AddKeyRequest';
+import EditKeyRequest from './components/ObjectKeyModal/EditKeyRequest';
 import ValidationFailure from './components/ValidationFailure';
 import {toType, isTheme} from './helpers/util';
 import ObjectAttributes from './stores/ObjectAttributes';
@@ -139,7 +140,8 @@ class ReactJsonView extends React.PureComponent {
         return {
             'reset': this.resetState,
             'variable-update': this.updateSrc,
-            'add-key-request': this.addKeyRequest
+            'add-key-request': this.addKeyRequest,
+            'edit-key-request': this.editKeyRequest
         };
     }
     //make sure props are passed in as expected
@@ -182,6 +184,7 @@ class ReactJsonView extends React.PureComponent {
             validationFailure,
             validationMessage,
             addKeyRequest,
+            editKeyRequest,
             theme,
             src,
             name
@@ -211,6 +214,11 @@ class ReactJsonView extends React.PureComponent {
                     theme={theme}
                     rjvId={this.rjvId}
                     defaultValue={defaultValue} />
+                <EditKeyRequest
+                    active={editKeyRequest}
+                    theme={theme}
+                    rjvId={this.rjvId}
+                    defaultValue={defaultValue} />
             </div>
         );
     }
@@ -230,17 +238,20 @@ class ReactJsonView extends React.PureComponent {
 
         const on_edit_payload = {
             existing_src: src,
-            new_value: new_value,
-            updated_src: updated_src,
-            name: name,
-            namespace: namespace,
-            existing_value: existing_value,
+            new_value,
+            updated_src,
+            name,
+            namespace,
+            existing_value,
         };
 
         switch (type) {
         case 'variable-added':
             result = onAdd(on_edit_payload);
             break;
+        case 'variable-update-key':
+            result = onEdit(on_edit_payload);
+            break;
         case 'variable-edited':
             result = onEdit(on_edit_payload);
             break;
@@ -267,10 +278,17 @@ class ReactJsonView extends React.PureComponent {
         });
     }
 
+    editKeyRequest = () => {
+        this.setState({
+            editKeyRequest: true
+        });
+    }
+
     resetState = () => {
         this.setState({
             validationFailure: false,
-            addKeyRequest: false
+            addKeyRequest: false,
+            editKeyRequest: false
         });
     }
 }
diff --git a/src/js/stores/ObjectAttributes.js b/src/js/stores/ObjectAttributes.js
index 14987e8b..7a3dbb70 100644
--- a/src/js/stores/ObjectAttributes.js
+++ b/src/js/stores/ObjectAttributes.js
@@ -63,16 +63,27 @@ class ObjectAttributes extends EventEmitter {
             );
             this.emit('variable-update-' + rjvId);
             break;
+        case 'VARIABLE_KEY_UPDATED':
+            action.data.updated_src = this.updateSrc(
+                rjvId, data
+            );
+            this.set(rjvId, 'action', 'variable-update',{...data, type:'variable-key-added'});
+            this.emit('variable-update-' + rjvId);
+            break;
         case 'ADD_VARIABLE_KEY_REQUEST':
             this.set(rjvId, 'action', 'new-key-request', data);
             this.emit('add-key-request-' + rjvId);
             break;
+        case 'UPDATE_VARIABLE_KEY_REQUEST':
+            this.set(rjvId, 'action', 'edit-key-request', data);
+            this.emit('edit-key-request-' + rjvId);
+            break;
         }
     }
 
     updateSrc = (rjvId, request) => {
         let {
-            name, namespace, new_value, existing_value, variable_removed
+            name, namespace, new_value, existing_value, variable_key_updated, variable_removed, key_name
         } = request;
 
         namespace.shift();
@@ -88,19 +99,26 @@ class ObjectAttributes extends EventEmitter {
             walk = walk[idx];
         }
 
-
-        if (variable_removed) {
+        if(variable_key_updated) {
             if (toType(walk) == 'array') {
                 walk.splice(name, 1);
             } else {
+                walk[key_name] = existing_value;
                 delete walk[name];
             }
+        } else if (variable_removed) {
+            if (toType(walk) == 'array') {
+                walk.splice(name, 1);
+            } else {
+                if(walk) delete walk[name];
+            }
         } else {
             //update copied variable at specified namespace
             if (name !== null) {
                 walk[name] = new_value;
             } else {
-                updated_src = new_value;
+                walk[new_value] = existing_value;
+                //updated_src = new_value;
             }
         }
 
diff --git a/src/style/scss/global.scss b/src/style/scss/global.scss
index 8f65e092..4667f366 100644
--- a/src/style/scss/global.scss
+++ b/src/style/scss/global.scss
@@ -14,7 +14,7 @@
     }
 
     .object-key-val {
-        &:hover > span > .object-meta-data {
+        &:hover > span > .object-meta-data, &:hover > span > span {
             & > .copy-to-clipboard-container {
                 display: inline-block;
             }
@@ -24,6 +24,9 @@
             & > .click-to-remove {
                 display: inline-block;
             }
+            & > .click-to-edit {
+                display: inline-block;
+            }
         }
     }
 
diff --git a/test/tests/js/components/ObjectKeyModal/EditKeyRequest-test.js b/test/tests/js/components/ObjectKeyModal/EditKeyRequest-test.js
new file mode 100644
index 00000000..9d36351b
--- /dev/null
+++ b/test/tests/js/components/ObjectKeyModal/EditKeyRequest-test.js
@@ -0,0 +1,38 @@
+import React from "react"
+import { shallow, render, mount } from "enzyme"
+import { expect } from "chai"
+
+import EditKeyRequest from "./../../../../../src/js/components/ObjectKeyModal/EditKeyRequest"
+import ObjectAttributes from "./../../../../../src/js/stores/ObjectAttributes"
+
+describe("<EditKeyRequest />", function() {
+    const rjvId = 1
+
+    it("EditKeyRequest should not render input when inactive", function() {
+        ObjectAttributes.set(rjvId, "action", "new-key-request", {
+            existing_value: { test: true },
+            namespace: [],
+            new_value: { test: null }
+        })
+        ObjectAttributes.set(rjvId, "global", "src", { test: true })
+        const wrapper = mount(
+            <EditKeyRequest active={false} theme="rjv-default" rjvId={rjvId} />
+        )
+
+        expect(wrapper.find(".key-modal-input").length).to.equal(0)
+    })
+
+    it("EditKeyRequest should render input when active", function() {
+        ObjectAttributes.set(rjvId, "action", "new-key-request", {
+            existing_value: { test: true },
+            namespace: [],
+            new_value: { test: null }
+        })
+        ObjectAttributes.set(rjvId, "global", "src", { test: true })
+        const wrapper = mount(
+            <EditKeyRequest active={true} theme="rjv-default" rjvId={rjvId} />
+        )
+
+        expect(wrapper.find(".key-modal-input").length).to.equal(1)
+    })
+})

From 37838234ef04baf0488c5dfd1acbb5783ad30c0f Mon Sep 17 00:00:00 2001
From: Mateo Silguero <mfsilguero@gmail.com>
Date: Tue, 13 Nov 2018 10:24:16 -0300
Subject: [PATCH 2/2] disabled edit array keys

---
 src/js/components/VariableEditor.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/js/components/VariableEditor.js b/src/js/components/VariableEditor.js
index c430c3ac..405f9302 100644
--- a/src/js/components/VariableEditor.js
+++ b/src/js/components/VariableEditor.js
@@ -66,7 +66,7 @@ class VariableEditor extends React.PureComponent {
                 class="variable-row"
                 key={variable.name}
             >
-                {onEdit !== false && editMode == false
+                {isNaN(Number(variable.name)) && onEdit !== false && editMode == false
                     ? this.getEditKeyIcon()
                     : null}
                 {type == 'array' ? (