mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-09-21 23:47:17 +03:00
parent
dde9908650
commit
7a683324f2
@ -1,8 +1,8 @@
|
||||
.jsonNormalInput {
|
||||
.normalInput {
|
||||
padding-right: 30px;
|
||||
}
|
||||
|
||||
.jsonToggleButton {
|
||||
.modeToggleButton {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
@ -11,4 +11,12 @@
|
||||
&:hover {
|
||||
opacity: 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
.modeType {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 28px;
|
||||
z-index: 100;
|
||||
font-style: italic;
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
import React, { useState } from 'react';
|
||||
import AceEditor from 'react-ace';
|
||||
|
||||
const styles = require('./JsonInput.scss');
|
||||
import 'brace/mode/markdown';
|
||||
import 'brace/theme/github';
|
||||
|
||||
const styles = require('./CustomInput.scss');
|
||||
|
||||
const NORMALKEY = 'normal';
|
||||
const JSONKEY = 'json';
|
||||
@ -112,7 +115,7 @@ const JsonInput = props => {
|
||||
value={data}
|
||||
onChange={handleInputChangeAndPropagate}
|
||||
onKeyUp={handleKeyUpEvent}
|
||||
className={allProps.className + ' ' + styles.jsonNormalInput}
|
||||
className={allProps.className + ' ' + styles.normalInput}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -126,12 +129,12 @@ const JsonInput = props => {
|
||||
key="icon_json_editor"
|
||||
className={
|
||||
'fa ' +
|
||||
styles.jsonToggleButton +
|
||||
styles.modeToggleButton +
|
||||
(editorType === JSONKEY ? ' fa-compress' : ' fa-expand')
|
||||
}
|
||||
onClick={() => updateState(toggleEditorType)}
|
||||
title={
|
||||
(editorType === JSONKEY ? 'Collapse' : 'Expand') + '(Ctrl + Space)'
|
||||
(editorType === JSONKEY ? 'Collapse' : 'Expand') + ' (Ctrl + Space)'
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
|
166
console/src/components/Common/CustomInputTypes/TextInput.js
Normal file
166
console/src/components/Common/CustomInputTypes/TextInput.js
Normal file
@ -0,0 +1,166 @@
|
||||
import React, { useState } from 'react';
|
||||
import AceEditor from 'react-ace';
|
||||
|
||||
import 'brace/mode/html';
|
||||
import 'brace/mode/markdown';
|
||||
import 'brace/theme/github';
|
||||
import 'brace/theme/chrome';
|
||||
|
||||
const styles = require('./CustomInput.scss');
|
||||
|
||||
// editorType is what sort of editor. All are ACE Editor
|
||||
// modes except 0, which is text input
|
||||
|
||||
// ACE editor mode names
|
||||
const EDITORTYPES = [
|
||||
'normal', // must be first
|
||||
'text',
|
||||
'markdown',
|
||||
'html',
|
||||
];
|
||||
|
||||
// human readable editor names
|
||||
const EDITORTYPENAMES = [
|
||||
'single line input',
|
||||
'multi-line text input',
|
||||
'markdown',
|
||||
'html',
|
||||
];
|
||||
|
||||
// short human readable editor names
|
||||
// for the visible label
|
||||
const SHORTEDITORTYPENAMES = ['', 'multi-line', 'markdown', 'html'];
|
||||
|
||||
const NORMALKEY = 0;
|
||||
|
||||
const createInitialState = data => {
|
||||
const initialState = {
|
||||
editorType: NORMALKEY,
|
||||
data: data,
|
||||
};
|
||||
return initialState;
|
||||
};
|
||||
|
||||
const TextInput = 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 cycleEditorType = currentState => {
|
||||
const nextEditorType = (currentState.editorType + 1) % EDITORTYPES.length;
|
||||
|
||||
return {
|
||||
...currentState,
|
||||
editorType: nextEditorType,
|
||||
};
|
||||
};
|
||||
|
||||
const handleKeyUpEvent = e => {
|
||||
if ((e.ctrlKey || event.metaKey) && e.which === 32) {
|
||||
updateState(cycleEditorType);
|
||||
}
|
||||
};
|
||||
|
||||
const handleEditorExec = () => {
|
||||
updateState(cycleEditorType);
|
||||
};
|
||||
|
||||
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 getAceEditor = curmode => {
|
||||
return (
|
||||
<AceEditor
|
||||
key="ace_text_editor"
|
||||
{...allProps}
|
||||
mode={curmode}
|
||||
theme="chrome"
|
||||
name="texttoggler"
|
||||
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_text_editor"
|
||||
{...allProps}
|
||||
placeholder={placeholderProp}
|
||||
value={data}
|
||||
onChange={handleInputChangeAndPropagate}
|
||||
onKeyUp={handleKeyUpEvent}
|
||||
className={allProps.className + ' ' + styles.normalInput}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const editor =
|
||||
editorType === NORMALKEY
|
||||
? getNormalEditor()
|
||||
: getAceEditor(EDITORTYPES[editorType]);
|
||||
|
||||
return (
|
||||
<span className="text_input_editor">
|
||||
<label>{editor}</label>
|
||||
<span
|
||||
onClick={() => updateState(cycleEditorType)}
|
||||
title={
|
||||
'Change to ' +
|
||||
EDITORTYPENAMES[(editorType + 1) % EDITORTYPES.length] +
|
||||
' (Ctrl + Space)'
|
||||
}
|
||||
>
|
||||
<span className={styles.modeType}>
|
||||
{SHORTEDITORTYPENAMES[editorType]}
|
||||
</span>
|
||||
<i
|
||||
key="icon_text_editor"
|
||||
className={
|
||||
'fa ' +
|
||||
styles.modeToggleButton +
|
||||
(editorType === NORMALKEY ? ' fa-expand' : ' fa-chevron-right')
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
export default TextInput;
|
@ -5,6 +5,7 @@ import { editItem, E_ONGOING_REQ } from './EditActions';
|
||||
import globals from '../../../../Globals';
|
||||
import { modalClose } from './EditActions';
|
||||
import JsonInput from '../../../Common/CustomInputTypes/JsonInput';
|
||||
import TextInput from '../../../Common/CustomInputTypes/TextInput';
|
||||
import Button from '../../../Common/Button/Button';
|
||||
|
||||
import {
|
||||
@ -19,6 +20,7 @@ import {
|
||||
TIMETZ,
|
||||
JSONB,
|
||||
JSONDTYPE,
|
||||
TEXT,
|
||||
} from '../utils';
|
||||
// import RichTextEditor from 'react-rte';
|
||||
import { replace } from 'react-router-redux';
|
||||
@ -84,180 +86,59 @@ class EditItem extends Component {
|
||||
e.target.focus();
|
||||
};
|
||||
|
||||
const standardEditProps = {
|
||||
className: `form-control ${styles.insertBox}`,
|
||||
onClick: clicker,
|
||||
ref: inputRef,
|
||||
'data-test': `typed-input-${i}`,
|
||||
type: 'text',
|
||||
defaultValue: oldItem[colName],
|
||||
};
|
||||
|
||||
// Text type
|
||||
let typedInput = (
|
||||
<input
|
||||
placeholder={getPlaceholder(colType)}
|
||||
type="text"
|
||||
className={'form-control ' + styles.insertBox}
|
||||
onClick={clicker}
|
||||
ref={inputRef}
|
||||
defaultValue={oldItem[colName]}
|
||||
data-test={`typed-input-${i}`}
|
||||
/>
|
||||
<input {...standardEditProps} placeholder={getPlaceholder(colType)} />
|
||||
);
|
||||
|
||||
// Integer
|
||||
if (colType === INTEGER) {
|
||||
typedInput = (
|
||||
<input
|
||||
placeholder={getPlaceholder(colType)}
|
||||
type="text"
|
||||
className={'form-control ' + styles.insertBox}
|
||||
onClick={clicker}
|
||||
ref={inputRef}
|
||||
defaultValue={oldItem[colName]}
|
||||
data-test={`typed-input-${i}`}
|
||||
/>
|
||||
);
|
||||
} else if (colType === BIGINT) {
|
||||
typedInput = (
|
||||
<input
|
||||
placeholder={getPlaceholder(colType)}
|
||||
type="text"
|
||||
className={'form-control ' + styles.insertBox}
|
||||
onClick={clicker}
|
||||
ref={inputRef}
|
||||
defaultValue={oldItem[colName]}
|
||||
data-test={`typed-input-${i}`}
|
||||
/>
|
||||
);
|
||||
} else if (colType === NUMERIC) {
|
||||
typedInput = (
|
||||
<input
|
||||
placeholder={getPlaceholder(colType)}
|
||||
type="text"
|
||||
className={'form-control ' + styles.insertBox}
|
||||
onClick={clicker}
|
||||
ref={inputRef}
|
||||
defaultValue={oldItem[colName]}
|
||||
data-test={`typed-input-${i}`}
|
||||
/>
|
||||
);
|
||||
} else if (colType === TIMESTAMP) {
|
||||
typedInput = (
|
||||
<input
|
||||
placeholder={getPlaceholder(colType)}
|
||||
type="text"
|
||||
className={'form-control ' + styles.insertBox}
|
||||
onClick={clicker}
|
||||
ref={inputRef}
|
||||
defaultValue={oldItem[colName]}
|
||||
data-test={`typed-input-${i}`}
|
||||
/>
|
||||
);
|
||||
} else if (colType === DATE) {
|
||||
typedInput = (
|
||||
<input
|
||||
placeholder={getPlaceholder(colType)}
|
||||
type="text"
|
||||
className={'form-control ' + styles.insertBox}
|
||||
onClick={clicker}
|
||||
ref={inputRef}
|
||||
defaultValue={oldItem[colName]}
|
||||
data-test={`typed-input-${i}`}
|
||||
/>
|
||||
);
|
||||
} else if (colType === TIMETZ) {
|
||||
typedInput = (
|
||||
<input
|
||||
placeholder={getPlaceholder(colType)}
|
||||
type="text"
|
||||
className={'form-control ' + styles.insertBox}
|
||||
onClick={clicker}
|
||||
ref={inputRef}
|
||||
defaultValue={oldItem[colName]}
|
||||
data-test={`typed-input-${i}`}
|
||||
/>
|
||||
);
|
||||
} else if (colType === JSONDTYPE || 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 = (
|
||||
<JsonInput
|
||||
standardProps={standardEditProps}
|
||||
placeholderProp={getPlaceholder(colType)}
|
||||
/>
|
||||
);
|
||||
} else if (colType === BOOLEAN) {
|
||||
typedInput = (
|
||||
<select
|
||||
className={'form-control ' + styles.insertBox}
|
||||
onClick={clicker}
|
||||
ref={inputRef}
|
||||
defaultValue={JSON.stringify(oldItem[colName])}
|
||||
data-test={`typed-input-${i}`}
|
||||
>
|
||||
<option value="true">True</option>
|
||||
<option value="false">False</option>
|
||||
</select>
|
||||
);
|
||||
} else if (colType === UUID) {
|
||||
typedInput = (
|
||||
<input
|
||||
placeholder={getPlaceholder(colType)}
|
||||
type="text"
|
||||
className={'form-control ' + styles.insertBox}
|
||||
onClick={clicker}
|
||||
ref={inputRef}
|
||||
defaultValue={oldItem[colName]}
|
||||
data-test={`typed-input-${i}`}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
// find value to be shown. rich text editor vs clone
|
||||
let defaultValue = '';
|
||||
let currentValue = '';
|
||||
if (
|
||||
this.state.editorColumnMap[colName] === null ||
|
||||
this.state.editorColumnMap[colName] === undefined
|
||||
) {
|
||||
defaultValue = oldItem[colName];
|
||||
} else if (this.state.editorColumnMap[colName] !== null) {
|
||||
defaultValue = this.state.editorColumnMap[colName];
|
||||
currentValue = this.state.editorColumnMap[colName];
|
||||
}
|
||||
if (currentValue !== '') {
|
||||
switch (colType) {
|
||||
case INTEGER:
|
||||
case BIGINT:
|
||||
case NUMERIC:
|
||||
case TIMESTAMP:
|
||||
case DATE:
|
||||
case TIMETZ:
|
||||
case UUID:
|
||||
break;
|
||||
case JSONB:
|
||||
case JSONDTYPE:
|
||||
typedInput = (
|
||||
<span>
|
||||
<input
|
||||
placeholder={getPlaceholder(colType)}
|
||||
type="text"
|
||||
className={'form-control ' + styles.insertBox}
|
||||
onClick={clicker}
|
||||
ref={inputRef}
|
||||
onChange={e => {
|
||||
this.onTextChange(e, colName);
|
||||
}}
|
||||
value={currentValue}
|
||||
data-test={`typed-input-${i}`}
|
||||
/>
|
||||
</span>
|
||||
<JsonInput
|
||||
standardProps={{
|
||||
...standardEditProps,
|
||||
defaultValue: JSON.stringify(oldItem[colName]),
|
||||
}}
|
||||
placeholderProp={getPlaceholder(colType)}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
break;
|
||||
case TEXT:
|
||||
typedInput = (
|
||||
<span>
|
||||
<input
|
||||
placeholder={getPlaceholder(colType)}
|
||||
type="text"
|
||||
className={'form-control ' + styles.insertBox}
|
||||
onClick={clicker}
|
||||
ref={inputRef}
|
||||
onChange={e => {
|
||||
this.onTextChange(e, colName);
|
||||
}}
|
||||
value={defaultValue}
|
||||
data-test={`typed-input-${i}`}
|
||||
/>
|
||||
</span>
|
||||
<TextInput
|
||||
standardProps={{ ...standardEditProps }}
|
||||
placeholderProp={getPlaceholder(colType)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
break;
|
||||
case BOOLEAN:
|
||||
typedInput = (
|
||||
<select {...standardEditProps}>
|
||||
<option value="true">True</option>
|
||||
<option value="false">False</option>
|
||||
</select>
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -5,8 +5,9 @@ import { insertItem, I_RESET } from './InsertActions';
|
||||
import { ordinalColSort } from '../utils';
|
||||
import { setTable } from '../DataActions';
|
||||
import JsonInput from '../../../Common/CustomInputTypes/JsonInput';
|
||||
import TextInput from '../../../Common/CustomInputTypes/TextInput';
|
||||
import Button from '../../../Common/Button/Button';
|
||||
import { getPlaceholder, BOOLEAN, JSONB, JSONDTYPE } from '../utils';
|
||||
import { getPlaceholder, BOOLEAN, JSONB, JSONDTYPE, TEXT } from '../utils';
|
||||
|
||||
import { getParentNodeByClass } from '../../../../utils/domFunctions';
|
||||
|
||||
@ -28,8 +29,8 @@ class InsertItem extends Component {
|
||||
|
||||
nextInsert() {
|
||||
// when use state object remember to do it inside a class method.
|
||||
// Since the state variable lifecycle is tired to the instance of the class
|
||||
// and making this change using an anonymous function will case errors.
|
||||
// Since the state variable lifecycle is tied to the instance of the class
|
||||
// and making this change using an anonymous function will cause errors.
|
||||
this.setState({
|
||||
insertedRows: this.state.insertedRows + 1,
|
||||
});
|
||||
@ -59,6 +60,13 @@ class InsertItem extends Component {
|
||||
throw new NotFoundError();
|
||||
}
|
||||
|
||||
const isColumnAutoIncrement = column => {
|
||||
return (
|
||||
column.column_default ===
|
||||
"nextval('" + tableName + '_' + column.column_name + "_seq'::regclass)"
|
||||
);
|
||||
};
|
||||
|
||||
const _columns = schemas.find(
|
||||
x => x.table_name === tableName && x.table_schema === currentSchema
|
||||
).columns;
|
||||
@ -81,14 +89,8 @@ class InsertItem extends Component {
|
||||
}
|
||||
e.target.focus();
|
||||
};
|
||||
const colDefault = col.column_default;
|
||||
let isAutoIncrement = false;
|
||||
if (
|
||||
colDefault ===
|
||||
"nextval('" + tableName + '_' + colName + "_seq'::regclass)"
|
||||
) {
|
||||
isAutoIncrement = true;
|
||||
}
|
||||
|
||||
const isAutoIncrement = isColumnAutoIncrement(col);
|
||||
|
||||
const standardInputProps = {
|
||||
className: `form-control ${styles.insertBox}`,
|
||||
@ -144,34 +146,44 @@ class InsertItem extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
if (colType === JSONDTYPE || colType === JSONB) {
|
||||
// JSON/JSONB
|
||||
typedInput = (
|
||||
<JsonInput
|
||||
standardProps={standardInputProps}
|
||||
placeholderProp={getPlaceholder(colType)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (colType === BOOLEAN) {
|
||||
// Boolean
|
||||
typedInput = (
|
||||
<select
|
||||
{...standardInputProps}
|
||||
onClick={e => {
|
||||
e.target.parentNode.parentNode.click();
|
||||
e.target.focus();
|
||||
}}
|
||||
defaultValue={placeHolder}
|
||||
>
|
||||
<option value="" disabled>
|
||||
-- bool --
|
||||
</option>
|
||||
<option value="true">True</option>
|
||||
<option value="false">False</option>
|
||||
</select>
|
||||
);
|
||||
switch (colType) {
|
||||
case JSONB:
|
||||
case JSONDTYPE:
|
||||
typedInput = (
|
||||
<JsonInput
|
||||
standardProps={standardInputProps}
|
||||
placeholderProp={getPlaceholder(colType)}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case TEXT:
|
||||
typedInput = (
|
||||
<TextInput
|
||||
standardProps={standardInputProps}
|
||||
placeholderProp={getPlaceholder(colType)}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case BOOLEAN:
|
||||
typedInput = (
|
||||
<select
|
||||
{...standardInputProps}
|
||||
onClick={e => {
|
||||
e.target.parentNode.parentNode.click();
|
||||
e.target.focus();
|
||||
}}
|
||||
defaultValue={placeHolder}
|
||||
>
|
||||
<option value="" disabled>
|
||||
-- bool --
|
||||
</option>
|
||||
<option value="true">True</option>
|
||||
<option value="false">False</option>
|
||||
</select>
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
|
Loading…
Reference in New Issue
Block a user