mirror of
https://github.com/getredash/redash.git
synced 2025-12-25 01:03:20 -05:00
Use AceEditor for Query Snippets (#3973)
Co-Authored-By: Ran Byron <ranbena@gmail.com>
This commit is contained in:
@@ -345,3 +345,22 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// overrides for tall form components such as ace editor
|
||||
.@{form-prefix-cls}-item {
|
||||
&-children {
|
||||
display: block; // so feeback icon positions correctly
|
||||
}
|
||||
|
||||
// no change for short components, sticks to body for tall ones
|
||||
&-children-icon {
|
||||
top: auto !important;
|
||||
bottom: 8px;
|
||||
|
||||
// makes the icon white instead of see-through
|
||||
& svg {
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
client/app/components/AceEditorInput.jsx
Normal file
22
client/app/components/AceEditorInput.jsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import React, { forwardRef } from 'react';
|
||||
import AceEditor from 'react-ace';
|
||||
|
||||
import './AceEditorInput.less';
|
||||
|
||||
function AceEditorInput(props, ref) {
|
||||
return (
|
||||
<div className="ace-editor-input">
|
||||
<AceEditor
|
||||
ref={ref}
|
||||
mode="sql"
|
||||
theme="textmate"
|
||||
height="100px"
|
||||
editorProps={{ $blockScrolling: Infinity }}
|
||||
showPrintMargin={false}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default forwardRef(AceEditorInput);
|
||||
11
client/app/components/AceEditorInput.less
Normal file
11
client/app/components/AceEditorInput.less
Normal file
@@ -0,0 +1,11 @@
|
||||
.ace-editor-input {
|
||||
// hide ghost cursor when not focused
|
||||
.ace_hidden-cursors {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
// allow Ant Form feedback icon to hover scrollbar
|
||||
.ace_scrollbar {
|
||||
z-index: auto;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import Icon from 'antd/lib/icon';
|
||||
import { includes, isFunction } from 'lodash';
|
||||
import Select from 'antd/lib/select';
|
||||
import notification from '@/services/notification';
|
||||
import AceEditorInput from '@/components/AceEditorInput';
|
||||
import { Field, Action, AntdForm } from '../proptypes';
|
||||
import helper from './dynamicFormHelper';
|
||||
|
||||
@@ -176,6 +177,8 @@ class DynamicForm extends React.Component {
|
||||
return getFieldDecorator(name, options)(<InputNumber {...props} />);
|
||||
} else if (type === 'textarea') {
|
||||
return getFieldDecorator(name, options)(<Input.TextArea {...props} />);
|
||||
} else if (type === 'ace') {
|
||||
return getFieldDecorator(name, options)(<AceEditorInput {...props} />);
|
||||
}
|
||||
return getFieldDecorator(name, options)(<Input {...props} />);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ export const Field = PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
title: PropTypes.string,
|
||||
type: PropTypes.oneOf([
|
||||
'ace',
|
||||
'text',
|
||||
'textarea',
|
||||
'email',
|
||||
|
||||
@@ -48,9 +48,8 @@ class QuerySnippetDialog extends React.Component {
|
||||
{ name: 'description', title: 'Description', type: 'text' },
|
||||
{ name: 'snippet',
|
||||
title: 'Snippet',
|
||||
type: 'textarea',
|
||||
required: true,
|
||||
props: { autosize: { minRows: 3, maxRows: 6 } } },
|
||||
type: 'ace',
|
||||
required: true },
|
||||
].map(field => ({ ...field, readOnly, initialValue: get(querySnippet, field.name, '') }));
|
||||
|
||||
return (
|
||||
@@ -79,6 +78,7 @@ class QuerySnippetDialog extends React.Component {
|
||||
fields={formFields}
|
||||
onSubmit={this.handleSubmit}
|
||||
hideSubmitButton
|
||||
feedbackIcons
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user