Add query editor support for control-return (#1979)

- Control-return in the editor will now run the query

Closes #1631
This commit is contained in:
Zachary Wasserman 2019-01-15 11:06:52 -08:00 коммит произвёл GitHub
Родитель 16cf164adb
Коммит ca84f84078
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 24 добавлений и 27 удалений

Просмотреть файл

@ -15,10 +15,11 @@ class KolideAce extends Component {
static propTypes = {
error: PropTypes.string,
fontSize: PropTypes.number,
handleSubmit: PropTypes.func.isRequired,
label: PropTypes.string,
name: PropTypes.string,
onChange: PropTypes.func,
onLoad: PropTypes.func,
onChange: PropTypes.func.isRequired,
onLoad: PropTypes.func.isRequired,
value: PropTypes.string,
readOnly: PropTypes.bool,
showGutter: PropTypes.bool,
@ -49,6 +50,7 @@ class KolideAce extends Component {
const {
error,
fontSize,
handleSubmit,
name,
onChange,
onLoad,
@ -86,6 +88,11 @@ class KolideAce extends Component {
value={value}
width="100%"
wrapEnabled={wrapEnabled}
commands={[{
name: 'commandName',
bindKey: { win: 'Ctrl-Enter', mac: 'Ctrl-Enter' },
exec: handleSubmit,
}]}
/>
</div>
);

Просмотреть файл

@ -41,10 +41,11 @@ class QueryForm extends Component {
name: formFieldInterface.isRequired,
query: formFieldInterface.isRequired,
}).isRequired,
handleSubmit: PropTypes.func,
handleSubmit: PropTypes.func.isRequired,
formData: queryInterface,
onOsqueryTableSelect: PropTypes.func,
onUpdate: PropTypes.func,
onOsqueryTableSelect: PropTypes.func.isRequired,
onRunQuery: PropTypes.func.isRequired,
onUpdate: PropTypes.func.isRequired,
queryIsRunning: PropTypes.bool,
title: PropTypes.string,
};
@ -137,7 +138,7 @@ class QueryForm extends Component {
}
render () {
const { baseError, fields, handleSubmit, queryIsRunning, title } = this.props;
const { baseError, fields, handleSubmit, onRunQuery, queryIsRunning, title } = this.props;
const { errors } = this.state;
const { onLoad, renderButtons } = this;
@ -158,6 +159,7 @@ class QueryForm extends Component {
onLoad={onLoad}
readOnly={queryIsRunning}
wrapperClassName={`${baseClass}__text-editor-wrapper`}
handleSubmit={onRunQuery}
/>
<InputField
{...fields.description}

Просмотреть файл

@ -16,7 +16,6 @@ class QueryPageSelectTargets extends Component {
onRunQuery: PropTypes.func.isRequired,
onStopQuery: PropTypes.func.isRequired,
onTargetSelect: PropTypes.func.isRequired,
query: PropTypes.string,
queryIsRunning: PropTypes.bool,
selectedTargets: PropTypes.arrayOf(targetInterface),
targetsCount: PropTypes.number,
@ -33,7 +32,6 @@ class QueryPageSelectTargets extends Component {
campaign,
onRunQuery,
onStopQuery,
query,
queryIsRunning,
queryTimerMilliseconds,
} = this.props;
@ -44,7 +42,6 @@ class QueryPageSelectTargets extends Component {
campaign={campaign}
onRunQuery={onRunQuery}
onStopQuery={onStopQuery}
query={query}
queryIsRunning={queryIsRunning}
queryTimerMilliseconds={queryTimerMilliseconds}
/>

Просмотреть файл

@ -9,11 +9,7 @@ import Timer from 'components/loaders/Timer';
const baseClass = 'query-progress-details';
const QueryProgressDetails = ({ campaign, className, onRunQuery, onStopQuery, query, queryIsRunning, queryTimerMilliseconds }) => {
const handleRunQuery = () => {
return onRunQuery(query);
};
const QueryProgressDetails = ({ campaign, className, onRunQuery, onStopQuery, queryIsRunning, queryTimerMilliseconds }) => {
const { hosts_count: hostsCount } = campaign;
const totalHostsCount = get(campaign, ['totals', 'count'], 0);
const totalRowsCount = get(campaign, ['query_results', 'length'], 0);
@ -22,7 +18,7 @@ const QueryProgressDetails = ({ campaign, className, onRunQuery, onStopQuery, qu
<div className={`${baseClass}__btn-wrapper`}>
<Button
className={`${baseClass}__run-btn`}
onClick={handleRunQuery}
onClick={onRunQuery}
variant="success"
>
Run
@ -77,7 +73,6 @@ QueryProgressDetails.propTypes = {
className: PropTypes.string,
onRunQuery: PropTypes.func.isRequired,
onStopQuery: PropTypes.func.isRequired,
query: PropTypes.string,
queryIsRunning: PropTypes.bool,
queryTimerMilliseconds: PropTypes.number,
};

Просмотреть файл

@ -127,19 +127,17 @@ describe('QueryProgressDetails - component', () => {
describe('running a query', () => {
it('calls the onRunQuery prop with the query text', () => {
const spy = createSpy();
const query = 'select * from groups';
const props = {
...defaultProps,
campaign: campaignStub,
onRunQuery: spy,
query,
};
const Component = mount(<QueryProgressDetails {...props} />);
const RunQueryButton = Component.find('.query-progress-details__run-btn');
RunQueryButton.hostNodes().simulate('click');
expect(spy).toHaveBeenCalledWith(query);
expect(spy).toHaveBeenCalled();
});
});

Просмотреть файл

@ -23,7 +23,6 @@ class QueryResultsTable extends Component {
isQueryShrinking: PropTypes.bool,
onRunQuery: PropTypes.func.isRequired,
onStopQuery: PropTypes.func.isRequired,
query: PropTypes.string,
queryIsRunning: PropTypes.bool,
queryTimerMilliseconds: PropTypes.number,
};
@ -149,7 +148,6 @@ class QueryResultsTable extends Component {
onToggleQueryFullScreen,
onRunQuery,
onStopQuery,
query,
queryIsRunning,
queryTimerMilliseconds,
} = this.props;
@ -176,7 +174,6 @@ class QueryResultsTable extends Component {
campaign={campaign}
onRunQuery={onRunQuery}
onStopQuery={onStopQuery}
query={query}
queryIsRunning={queryIsRunning}
className={`${baseClass}__full-screen`}
queryTimerMilliseconds={queryTimerMilliseconds}

Просмотреть файл

@ -193,7 +193,8 @@ export class QueryPage extends Component {
return false;
}
onRunQuery = debounce((queryText) => {
onRunQuery = debounce(() => {
const { queryText } = this.state;
const { dispatch, selectedTargets } = this.props;
const { error } = validateQuery(queryText);
@ -447,7 +448,6 @@ export class QueryPage extends Component {
campaign,
queryIsRunning,
queryResultsToggle,
queryText,
runQueryMilliseconds,
} = this.state;
const { onExportQueryResults, onToggleQueryFullScreen, onRunQuery, onStopQuery, onTargetSelect } = this;
@ -474,7 +474,6 @@ export class QueryPage extends Component {
onRunQuery={onRunQuery}
onStopQuery={onStopQuery}
onTargetSelect={onTargetSelect}
query={queryText}
queryIsRunning={queryIsRunning}
queryTimerMilliseconds={runQueryMilliseconds}
/>
@ -484,7 +483,7 @@ export class QueryPage extends Component {
renderTargetsInput = () => {
const { onFetchTargets, onRunQuery, onStopQuery, onTargetSelect } = this;
const { campaign, queryIsRunning, queryText, targetsCount, targetsError, runQueryMilliseconds } = this.state;
const { campaign, queryIsRunning, targetsCount, targetsError, runQueryMilliseconds } = this.state;
const { selectedTargets } = this.props;
return (
@ -495,7 +494,6 @@ export class QueryPage extends Component {
onRunQuery={onRunQuery}
onStopQuery={onStopQuery}
onTargetSelect={onTargetSelect}
query={queryText}
queryIsRunning={queryIsRunning}
selectedTargets={selectedTargets}
targetsCount={targetsCount}

Просмотреть файл

@ -65,6 +65,9 @@ export const itBehavesLikeAFormInputElement = (form, inputName, inputType = 'Inp
export const createAceSpy = () => {
return spyOn(global.window.ace, 'edit').andReturn({
$options: {},
commands: {
addCommand: noop,
},
getValue: () => { return 'Hello world'; },
getSession: () => {
return {