这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
137 changes: 137 additions & 0 deletions console/src/components/Common/CustomInputTypes/JsonInput.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import React, { useState } from 'react';
import AceEditor from 'react-ace';

const styles = require('./JsonInput.scss');

const NORMALKEY = 'normal';
const JSONKEY = 'json';

const parseJSONData = (data, editorType) => {
try {
const dataObject = typeof data === 'object' ? data : JSON.parse(data);

return JSON.stringify(dataObject, null, editorType === JSONKEY ? 4 : 0);
} catch (e) {
return data;
}
};

const createInitialState = data => {
const initialState = {
editorType: NORMALKEY,
data: parseJSONData(data, NORMALKEY),
};
return initialState;
};

const JsonInput = props => {
const { standardProps, placeholderProp } = props;
const { defaultValue, onChange } = standardProps;
const allProps = { ...standardProps };
delete allProps.defaultValue;
const [state, updateState] = useState(createInitialState(defaultValue));
const { editorType, data } = state;

const updateData = (newData, currentState) => {
return {
...currentState,
data: newData,
};
};

const toggleEditorType = currentState => {
const nextEditorType =
currentState.editorType === JSONKEY ? NORMALKEY : JSONKEY;

return {
...currentState,
data: parseJSONData(currentState.data, nextEditorType),
editorType: nextEditorType,
};
};

const handleKeyUpEvent = e => {
if ((e.ctrlKey || event.metaKey) && e.which === 32) {
updateState(toggleEditorType);
}
};

const handleEditorExec = () => {
updateState(toggleEditorType);
};

const handleInputChangeAndPropagate = e => {
const val = e.target.value;
updateState(currentState => updateData(val, currentState));
if (onChange) {
onChange(e);
}
};

const handleTextAreaChangeAndPropagate = (value, e) => {
const val = value;
updateState(currentState => updateData(val, currentState));
if (onChange) {
onChange(e, value);
}
};

const getJsonEditor = () => {
return (
<AceEditor
key="ace_json_editor"
{...allProps}
mode="json"
theme="github"
name="jsontoggler"
minLines={10}
maxLines={100}
width="100%"
value={data}
showPrintMargin={false}
onChange={handleTextAreaChangeAndPropagate}
showGutter={false}
focus
commands={[
{
name: 'toggleEditor',
bindKey: { win: 'Ctrl-Space', mac: 'Command-Space' },
exec: handleEditorExec,
},
]}
/>
);
};

const getNormalEditor = () => {
return (
<input
key="input_json_editor"
{...allProps}
placeholder={`${placeholderProp} (Ctrl + Space to toggle)`}
value={data}
onChange={handleInputChangeAndPropagate}
onKeyUp={handleKeyUpEvent}
className={allProps.className + ' ' + styles.jsonNormalInput}
/>
);
};

const editor = editorType === JSONKEY ? getJsonEditor() : getNormalEditor();

return (
<span className="json_input_editor">
<label>{editor}</label>
<i
key="icon_json_editor"
className={
'fa ' +
styles.jsonToggleButton +
(editorType === JSONKEY ? ' fa-compress' : ' fa-expand')
}
onClick={() => updateState(toggleEditorType)}
/>
</span>
);
};
export default JsonInput;
14 changes: 14 additions & 0 deletions console/src/components/Common/CustomInputTypes/JsonInput.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.jsonNormalInput {
padding-right: 30px;
}

.jsonToggleButton {
position: absolute;
top: 10px;
right: 10px;
z-index: 100;
opacity: 0.3;
&:hover {
opacity: 1.0;
}
}
4 changes: 2 additions & 2 deletions console/src/components/Common/Dropdown/Dropdown.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';

import { getMeParentNode } from '../../../utils/domFunctions';
import { getParentNodeByAttribute } from '../../../utils/domFunctions';
import Button from '../Button/Button';

const styles = require('./Dropdown.scss');
Expand Down Expand Up @@ -65,7 +65,7 @@ const Dropdown = ({ keyPrefix, testId, children, options, position }) => {
/*
* Update the state only if the element clicked on is not the data dropdown component
* */
const dataElement = getMeParentNode(e.target, 'data-element');
const dataElement = getParentNodeByAttribute(e.target, 'data-element');
if (d) {
/* If the element has parent whose `nodeId` is same as the current one
* */
Expand Down
29 changes: 17 additions & 12 deletions console/src/components/Services/Data/TableBrowseRows/EditItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import TableHeader from '../TableCommon/TableHeader';
import { editItem, E_ONGOING_REQ } from './EditActions';
import globals from '../../../../Globals';
import { modalClose } from './EditActions';
import JsonInput from '../../../Common/CustomInputTypes/JsonInput';
import Button from '../../../Common/Button/Button';

import {
Expand All @@ -14,8 +15,6 @@ import {
DATE,
BOOLEAN,
UUID,
JSONDTYPE,
JSONB,
TIMESTAMP,
TIMETZ,
} from '../utils';
Expand Down Expand Up @@ -167,16 +166,19 @@ class EditItem extends Component {
data-test={`typed-input-${i}`}
/>
);
} else if (colType === JSONDTYPE || colType === JSONB) {
} else if (colType === 'json' || colType === 'jsonb') {
const standardEditProps = {
className: `form-control ${styles.insertBox}`,
onClick: clicker,
ref: inputRef,
defaultValue: JSON.stringify(oldItem[colName]),
'data-test': `typed-input-${i}`,
type: 'text',
};
typedInput = (
<input
placeholder={getPlaceholder(colType)}
type="text"
className={'form-control ' + styles.insertBox}
onClick={clicker}
ref={inputRef}
defaultValue={JSON.stringify(oldItem[colName])}
data-test={`typed-input-${i}`}
<JsonInput
standardProps={standardEditProps}
placeholderProp={'{"name": "foo"} or [12, "asdf"]'}
/>
);
} else if (colType === BOOLEAN) {
Expand Down Expand Up @@ -350,7 +352,10 @@ class EditItem extends Component {
// default
return;
} else {
inputValues[colName] = refs[colName].valueNode.value; // TypedInput is an input inside a div
inputValues[colName] =
refs[colName].valueNode.props !== undefined
? refs[colName].valueNode.props.value
: refs[colName].valueNode.value;
}
});
dispatch(editItem(tableName, inputValues));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import TableHeader from '../TableCommon/TableHeader';
import { insertItem, I_RESET } from './InsertActions';
import { ordinalColSort } from '../utils';
import { setTable } from '../DataActions';
import JsonInput from '../../../Common/CustomInputTypes/JsonInput';
import Button from '../../../Common/Button/Button';
import { getPlaceholder, BOOLEAN, JSONB, JSONDTYPE } from '../utils';

import { getParentNodeByClass } from '../../../../utils/domFunctions';

class InsertItem extends Component {
constructor() {
super();
Expand Down Expand Up @@ -57,7 +60,12 @@ class InsertItem extends Component {
refs[colName] = { valueNode: null, nullNode: null, defaultNode: null };
const inputRef = node => (refs[colName].valueNode = node);
const clicker = e => {
e.target.parentNode.click();
const checkboxLabel = getParentNodeByClass(e.target, 'radio-inline');
if (checkboxLabel) {
checkboxLabel.click();
} else {
e.target.parentNode.click();
}
e.target.focus();
};
const colDefault = col.column_default;
Expand All @@ -74,22 +82,21 @@ class InsertItem extends Component {
'data-test': `typed-input-${i}`,
defaultValue: clone && colName in clone ? clone[colName] : '',
onClick: clicker,
onChange: e => {
onChange: (e, val) => {
if (isAutoIncrement) return;
if (!isNullable && !hasDefault) return;

const textValue = e.target.value;
const textValue = typeof val === 'string' ? val : e.target.value;

const radioToSelectWhenEmpty = hasDefault
? refs[colName].defaultNode
: refs[colName].nullNode;

refs[colName].insertRadioNode.checked = !!textValue.length;
radioToSelectWhenEmpty.checked = !textValue.length;
},
onFocus: e => {
if (isAutoIncrement) return;
if (!isNullable && !hasDefault) return;

const textValue = e.target.value;
if (
textValue === undefined ||
Expand All @@ -110,7 +117,6 @@ class InsertItem extends Component {
};

const colType = col.data_type;

const placeHolder = hasDefault
? col.column_default
: getPlaceholder(colType);
Expand All @@ -128,12 +134,9 @@ class InsertItem extends Component {
if (colType === JSONDTYPE || colType === JSONB) {
// JSON/JSONB
typedInput = (
<input
{...standardInputProps}
placeholder={placeHolder}
defaultValue={
clone && colName in clone ? JSON.stringify(clone[colName]) : ''
}
<JsonInput
standardProps={standardInputProps}
placeholderProp={getPlaceholder(colType)}
/>
);
}
Expand Down Expand Up @@ -262,7 +265,10 @@ class InsertItem extends Component {
// default
return;
} else {
inputValues[colName] = refs[colName].valueNode.value;
inputValues[colName] =
refs[colName].valueNode.props !== undefined
? refs[colName].valueNode.props.value
: refs[colName].valueNode.value;
}
});
dispatch(insertItem(tableName, inputValues)).then(() => {
Expand Down
Loading