diff --git a/src/legacy/core_plugins/console/index.ts b/src/legacy/core_plugins/console/index.ts index c4e6a77b7d859..cec6d0a4219ae 100644 --- a/src/legacy/core_plugins/console/index.ts +++ b/src/legacy/core_plugins/console/index.ts @@ -19,7 +19,7 @@ import Boom from 'boom'; import { first } from 'rxjs/operators'; -import { resolve, join, sep } from 'path'; +import { resolve, join } from 'path'; import url from 'url'; import { has, isEmpty, head, pick } from 'lodash'; @@ -51,9 +51,7 @@ function filterHeaders(originalHeaders: any, headersToKeep: any) { // eslint-disable-next-line export default function(kibana: any) { - const modules = resolve(__dirname, 'public/webpackShims/'); - const quarantinedSrc = resolve(__dirname, 'public/quarantined/src/'); - const npSrc = resolve(__dirname, 'np_ready/public'); + const npSrc = resolve(__dirname, 'public/np_ready'); let defaultVars: any; return new kibana.Plugin({ @@ -180,16 +178,10 @@ export default function(kibana: any) { }, uiExports: { - devTools: [`${npSrc}/legacy`], - styleSheetPaths: resolve(__dirname, 'public/quarantined/index.scss'), - + devTools: [resolve(__dirname, 'public/legacy')], + styleSheetPaths: resolve(npSrc, 'application/styles/index.scss'), injectDefaultVars: () => defaultVars, - - noParse: [ - join(modules, 'ace' + sep), - join(modules, 'moment_src/moment' + sep), - join(quarantinedSrc, 'sense_editor/mode/worker.js'), - ], + noParse: [join(npSrc, 'application/models/legacy_core_editor/mode/worker/worker.js')], }, } as any); } diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/load_remote_editor_state.test.ts b/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/load_remote_editor_state.test.ts deleted file mode 100644 index 0eb6a8fec4f86..0000000000000 --- a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/load_remote_editor_state.test.ts +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import sinon from 'sinon'; -import $ from 'jquery'; - -import { loadRemoteState } from './load_remote_editor_state'; - -describe('[Legacy Console] loading remote editor state', () => { - const sandbox = sinon.createSandbox(); - - let inputMock: any; - let ajaxDoneStub: any; - beforeEach(() => { - ajaxDoneStub = sinon.stub(); - sandbox.stub($, 'ajax').returns({ done: ajaxDoneStub } as any); - - inputMock = { - update: sinon.stub(), - moveToNextRequestEdge: sinon.stub(), - highlightCurrentRequestsAndUpdateActionBar: sinon.stub(), - updateActionsBar: sinon.stub(), - getSession: sinon.stub().returns({ on() {} }), - }; - }); - - afterEach(() => { - sandbox.restore(); - }); - - it('correctly loads state from any external HTTPS links.', () => { - const mockContent = {}; - ajaxDoneStub.yields(mockContent); - - loadRemoteState({ - input: inputMock, - url: 'https://state.link.com/content', - }); - - sinon.assert.calledOnce($.ajax as any); - sinon.assert.calledWithExactly($.ajax as any, { - url: 'https://state.link.com/content', - dataType: 'text', - kbnXsrfToken: false, - headers: {}, - }); - - sinon.assert.calledTwice(inputMock.moveToNextRequestEdge); - sinon.assert.calledWithExactly(inputMock.moveToNextRequestEdge, true); - sinon.assert.calledOnce(inputMock.highlightCurrentRequestsAndUpdateActionBar); - sinon.assert.calledOnce(inputMock.updateActionsBar); - sinon.assert.calledOnce(inputMock.update); - sinon.assert.calledWithExactly(inputMock.update, sinon.match.same(mockContent)); - }); - - it('correctly loads state from GitHub API HTTPS links.', () => { - const mockContent = {}; - ajaxDoneStub.yields(mockContent); - - loadRemoteState({ - input: inputMock, - url: 'https://api.github.com/content', - }); - - sinon.assert.calledOnce($.ajax as any); - sinon.assert.calledWithExactly($.ajax as any, { - url: 'https://api.github.com/content', - dataType: 'text', - kbnXsrfToken: false, - headers: { Accept: 'application/vnd.github.v3.raw' }, - }); - - sinon.assert.calledTwice(inputMock.moveToNextRequestEdge); - sinon.assert.calledWithExactly(inputMock.moveToNextRequestEdge, true); - sinon.assert.calledOnce(inputMock.highlightCurrentRequestsAndUpdateActionBar); - sinon.assert.calledOnce(inputMock.updateActionsBar); - sinon.assert.calledOnce(inputMock.update); - sinon.assert.calledWithExactly(inputMock.update, sinon.match.same(mockContent)); - }); -}); diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/load_remote_editor_state.ts b/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/load_remote_editor_state.ts deleted file mode 100644 index b2f475036c5da..0000000000000 --- a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/load_remote_editor_state.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import $ from 'jquery'; - -// @ts-ignore -// import mappings from '../../../../../../public/quarantined/src/mappings'; - -/* eslint-disable no-console */ - -export interface InitializationArgs { - url: string; - input: any; -} - -export function loadRemoteState({ url, input }: InitializationArgs) { - const loadFrom = { - url, - // Having dataType here is required as it doesn't allow jQuery to `eval` content - // coming from the external source thereby preventing XSS attack. - dataType: 'text', - kbnXsrfToken: false, - headers: {}, - }; - - if (/https?:\/\/api.github.com/.test(url)) { - loadFrom.headers = { Accept: 'application/vnd.github.v3.raw' }; - } - - $.ajax(loadFrom).done(data => { - input.update(data); - input.moveToNextRequestEdge(true); - input.highlightCurrentRequestsAndUpdateActionBar(); - input.updateActionsBar(); - }); - input.moveToNextRequestEdge(true); -} diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_menu_actions.ts b/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_menu_actions.ts deleted file mode 100644 index b728df615fc9d..0000000000000 --- a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_menu_actions.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -// @ts-ignore -import { getEndpointFromPosition } from '../../../../../../public/quarantined/src/autocomplete'; - -export function autoIndent(editor: any, event: any) { - editor.autoIndent(); - event.preventDefault(); - editor.focus(); -} - -export function getDocumentation(editor: any, docLinkVersion: string): Promise { - return new Promise(resolve => { - editor.getRequestsInRange((requests: any) => { - if (!requests || requests.length === 0) { - resolve(null); - return; - } - const position = requests[0].range.end; - position.column = position.column - 1; - const endpoint = getEndpointFromPosition(editor, position, editor.parser); - if (endpoint && endpoint.documentation && endpoint.documentation.indexOf('http') !== -1) { - const nextDocumentation = endpoint.documentation - .replace('/master/', `/${docLinkVersion}/`) - .replace('/current/', `/${docLinkVersion}/`); - resolve(nextDocumentation); - } else { - resolve(null); - } - }); - }); -} diff --git a/src/legacy/core_plugins/console/np_ready/public/application/models/legacy_editor.test.ts b/src/legacy/core_plugins/console/np_ready/public/application/models/legacy_editor.test.ts deleted file mode 100644 index 0dc1bcc96ddee..0000000000000 --- a/src/legacy/core_plugins/console/np_ready/public/application/models/legacy_editor.test.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { Range as AceRange } from 'brace'; -import { LegacyEditor } from './legacy_editor'; - -describe('Legacy Editor', () => { - const aceMock: any = { - getValue() { - return 'ok'; - }, - - getCursorPosition() { - return { - row: 1, - column: 1, - }; - }, - - getSession() { - return { - replace(range: AceRange, value: string) {}, - getLine(n: number) { - return 'line'; - }, - doc: { - getTextRange(r: any) { - return ''; - }, - }, - getState(n: number) { - return n; - }, - }; - }, - }; - - // This is to ensure that we are correctly importing Ace's Range component - it('smoke tests for updates to ranges', () => { - const legacyEditor = new LegacyEditor(aceMock); - legacyEditor.getValueInRange({ - start: { lineNumber: 1, column: 1 }, - end: { lineNumber: 2, column: 2 }, - }); - legacyEditor.replace( - { - start: { lineNumber: 1, column: 1 }, - end: { lineNumber: 2, column: 2 }, - }, - 'test!' - ); - }); -}); diff --git a/src/legacy/core_plugins/console/np_ready/public/application/models/legacy_editor.ts b/src/legacy/core_plugins/console/np_ready/public/application/models/legacy_editor.ts deleted file mode 100644 index f8c3f425a1032..0000000000000 --- a/src/legacy/core_plugins/console/np_ready/public/application/models/legacy_editor.ts +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import ace from 'brace'; -import { Editor as IAceEditor } from 'brace'; -import { CoreEditor, Position, Range, Token, TokensProvider } from '../../types'; -import { AceTokensProvider } from '../../lib/ace_token_provider'; - -const _AceRange = ace.acequire('ace/range').Range; - -export class LegacyEditor implements CoreEditor { - constructor(private readonly editor: IAceEditor) {} - - getLineState(lineNumber: number) { - const session = this.editor.getSession(); - return session.getState(lineNumber - 1); - } - - getValueInRange({ start, end }: Range): string { - const session = this.editor.getSession(); - const aceRange = new _AceRange( - start.lineNumber - 1, - start.column - 1, - end.lineNumber - 1, - end.column - 1 - ); - return session.doc.getTextRange(aceRange); - } - - getTokenProvider(): TokensProvider { - return new AceTokensProvider(this.editor.getSession()); - } - - getValue(): string { - return this.editor.getValue(); - } - - getLineValue(lineNumber: number): string { - const session = this.editor.getSession(); - return session.getLine(lineNumber - 1); - } - - getCurrentPosition(): Position { - const cursorPosition = this.editor.getCursorPosition(); - return { - lineNumber: cursorPosition.row + 1, - column: cursorPosition.column + 1, - }; - } - - clearSelection(): void { - this.editor.clearSelection(); - } - - getTokenAt(pos: Position): Token | null { - const provider = this.getTokenProvider(); - return provider.getTokenAt(pos); - } - - insert(valueOrPos: string | Position, value?: string): void { - if (typeof valueOrPos === 'string') { - this.editor.insert(valueOrPos); - return; - } - const document = this.editor.getSession().getDocument(); - document.insert( - { - column: valueOrPos.column - 1, - row: valueOrPos.lineNumber - 1, - }, - value || '' - ); - } - - moveCursorToPosition(pos: Position): void { - this.editor.moveCursorToPosition({ row: pos.lineNumber - 1, column: pos.column - 1 }); - } - - replace({ start, end }: Range, value: string): void { - const aceRange = new _AceRange( - start.lineNumber - 1, - start.column - 1, - end.lineNumber - 1, - end.column - 1 - ); - const session = this.editor.getSession(); - session.replace(aceRange, value); - } - - getLines(startLine: number, endLine: number): string[] { - const session = this.editor.getSession(); - return session.getLines(startLine - 1, endLine - 1); - } -} diff --git a/src/legacy/core_plugins/console/np_ready/server/.gitkeep b/src/legacy/core_plugins/console/np_ready/server/.gitkeep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/legacy/core_plugins/console/public/README.md b/src/legacy/core_plugins/console/public/README.md deleted file mode 100644 index 3a53c46143793..0000000000000 --- a/src/legacy/core_plugins/console/public/README.md +++ /dev/null @@ -1,21 +0,0 @@ -## New Platform (NP) Ready vs Quarantined - -We want to move toward more modularised code in the Console app. -Part of the effort means separating out different console components -like: - -- The language parser -- The editor rendering component -- Autocomplete -- The UI container components - -In addition to this effort we want to bring Console in line with NP -requirements and ensure that we are not using angular and public ui -in this app anymore. - -The quarantined folder contains all of the code that has not been cleared -for living in the new platform as it has not been properly refactored -or has dependencies on, for example, UI public. - -Over time, the quarantined part of the code should shrink to nothing -and we should only have NP ready code. diff --git a/src/legacy/core_plugins/console/np_ready/kibana.json b/src/legacy/core_plugins/console/public/kibana.json similarity index 59% rename from src/legacy/core_plugins/console/np_ready/kibana.json rename to src/legacy/core_plugins/console/public/kibana.json index ed8e4d8f15830..3363af353912a 100644 --- a/src/legacy/core_plugins/console/np_ready/kibana.json +++ b/src/legacy/core_plugins/console/public/kibana.json @@ -2,5 +2,6 @@ "id": "console", "version": "kibana", "server": true, - "ui": true + "ui": true, + "requiredPlugins": ["home"] } diff --git a/src/legacy/core_plugins/console/np_ready/public/legacy.ts b/src/legacy/core_plugins/console/public/legacy.ts similarity index 62% rename from src/legacy/core_plugins/console/np_ready/public/legacy.ts rename to src/legacy/core_plugins/console/public/legacy.ts index 758ea81be88ad..c456d777187aa 100644 --- a/src/legacy/core_plugins/console/np_ready/public/legacy.ts +++ b/src/legacy/core_plugins/console/public/legacy.ts @@ -17,35 +17,35 @@ * under the License. */ -import 'brace'; -import 'brace/ext/language_tools'; -import 'brace/ext/searchbox'; -import 'brace/mode/json'; -import 'brace/mode/text'; - -/* eslint-disable @kbn/eslint/no-restricted-paths */ import { npSetup, npStart } from 'ui/new_platform'; import { I18nContext } from 'ui/i18n'; -/* eslint-enable @kbn/eslint/no-restricted-paths */ +import chrome from 'ui/chrome'; +import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue'; export interface XPluginSet { dev_tools: DevToolsSetup; home: HomePublicPluginSetup; __LEGACY: { I18nContext: any; + elasticsearchUrl: string; + category: FeatureCatalogueCategory; }; } -import { plugin } from '.'; -import { DevToolsSetup } from '../../../../../plugins/dev_tools/public'; -import { HomePublicPluginSetup } from '../../../../../plugins/home/public'; +import { plugin } from './np_ready'; +import { DevToolsSetup } from '../../../../plugins/dev_tools/public'; +import { HomePublicPluginSetup } from '../../../../plugins/home/public'; const pluginInstance = plugin({} as any); -pluginInstance.setup(npSetup.core, { - ...npSetup.plugins, - __LEGACY: { - I18nContext, - }, -}); -pluginInstance.start(npStart.core); +(async () => { + await pluginInstance.setup(npSetup.core, { + ...npSetup.plugins, + __LEGACY: { + elasticsearchUrl: chrome.getInjected('elasticsearchUrl'), + I18nContext, + category: FeatureCatalogueCategory.ADMIN, + }, + }); + await pluginInstance.start(npStart.core); +})(); diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/console_menu.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/console_menu.tsx similarity index 98% rename from src/legacy/core_plugins/console/np_ready/public/application/components/console_menu.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/components/console_menu.tsx index fd87c0b94ef5b..7842c15be267f 100644 --- a/src/legacy/core_plugins/console/np_ready/public/application/components/console_menu.tsx +++ b/src/legacy/core_plugins/console/public/np_ready/application/components/console_menu.tsx @@ -25,7 +25,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; interface Props { - getCurl: (cb: (text: string) => void) => void; + getCurl: () => Promise; getDocumentation: () => Promise; autoIndent: (ev?: React.MouseEvent) => void; addNotification?: (opts: { title: string }) => void; @@ -48,7 +48,7 @@ export class ConsoleMenu extends Component { mouseEnter = () => { if (this.state.isPopoverOpen) return; - this.props.getCurl(text => { + this.props.getCurl().then(text => { this.setState({ curlCode: text }); }); }; diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/editor_example.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/editor_example.tsx similarity index 80% rename from src/legacy/core_plugins/console/np_ready/public/application/components/editor_example.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/components/editor_example.tsx index 01bd3fcd78e53..ea08a06a9e39b 100644 --- a/src/legacy/core_plugins/console/np_ready/public/application/components/editor_example.tsx +++ b/src/legacy/core_plugins/console/public/np_ready/application/components/editor_example.tsx @@ -20,9 +20,7 @@ import React, { useEffect } from 'react'; // @ts-ignore import exampleText from 'raw-loader!../constants/help_example.txt'; -import $ from 'jquery'; -// @ts-ignore -import SenseEditor from '../../../../public/quarantined/src/sense_editor/editor'; +import { createReadOnlyAceEditor } from '../models/legacy_core_editor'; interface EditorExampleProps { panel: string; @@ -32,11 +30,9 @@ export function EditorExample(props: EditorExampleProps) { const elemId = `help-example-${props.panel}`; useEffect(() => { - const el = $(`#${elemId}`); - el.text(exampleText.trim()); - const editor = new SenseEditor(el); - editor.setReadOnly(true); - editor.$blockScrolling = Infinity; + const el = document.querySelector(`#${elemId}`)!; + el.textContent = exampleText.trim(); + const editor = createReadOnlyAceEditor(el); return () => { editor.destroy(); diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/help_panel.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/help_panel.tsx similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/components/help_panel.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/components/help_panel.tsx diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/components/index.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/components/index.ts rename to src/legacy/core_plugins/console/public/np_ready/application/components/index.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/settings_modal.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/settings_modal.tsx similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/components/settings_modal.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/components/settings_modal.tsx diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/__snapshots__/split_panel.test.tsx.snap b/src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/__snapshots__/split_panel.test.tsx.snap similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/__snapshots__/split_panel.test.tsx.snap rename to src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/__snapshots__/split_panel.test.tsx.snap diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/components/resizer.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/components/resizer.tsx similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/components/resizer.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/components/resizer.tsx diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/containers/panel.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/containers/panel.tsx similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/containers/panel.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/containers/panel.tsx diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/containers/panel_container.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/containers/panel_container.tsx similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/containers/panel_container.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/containers/panel_container.tsx diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/context.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/context.tsx similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/context.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/context.tsx diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/index.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/index.ts rename to src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/index.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/registry.ts b/src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/registry.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/registry.ts rename to src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/registry.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/split_panel.test.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/split_panel.test.tsx similarity index 98% rename from src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/split_panel.test.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/split_panel.test.tsx index e60912a29355b..304535421a78a 100644 --- a/src/legacy/core_plugins/console/np_ready/public/application/components/split_panel/split_panel.test.tsx +++ b/src/legacy/core_plugins/console/public/np_ready/application/components/split_panel/split_panel.test.tsx @@ -22,7 +22,7 @@ import { mount } from 'enzyme'; import toJson from 'enzyme-to-json'; import { spy } from 'sinon'; -import { PanelsContainer, Panel } from '.'; +import { PanelsContainer, Panel } from './index'; const testComponentA =

A

; const testComponentB =

B

; diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/top_nav_menu.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/top_nav_menu.tsx similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/components/top_nav_menu.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/components/top_nav_menu.tsx diff --git a/src/legacy/core_plugins/console/np_ready/public/application/components/welcome_panel.tsx b/src/legacy/core_plugins/console/public/np_ready/application/components/welcome_panel.tsx similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/components/welcome_panel.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/components/welcome_panel.tsx diff --git a/src/legacy/core_plugins/console/np_ready/public/application/constants/help_example.txt b/src/legacy/core_plugins/console/public/np_ready/application/constants/help_example.txt similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/constants/help_example.txt rename to src/legacy/core_plugins/console/public/np_ready/application/constants/help_example.txt diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/console_history/console_history.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/console_history.tsx similarity index 98% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/console_history/console_history.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/console_history.tsx index 30966a2f77e1d..8ec8b9c61bf03 100644 --- a/src/legacy/core_plugins/console/np_ready/public/application/containers/console_history/console_history.tsx +++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/console_history.tsx @@ -175,7 +175,7 @@ export function ConsoleHistory({ close }: Props) { role="option" onMouseEnter={() => setViewingReq(req)} onMouseLeave={() => setViewingReq(selectedReq.current)} - onDoubleClick={restoreRequestFromHistory} + onDoubleClick={() => restoreRequestFromHistory(selectedReq.current)} aria-label={i18n.translate('console.historyPage.itemOfRequestListAriaLabel', { defaultMessage: 'Request: {historyItem}', values: { historyItem: reqDescription }, diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/console_history/history_viewer.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/history_viewer.tsx similarity index 83% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/console_history/history_viewer.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/history_viewer.tsx index 6fbb46bba6212..2a5ffee149b92 100644 --- a/src/legacy/core_plugins/console/np_ready/public/application/containers/console_history/history_viewer.tsx +++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/history_viewer.tsx @@ -19,13 +19,14 @@ import React, { useEffect, useRef } from 'react'; import { i18n } from '@kbn/i18n'; -import $ from 'jquery'; import { DevToolsSettings } from '../../../services'; import { subscribeResizeChecker } from '../editor/legacy/subscribe_console_resize_checker'; // @ts-ignore -import SenseEditor from '../../../../../public/quarantined/src/sense_editor/editor'; +import * as InputMode from '../../models/legacy_core_editor/mode/input'; +const inputMode = new InputMode.Mode(); +import * as editor from '../../models/legacy_core_editor'; import { applyCurrentSettings } from '../editor/legacy/console_editor/apply_editor_settings'; interface Props { @@ -35,13 +36,11 @@ interface Props { export function HistoryViewer({ settings, req }: Props) { const divRef = useRef(null); - const viewerRef = useRef(null); + const viewerRef = useRef(null); useEffect(() => { - const viewer = new SenseEditor($(divRef.current!)); + const viewer = editor.createReadOnlyAceEditor(divRef.current!); viewerRef.current = viewer; - viewer.renderer.setShowPrintMargin(false); - viewer.$blockScrolling = Infinity; const unsubscribe = subscribeResizeChecker(divRef.current!, viewer); return () => unsubscribe(); }, []); @@ -54,13 +53,14 @@ export function HistoryViewer({ settings, req }: Props) { const { current: viewer } = viewerRef; if (req) { const s = req.method + ' ' + req.endpoint + '\n' + (req.data || ''); - viewer.setValue(s); + viewer.update(s, inputMode); viewer.clearSelection(); } else { - viewer.getSession().setValue( + viewer.update( i18n.translate('console.historyPage.noHistoryTextMessage', { defaultMessage: 'No history available', - }) + }), + inputMode ); } } diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/console_history/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/index.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/console_history/index.ts rename to src/legacy/core_plugins/console/public/np_ready/application/containers/console_history/index.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/editor.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/editor.tsx similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/editor.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/editor.tsx diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/index.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/index.ts rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/index.ts diff --git a/src/legacy/core_plugins/console/public/quarantined/src/__tests__/utils.js b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/apply_editor_settings.ts similarity index 56% rename from src/legacy/core_plugins/console/public/quarantined/src/__tests__/utils.js rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/apply_editor_settings.ts index fa88e42fa557f..f9cfadf7fe34b 100644 --- a/src/legacy/core_plugins/console/public/quarantined/src/__tests__/utils.js +++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/apply_editor_settings.ts @@ -17,20 +17,21 @@ * under the License. */ -import expect from '@kbn/expect'; +import { DevToolsSettings } from '../../../../../services'; +import { CoreEditor } from '../../../../../types'; +import { CustomAceEditor } from '../../../../models/legacy_core_editor'; -import utils from '../utils'; - -describe('console utils', () => { - describe('collapseLiteralStrings', () => { - it('will collapse multiline strings', () => { - const multiline = '{ "foo": """bar\nbaz""" }'; - expect(utils.collapseLiteralStrings(multiline)).to.be('{ "foo": "bar\\nbaz" }'); - }); - - it('will collapse multiline strings with CRLF endings', () => { - const multiline = '{ "foo": """bar\r\nbaz""" }'; - expect(utils.collapseLiteralStrings(multiline)).to.be('{ "foo": "bar\\r\\nbaz" }'); +export function applyCurrentSettings( + editor: CoreEditor | CustomAceEditor, + settings: DevToolsSettings +) { + if ((editor as any).setStyles) { + (editor as CoreEditor).setStyles({ + wrapLines: settings.wrapMode, + fontSize: settings.fontSize + 'px', }); - }); -}); + } else { + (editor as CustomAceEditor).getSession().setUseWrapMode(settings.wrapMode); + (editor as CustomAceEditor).container.style.fontSize = settings.fontSize + 'px'; + } +} diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor.test.mock.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.test.mock.tsx similarity index 75% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor.test.mock.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.test.mock.tsx index a9db5cfcac3eb..5df72c0f03496 100644 --- a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor.test.mock.tsx +++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.test.mock.tsx @@ -21,24 +21,27 @@ jest.mock('../../../../contexts/editor_context/editor_registry.ts', () => ({ instance: { setInputEditor: () => {}, getInputEditor: () => ({ - getRequestsInRange: (cb: any) => cb([{ test: 'test' }]), + getRequestsInRange: async () => [{ test: 'test' }], }), }, })); jest.mock('../../../../components/editor_example.tsx', () => {}); -jest.mock('../../../../../../../public/quarantined/src/mappings.js', () => ({ +jest.mock('../../../../../lib/mappings/mappings', () => ({ retrieveAutoCompleteInfo: () => {}, clearSubscriptions: () => {}, })); -jest.mock('../../../../../../../public/quarantined/src/input.ts', () => { +jest.mock('../../../../models/sense_editor', () => { return { - initializeEditor: () => ({ - $el: { - css: () => {}, - }, - focus: () => {}, - update: () => {}, - getSession: () => ({ on: () => {}, setUseWrapMode: () => {} }), + create: () => ({ + getCoreEditor: () => ({ + registerKeyboardShortcut: jest.fn(), + setStyles: jest.fn(), + getContainer: () => ({ + focus: () => {}, + }), + on: jest.fn(), + }), + update: jest.fn(), commands: { addCommand: () => {}, }, diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor.test.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.test.tsx similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor.test.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.test.tsx diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.tsx similarity index 78% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.tsx index b99249b2b0016..442ed330e9b7a 100644 --- a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor.tsx +++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.tsx @@ -21,8 +21,6 @@ import React, { CSSProperties, useCallback, useEffect, useRef, useState } from ' import { EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import $ from 'jquery'; - import { EuiIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { useServicesContext, useEditorReadContext } from '../../../../contexts'; import { useUIAceKeyboardMode } from '../use_ui_ace_keyboard_mode'; @@ -34,17 +32,11 @@ import { applyCurrentSettings } from './apply_editor_settings'; import { useSendCurrentRequestToES, useSetInputEditor } from '../../../../hooks'; +import * as senseEditor from '../../../../models/sense_editor'; // @ts-ignore -import { initializeEditor } from '../../../../../../../public/quarantined/src/input'; -// @ts-ignore -import mappings from '../../../../../../../public/quarantined/src/mappings'; +import mappings from '../../../../../lib/mappings/mappings'; import { subscribeResizeChecker } from '../subscribe_console_resize_checker'; -import { loadRemoteState } from './load_remote_editor_state'; - -export interface EditorProps { - previousStateLocation?: 'stored' | string; -} const abs: CSSProperties = { position: 'absolute', @@ -61,10 +53,11 @@ const DEFAULT_INPUT_VALUE = `GET _search } }`; -function EditorUI({ previousStateLocation = 'stored' }: EditorProps) { +function EditorUI() { const { services: { history, notifications }, docLinkVersion, + elasticsearchUrl, } = useServicesContext(); const { settings } = useEditorReadContext(); @@ -72,8 +65,7 @@ function EditorUI({ previousStateLocation = 'stored' }: EditorProps) { const sendCurrentRequestToES = useSendCurrentRequestToES(); const editorRef = useRef(null); - const actionsRef = useRef(null); - const editorInstanceRef = useRef(null); + const editorInstanceRef = useRef(null); const [textArea, setTextArea] = useState(null); useUIAceKeyboardMode(textArea); @@ -87,24 +79,18 @@ function EditorUI({ previousStateLocation = 'stored' }: EditorProps) { }, [docLinkVersion]); useEffect(() => { - const $editor = $(editorRef.current!); - const $actions = $(actionsRef.current!); - editorInstanceRef.current = initializeEditor($editor, $actions); - - if (previousStateLocation === 'stored') { - const { content } = history.getSavedEditorState() || { - content: DEFAULT_INPUT_VALUE, - }; - editorInstanceRef.current.update(content); - } else { - loadRemoteState({ url: previousStateLocation, input: editorInstanceRef.current }); - } + editorInstanceRef.current = senseEditor.create(editorRef.current!); + + const { content: text } = history.getSavedEditorState() || { + content: DEFAULT_INPUT_VALUE, + }; + editorInstanceRef.current.update(text); function setupAutosave() { let timer: number; const saveDelay = 500; - editorInstanceRef.current.getSession().on('change', function onChange() { + editorInstanceRef.current!.getCoreEditor().on('change', () => { if (timer) { clearTimeout(timer); } @@ -114,7 +100,7 @@ function EditorUI({ previousStateLocation = 'stored' }: EditorProps) { function saveCurrentState() { try { - const content = editorInstanceRef.current.getValue(); + const content = editorInstanceRef.current!.getCoreEditor().getValue(); history.updateCurrentState(content); } catch (e) { // Ignoring saving error @@ -128,7 +114,7 @@ function EditorUI({ previousStateLocation = 'stored' }: EditorProps) { const unsubscribeResizer = subscribeResizeChecker( editorRef.current!, - editorInstanceRef.current + editorInstanceRef.current.getCoreEditor() ); setupAutosave(); @@ -136,17 +122,20 @@ function EditorUI({ previousStateLocation = 'stored' }: EditorProps) { unsubscribeResizer(); mappings.clearSubscriptions(); }; - }, [history, previousStateLocation, setInputEditor]); + }, [history, setInputEditor]); useEffect(() => { - applyCurrentSettings(editorInstanceRef.current!, settings); + applyCurrentSettings(editorInstanceRef.current!.getCoreEditor(), settings); // Preserve legacy focus behavior after settings have updated. - editorInstanceRef.current!.focus(); + editorInstanceRef + .current!.getCoreEditor() + .getContainer() + .focus(); }, [settings]); useEffect(() => { registerCommands({ - input: editorInstanceRef.current, + senseEditor: editorInstanceRef.current!, sendCurrentRequestToES, openDocumentation, }); @@ -157,7 +146,6 @@ function EditorUI({ previousStateLocation = 'stored' }: EditorProps) {
    { - editorInstanceRef.current!.getRequestsAsCURL(cb); + getCurl={() => { + return editorInstanceRef.current!.getRequestsAsCURL(elasticsearchUrl); }} getDocumentation={() => { return getDocumentation(editorInstanceRef.current!, docLinkVersion); diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor_output.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor_output.tsx similarity index 78% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor_output.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor_output.tsx index 3690ea61d5684..b1398d0a19a8f 100644 --- a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/editor_output.tsx +++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor_output.tsx @@ -18,18 +18,14 @@ */ import React, { useEffect, useRef } from 'react'; -import $ from 'jquery'; - -// @ts-ignore -import { initializeOutput } from '../../../../../../../public/quarantined/src/output'; +import { createReadOnlyAceEditor, CustomAceEditor } from '../../../../models/legacy_core_editor'; import { useServicesContext, useEditorReadContext, useRequestReadContext, } from '../../../../contexts'; -// @ts-ignore -import utils from '../../../../../../../public/quarantined/src/utils'; +import * as utils from '../../../../../lib/utils/utils'; import { subscribeResizeChecker } from '../subscribe_console_resize_checker'; import { applyCurrentSettings } from './apply_editor_settings'; @@ -45,7 +41,7 @@ function modeForContentType(contentType: string) { function EditorOutputUI() { const editorRef = useRef(null); - const editorInstanceRef = useRef(null); + const editorInstanceRef = useRef(null); const { services } = useServicesContext(); const { settings: readOnlySettings } = useEditorReadContext(); @@ -54,8 +50,7 @@ function EditorOutputUI() { } = useRequestReadContext(); useEffect(() => { - const editor$ = $(editorRef.current!); - editorInstanceRef.current = initializeOutput(editor$, services.settings); + editorInstanceRef.current = createReadOnlyAceEditor(editorRef.current!); const unsubscribe = subscribeResizeChecker(editorRef.current!, editorInstanceRef.current); return () => { @@ -64,25 +59,26 @@ function EditorOutputUI() { }, [services.settings]); useEffect(() => { + const editor = editorInstanceRef.current!; if (data) { const mode = modeForContentType(data[0].response.contentType); - editorInstanceRef.current.session.setMode(mode); - editorInstanceRef.current.update( + editor.session.setMode(mode); + editor.update( data - .map(d => d.response.value) + .map(d => d.response.value as string) .map(readOnlySettings.tripleQuotes ? utils.expandLiteralStrings : a => a) .join('\n') ); } else if (error) { - editorInstanceRef.current.session.setMode(modeForContentType(error.contentType)); - editorInstanceRef.current.update(error.value); + editor.session.setMode(modeForContentType(error.contentType)); + editor.update(error.value); } else { - editorInstanceRef.current.update(''); + editor.update(''); } }, [readOnlySettings, data, error]); useEffect(() => { - applyCurrentSettings(editorInstanceRef.current, readOnlySettings); + applyCurrentSettings(editorInstanceRef.current!, readOnlySettings); }, [readOnlySettings]); return ( diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/index.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/index.ts rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/index.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/keyboard_shortcuts.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/keyboard_shortcuts.ts similarity index 55% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/keyboard_shortcuts.ts rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/keyboard_shortcuts.ts index d1605c1aefa56..39621a9cb3dd2 100644 --- a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/keyboard_shortcuts.ts +++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/keyboard_shortcuts.ts @@ -17,49 +17,60 @@ * under the License. */ import { throttle } from 'lodash'; +import { SenseEditor } from '../../../../models/sense_editor'; interface Actions { - input: any; // TODO: Wrap this in an editor interface + senseEditor: SenseEditor; sendCurrentRequestToES: () => void; openDocumentation: () => void; } -export function registerCommands({ input, sendCurrentRequestToES, openDocumentation }: Actions) { - const throttledAutoIndent = throttle(() => input.autoIndent(), 500, { +export function registerCommands({ + senseEditor, + sendCurrentRequestToES, + openDocumentation, +}: Actions) { + const throttledAutoIndent = throttle(() => senseEditor.autoIndent(), 500, { leading: true, trailing: true, }); - input.commands.addCommand({ - name: 'send to elasticsearch', - bindKey: { win: 'Ctrl-Enter', mac: 'Command-Enter' }, - exec: () => sendCurrentRequestToES(), + const coreEditor = senseEditor.getCoreEditor(); + + coreEditor.registerKeyboardShortcut({ + keys: { win: 'Ctrl-Enter', mac: 'Command-Enter' }, + name: 'send to Elasticsearch', + fn: () => sendCurrentRequestToES(), }); - input.commands.addCommand({ + + coreEditor.registerKeyboardShortcut({ name: 'open documentation', - bindKey: { win: 'Ctrl-/', mac: 'Command-/' }, - exec: () => { + keys: { win: 'Ctrl-/', mac: 'Command-/' }, + fn: () => { openDocumentation(); }, }); - input.commands.addCommand({ + + coreEditor.registerKeyboardShortcut({ name: 'auto indent request', - bindKey: { win: 'Ctrl-I', mac: 'Command-I' }, - exec: () => { + keys: { win: 'Ctrl-I', mac: 'Command-I' }, + fn: () => { throttledAutoIndent(); }, }); - input.commands.addCommand({ + + coreEditor.registerKeyboardShortcut({ name: 'move to previous request start or end', - bindKey: { win: 'Ctrl-Up', mac: 'Command-Up' }, - exec: () => { - input.moveToPreviousRequestEdge(); + keys: { win: 'Ctrl-Up', mac: 'Command-Up' }, + fn: () => { + senseEditor.moveToPreviousRequestEdge(); }, }); - input.commands.addCommand({ + + coreEditor.registerKeyboardShortcut({ name: 'move to next request start or end', - bindKey: { win: 'Ctrl-Down', mac: 'Command-Down' }, - exec: () => { - input.moveToNextRequestEdge(); + keys: { win: 'Ctrl-Down', mac: 'Command-Down' }, + fn: () => { + senseEditor.moveToNextRequestEdge(false); }, }); } diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_menu_actions.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_menu_actions.ts new file mode 100644 index 0000000000000..797ff5744eec3 --- /dev/null +++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_menu_actions.ts @@ -0,0 +1,52 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// @ts-ignore +import { getEndpointFromPosition } from '../../../../lib/autocomplete/autocomplete'; +import { SenseEditor } from '../../../models/sense_editor'; + +export async function autoIndent(editor: SenseEditor, event: Event) { + event.preventDefault(); + await editor.autoIndent(); + editor + .getCoreEditor() + .getContainer() + .focus(); +} + +export function getDocumentation( + editor: SenseEditor, + docLinkVersion: string +): Promise { + return editor.getRequestsInRange().then(requests => { + if (!requests || requests.length === 0) { + return null; + } + const position = requests[0].range.end; + position.column = position.column - 1; + const endpoint = getEndpointFromPosition(editor, position, editor.parser); + if (endpoint && endpoint.documentation && endpoint.documentation.indexOf('http') !== -1) { + return endpoint.documentation + .replace('/master/', `/${docLinkVersion}/`) + .replace('/current/', `/${docLinkVersion}/`); + } else { + return null; + } + }); +} diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/index.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/index.ts rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/index.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/subscribe_console_resize_checker.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/subscribe_console_resize_checker.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/subscribe_console_resize_checker.ts rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/subscribe_console_resize_checker.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/use_ui_ace_keyboard_mode.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/use_ui_ace_keyboard_mode.tsx similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/use_ui_ace_keyboard_mode.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/use_ui_ace_keyboard_mode.tsx diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/index.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/index.ts rename to src/legacy/core_plugins/console/public/np_ready/application/containers/index.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/main/get_top_nav.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/main/get_top_nav.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/main/get_top_nav.ts rename to src/legacy/core_plugins/console/public/np_ready/application/containers/main/get_top_nav.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/main/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/containers/main/index.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/main/index.ts rename to src/legacy/core_plugins/console/public/np_ready/application/containers/main/index.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/main/main.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/main/main.tsx similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/main/main.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/containers/main/main.tsx diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/settings.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/settings.tsx similarity index 98% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/settings.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/containers/settings.tsx index 8440faa6eeea8..795103a5c95bb 100644 --- a/src/legacy/core_plugins/console/np_ready/public/application/containers/settings.tsx +++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/settings.tsx @@ -21,7 +21,7 @@ import React from 'react'; import { AutocompleteOptions, DevToolsSettingsModal } from '../components'; // @ts-ignore -import mappings from '../../../../public/quarantined/src/mappings'; +import mappings from '../../lib/mappings/mappings'; import { useServicesContext, useEditorActionContext } from '../contexts'; import { DevToolsSettings } from '../../services'; diff --git a/src/legacy/core_plugins/console/np_ready/public/application/contexts/create_use_context.ts b/src/legacy/core_plugins/console/public/np_ready/application/contexts/create_use_context.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/contexts/create_use_context.ts rename to src/legacy/core_plugins/console/public/np_ready/application/contexts/create_use_context.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/contexts/editor_context/editor_context.tsx b/src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/editor_context.tsx similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/contexts/editor_context/editor_context.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/editor_context.tsx diff --git a/src/legacy/core_plugins/console/np_ready/public/application/contexts/editor_context/editor_registry.ts b/src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/editor_registry.ts similarity index 85% rename from src/legacy/core_plugins/console/np_ready/public/application/contexts/editor_context/editor_registry.ts rename to src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/editor_registry.ts index bdccc1af0860c..64b0cddb4189b 100644 --- a/src/legacy/core_plugins/console/np_ready/public/application/contexts/editor_context/editor_registry.ts +++ b/src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/editor_registry.ts @@ -17,15 +17,17 @@ * under the License. */ +import { SenseEditor } from '../../models/sense_editor'; + export class EditorRegistry { - inputEditor: any; + inputEditor: SenseEditor | undefined; - setInputEditor(inputEditor: any) { + setInputEditor(inputEditor: SenseEditor) { this.inputEditor = inputEditor; } getInputEditor() { - return this.inputEditor; + return this.inputEditor!; } } diff --git a/src/legacy/core_plugins/console/np_ready/public/application/contexts/editor_context/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/index.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/contexts/editor_context/index.ts rename to src/legacy/core_plugins/console/public/np_ready/application/contexts/editor_context/index.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/contexts/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/contexts/index.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/contexts/index.ts rename to src/legacy/core_plugins/console/public/np_ready/application/contexts/index.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/contexts/request_context.tsx b/src/legacy/core_plugins/console/public/np_ready/application/contexts/request_context.tsx similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/contexts/request_context.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/contexts/request_context.tsx diff --git a/src/legacy/core_plugins/console/np_ready/public/application/contexts/services_context.tsx b/src/legacy/core_plugins/console/public/np_ready/application/contexts/services_context.tsx similarity index 98% rename from src/legacy/core_plugins/console/np_ready/public/application/contexts/services_context.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/contexts/services_context.tsx index f715b1ae53a78..77f0924a51842 100644 --- a/src/legacy/core_plugins/console/np_ready/public/application/contexts/services_context.tsx +++ b/src/legacy/core_plugins/console/public/np_ready/application/contexts/services_context.tsx @@ -28,6 +28,7 @@ interface ContextValue { settings: Settings; notifications: NotificationsSetup; }; + elasticsearchUrl: string; docLinkVersion: string; } diff --git a/src/legacy/core_plugins/console/np_ready/public/application/factories/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/factories/index.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/factories/index.ts rename to src/legacy/core_plugins/console/public/np_ready/application/factories/index.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/factories/token_iterator.ts b/src/legacy/core_plugins/console/public/np_ready/application/factories/token_iterator.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/factories/token_iterator.ts rename to src/legacy/core_plugins/console/public/np_ready/application/factories/token_iterator.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/hooks/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/hooks/index.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/hooks/index.ts rename to src/legacy/core_plugins/console/public/np_ready/application/hooks/index.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_restore_request_from_history/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/index.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/hooks/use_restore_request_from_history/index.ts rename to src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/index.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_restore_request_from_history/restore_request_from_history.ts b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/restore_request_from_history.ts similarity index 59% rename from src/legacy/core_plugins/console/np_ready/public/application/hooks/use_restore_request_from_history/restore_request_from_history.ts rename to src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/restore_request_from_history.ts index b053e605b5fae..24af2df69809f 100644 --- a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_restore_request_from_history/restore_request_from_history.ts +++ b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/restore_request_from_history.ts @@ -17,26 +17,29 @@ * under the License. */ +import RowParser from '../../../lib/row_parser'; +import { SenseEditor } from '../../models/sense_editor'; /** * This function is considered legacy and should not be changed or updated before we have editor * interfaces in place (it's using a customized version of Ace directly). */ -export function restoreRequestFromHistory(input: any, req: any) { - const session = input.getSession(); - let pos = input.getCursorPosition(); +export function restoreRequestFromHistory(editor: SenseEditor, req: any) { + const coreEditor = editor.getCoreEditor(); + let pos = coreEditor.getCurrentPosition(); let prefix = ''; let suffix = '\n'; - if (input.parser.isStartRequestRow(pos.row)) { - pos.column = 0; + const parser = new RowParser(coreEditor); + if (parser.isStartRequestRow(pos.lineNumber)) { + pos.column = 1; suffix += '\n'; - } else if (input.parser.isEndRequestRow(pos.row)) { - const line = session.getLine(pos.row); - pos.column = line.length; + } else if (parser.isEndRequestRow(pos.lineNumber)) { + const line = coreEditor.getLineValue(pos.lineNumber); + pos.column = line.length + 1; prefix = '\n\n'; - } else if (input.parser.isInBetweenRequestsRow(pos.row)) { - pos.column = 0; + } else if (parser.isInBetweenRequestsRow(pos.lineNumber)) { + pos.column = 1; } else { - pos = input.nextRequestEnd(pos); + pos = editor.nextRequestEnd(pos); prefix = '\n\n'; } @@ -47,8 +50,8 @@ export function restoreRequestFromHistory(input: any, req: any) { s += suffix; - session.insert(pos, s); - input.clearSelection(); - input.moveCursorTo(pos.row + prefix.length, 0); - input.focus(); + coreEditor.insert(pos, s); + coreEditor.moveCursorToPosition({ lineNumber: pos.lineNumber + prefix.length, column: 1 }); + coreEditor.clearSelection(); + coreEditor.getContainer().focus(); } diff --git a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts rename to src/legacy/core_plugins/console/public/np_ready/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_send_current_request_to_es/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/index.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/hooks/use_send_current_request_to_es/index.ts rename to src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/index.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_send_current_request_to_es/send_request_to_es.ts b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/send_request_to_es.ts similarity index 96% rename from src/legacy/core_plugins/console/np_ready/public/application/hooks/use_send_current_request_to_es/send_request_to_es.ts rename to src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/send_request_to_es.ts index 22fa4477e9012..11c1f6638e9cf 100644 --- a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_send_current_request_to_es/send_request_to_es.ts +++ b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/send_request_to_es.ts @@ -17,10 +17,9 @@ * under the License. */ +import * as utils from '../../../lib/utils/utils'; // @ts-ignore -import utils from '../../../../../public/quarantined/src/utils'; -// @ts-ignore -import * as es from '../../../../../public/quarantined/src/es'; +import * as es from '../../../lib/es/es'; import { BaseResponseType } from '../../../types/common'; export interface EsRequestArgs { diff --git a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_send_current_request_to_es/use_send_current_request_to_es.ts b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/use_send_current_request_to_es.ts similarity index 94% rename from src/legacy/core_plugins/console/np_ready/public/application/hooks/use_send_current_request_to_es/use_send_current_request_to_es.ts rename to src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/use_send_current_request_to_es.ts index 52661103b2d13..b51c29f8e9db6 100644 --- a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_send_current_request_to_es/use_send_current_request_to_es.ts +++ b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_send_current_request_to_es/use_send_current_request_to_es.ts @@ -23,7 +23,7 @@ import { useServicesContext } from '../../contexts'; import { sendRequestToES } from './send_request_to_es'; import { useRequestActionContext } from '../../contexts'; // @ts-ignore -import mappings from '../../../../../public/quarantined/src/mappings'; +import mappings from '../../../lib/mappings/mappings'; export const useSendCurrentRequestToES = () => { const { @@ -36,7 +36,7 @@ export const useSendCurrentRequestToES = () => { dispatch({ type: 'sendRequest', payload: undefined }); try { const editor = registry.getInputEditor(); - const requests = await new Promise(resolve => editor.getRequestsInRange(resolve)); + const requests = await editor.getRequestsInRange(); if (!requests.length) { dispatch({ type: 'requestFail', diff --git a/src/legacy/core_plugins/console/np_ready/public/application/hooks/use_set_input_editor.ts b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_set_input_editor.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/hooks/use_set_input_editor.ts rename to src/legacy/core_plugins/console/public/np_ready/application/hooks/use_set_input_editor.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/index.tsx b/src/legacy/core_plugins/console/public/np_ready/application/index.tsx similarity index 91% rename from src/legacy/core_plugins/console/np_ready/public/application/index.tsx rename to src/legacy/core_plugins/console/public/np_ready/application/index.tsx index e181caf23d2cb..239e4320f00f8 100644 --- a/src/legacy/core_plugins/console/np_ready/public/application/index.tsx +++ b/src/legacy/core_plugins/console/public/np_ready/application/index.tsx @@ -18,7 +18,7 @@ */ import React from 'react'; -import { NotificationsSetup } from 'src/core/public'; +import { NotificationsSetup } from 'kibana/public'; import { ServicesContextProvider, EditorContextProvider, RequestContextProvider } from './contexts'; import { Main } from './containers'; import { createStorage, createHistory, createSettings, Settings } from '../services'; @@ -32,8 +32,9 @@ export function boot(deps: { docLinkVersion: string; I18nContext: any; notifications: NotificationsSetup; + elasticsearchUrl: string; }) { - const { I18nContext, notifications, docLinkVersion } = deps; + const { I18nContext, notifications, docLinkVersion, elasticsearchUrl } = deps; const storage = createStorage({ engine: window.localStorage, @@ -47,6 +48,7 @@ export function boot(deps: { { - let input; + let coreEditor; beforeEach(() => { // Set up our document body document.body.innerHTML = @@ -36,33 +33,25 @@ describe('Input Tokenization', () => {
    `; - input = initializeEditor( - $('#ConAppEditor'), - $('#ConAppEditorActions'), - ); - - input = initializeEditor( - $('#ConAppEditor'), - $('#ConAppEditorActions'), - ); - input.$el.show(); - input.autocomplete._test.removeChangeListener(); + coreEditor = create(document.querySelector('#ConAppEditor')); + + $(coreEditor.getContainer()).show(); }); afterEach(() => { - input.$el.hide(); - input.autocomplete._test.addChangeListener(); + $(coreEditor.getContainer()).hide(); }); function tokensAsList() { - const iter = new tokenIterator.TokenIterator(input.getSession(), 0, 0); + const iter = createTokenIterator({ editor: coreEditor, position: { lineNumber: 1, column: 1 } }); const ret = []; let t = iter.getCurrentToken(); - if (input.parser.isEmptyToken(t)) { - t = input.parser.nextNonEmptyToken(iter); + const parser = new RowParser(coreEditor); + if (parser.isEmptyToken(t)) { + t = parser.nextNonEmptyToken(iter); } while (t) { ret.push({ value: t.value, type: t.type }); - t = input.parser.nextNonEmptyToken(iter); + t = parser.nextNonEmptyToken(iter); } return ret; @@ -83,18 +72,15 @@ describe('Input Tokenization', () => { data = prefix; } - test('Token test ' + testCount++ + ' prefix: ' + prefix, async function (done) { - input.update(data, function () { - const tokens = tokensAsList(); - const normTokenList = []; - for (let i = 0; i < tokenList.length; i++) { - normTokenList.push({ type: tokenList[i++], value: tokenList[i] }); - } - - expect(tokens).toEqual(normTokenList); - done(); - }); + test('Token test ' + testCount++ + ' prefix: ' + prefix, async function () { + await coreEditor.setValue(data, true); + const tokens = tokensAsList(); + const normTokenList = []; + for (let i = 0; i < tokenList.length; i++) { + normTokenList.push({ type: tokenList[i++], value: tokenList[i] }); + } + expect(tokens).toEqual(normTokenList); }); } @@ -271,10 +257,8 @@ describe('Input Tokenization', () => { function statesAsList() { const ret = []; - const session = input.getSession(); - const maxLine = session.getLength(); - for (let row = 0; row < maxLine; row++) ret.push(session.getState(row)); - + const maxLine = coreEditor.getLineCount(); + for (let line = 1; line <= maxLine; line++) ret.push(coreEditor.getLineState(line)); return ret; } @@ -292,12 +276,10 @@ describe('Input Tokenization', () => { data = prefix; } - test('States test ' + testCount++ + ' prefix: ' + prefix, async function (done) { - input.update(data, function () { - const modes = statesAsList(); - expect(modes).toEqual(statesList); - done(); - }); + test('States test ' + testCount++ + ' prefix: ' + prefix, async function () { + await coreEditor.setValue(data, true); + const modes = statesAsList(); + expect(modes).toEqual(statesList); }); } diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/output_tokenization.test.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/__tests__/output_tokenization.test.js similarity index 89% rename from src/legacy/core_plugins/console/public/quarantined/tests/src/output_tokenization.test.js rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/__tests__/output_tokenization.test.js index 36c081f5ef923..b860f691dadb2 100644 --- a/src/legacy/core_plugins/console/public/quarantined/tests/src/output_tokenization.test.js +++ b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/__tests__/output_tokenization.test.js @@ -16,26 +16,21 @@ * specific language governing permissions and limitations * under the License. */ -import './setup_mocks'; -import ace from 'brace'; -import 'brace/mode/javascript'; -import 'brace/mode/json'; - const $ = require('jquery'); -const RowParser = require('../../src/sense_editor/row_parser'); - -import { initializeOutput } from '../../src/output'; +import RowParser from '../../../../lib/row_parser'; +import ace from 'brace'; +import { createReadOnlyAceEditor } from '../create_readonly'; let output; - const tokenIterator = ace.acequire('ace/token_iterator'); describe('Output Tokenization', () => { beforeEach(() => { - output = initializeOutput($('#ConAppOutput')); - output.$el.show(); + output = createReadOnlyAceEditor(document.querySelector('#ConAppOutput')); + $(output.container).show(); }); + afterEach(() => { - output.$el.hide(); + $(output.container).hide(); }); function tokensAsList() { diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/create.ts b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/create.ts new file mode 100644 index 0000000000000..8e03182621c83 --- /dev/null +++ b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/create.ts @@ -0,0 +1,30 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import ace from 'brace'; +import { LegacyCoreEditor } from './legacy_core_editor'; + +export const create = (el: HTMLElement) => { + const actions = document.querySelector('#ConAppEditorActions'); + if (!actions) { + throw new Error('Could not find ConAppEditorActions element!'); + } + const aceEditor = ace.edit(el); + return new LegacyCoreEditor(aceEditor, actions); +}; diff --git a/src/legacy/core_plugins/console/public/quarantined/src/output.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/create_readonly.ts similarity index 70% rename from src/legacy/core_plugins/console/public/quarantined/src/output.js rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/create_readonly.ts index 42555f17f19c1..ce8ededd0b12c 100644 --- a/src/legacy/core_plugins/console/public/quarantined/src/output.js +++ b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/create_readonly.ts @@ -18,19 +18,28 @@ */ import _ from 'lodash'; -const ace = require('brace'); -const OutputMode = require('./sense_editor/mode/output'); -const smartResize = require('./smart_resize'); +import ace from 'brace'; +// @ts-ignore +import * as OutputMode from './mode/output'; +import smartResize from './smart_resize'; -let output; -export function initializeOutput($el) { - output = ace.acequire('ace/ace').edit($el[0]); +export interface CustomAceEditor extends ace.Editor { + update: (text: string, mode?: any, cb?: () => void) => void; + append: (text: string, foldPrevious?: boolean, cb?: () => void) => void; +} + +/** + * Note: using read-only ace editor leaks the Ace editor API - use this as sparingly as possible or + * create an interface for it so that we don't rely directly on vendor APIs. + */ +export function createReadOnlyAceEditor(element: HTMLElement): CustomAceEditor { + const output: CustomAceEditor = ace.acequire('ace/ace').edit(element); const outputMode = new OutputMode.Mode(); output.$blockScrolling = Infinity; output.resize = smartResize(output); - output.update = (val, mode, cb) => { + output.update = (val: string, mode?: any, cb?: () => void) => { if (typeof mode === 'function') { cb = mode; mode = void 0; @@ -45,7 +54,7 @@ export function initializeOutput($el) { } }; - output.append = (val, foldPrevious, cb) => { + output.append = (val: string, foldPrevious?: boolean, cb?: () => void) => { if (typeof foldPrevious === 'function') { cb = foldPrevious; foldPrevious = true; @@ -65,12 +74,10 @@ export function initializeOutput($el) { } }; - output.$el = $el; - // eslint-disable-next-line (function setupSession(session) { session.setMode('ace/mode/text'); - session.setFoldStyle('markbeginend'); + (session as any).setFoldStyle('markbeginend'); session.setTabSize(2); session.setUseWrapMode(true); })(output.getSession()); @@ -80,7 +87,3 @@ export function initializeOutput($el) { return output; } - -export default function getOutput() { - return output; -} diff --git a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/apply_editor_settings.ts b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/index.ts similarity index 75% rename from src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/apply_editor_settings.ts rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/index.ts index 8445863b6dfc3..7655bbcd106d2 100644 --- a/src/legacy/core_plugins/console/np_ready/public/application/containers/editor/legacy/console_editor/apply_editor_settings.ts +++ b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/index.ts @@ -17,9 +17,12 @@ * under the License. */ -import { DevToolsSettings } from '../../../../../services'; +import 'brace'; +import 'brace/ext/language_tools'; +import 'brace/ext/searchbox'; +import 'brace/mode/json'; +import 'brace/mode/text'; -export function applyCurrentSettings(editor: any, settings: DevToolsSettings) { - editor.getSession().setUseWrapMode(settings.wrapMode); - editor.$el.css('font-size', settings.fontSize + 'px'); -} +export * from './legacy_core_editor'; +export * from './create_readonly'; +export * from './create'; diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/setup_mocks.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.test.mocks.ts similarity index 69% rename from src/legacy/core_plugins/console/public/quarantined/tests/src/setup_mocks.js rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.test.mocks.ts index 203d8a20b1055..66673ff42e4e8 100644 --- a/src/legacy/core_plugins/console/public/quarantined/tests/src/setup_mocks.js +++ b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.test.mocks.ts @@ -16,23 +16,18 @@ * specific language governing permissions and limitations * under the License. */ -/* eslint no-undef: 0 */ -jest.mock('../../src/sense_editor/mode/worker', () => { - return { workerModule: { id: 'sense_editor/mode/worker', src: '' } }; -}); -jest.mock('ui/chrome', () => { - return { - getInjected() { - return 'http://localhost:9200'; - } - }; +jest.mock('./mode/worker', () => { + return { workerModule: { id: 'sense_editor/mode/worker', src: '' } }; }); -window.Worker = function () { +// @ts-ignore +window.Worker = function() { this.postMessage = () => {}; - this.terminate = () => {}; + (this as any).terminate = () => {}; }; + +// @ts-ignore window.URL = { createObjectURL: () => { return ''; @@ -45,14 +40,4 @@ import 'brace/ext/searchbox'; import 'brace/mode/json'; import 'brace/mode/text'; -jest.mock('../../../../np_ready/public/application', () => ({ legacyBackDoorToSettings: () => {}, })); - document.queryCommandSupported = () => true; - -import jQuery from 'jquery'; -jest.spyOn(jQuery, 'ajax').mockImplementation( - () => - new Promise(() => { - // never resolve - }) -); diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.ts b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.ts new file mode 100644 index 0000000000000..621f4eeb0163e --- /dev/null +++ b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.ts @@ -0,0 +1,340 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import ace from 'brace'; +import { Editor as IAceEditor } from 'brace'; +import $ from 'jquery'; +import { CoreEditor, Position, Range, Token, TokensProvider, EditorEvent } from '../../../types'; +import { AceTokensProvider } from '../../../lib/ace_token_provider'; +import * as curl from '../sense_editor/curl'; +import smartResize from './smart_resize'; + +// @ts-ignore +import * as InputMode from './mode/input'; + +const _AceRange = ace.acequire('ace/range').Range; + +const rangeToAceRange = ({ start, end }: Range) => + new _AceRange(start.lineNumber - 1, start.column - 1, end.lineNumber - 1, end.column - 1); + +export class LegacyCoreEditor implements CoreEditor { + private _aceOnPaste: any; + $actions: any; + resize: () => void; + + constructor(private readonly editor: IAceEditor, actions: HTMLElement) { + this.$actions = $(actions); + this.editor.setShowPrintMargin(false); + + const session = this.editor.getSession(); + session.setMode(new InputMode.Mode()); + (session as any).setFoldStyle('markbeginend'); + session.setTabSize(2); + session.setUseWrapMode(true); + + this.resize = smartResize(this.editor); + + // Intercept ace on paste handler. + this._aceOnPaste = this.editor.onPaste; + this.editor.onPaste = this.DO_NOT_USE_onPaste.bind(this); + + this.editor.setOptions({ + enableBasicAutocompletion: true, + }); + + this.editor.$blockScrolling = Infinity; + this.hideActionsBar(); + this.editor.focus(); + } + + // dirty check for tokenizer state, uses a lot less cycles + // than listening for tokenizerUpdate + waitForLatestTokens(): Promise { + return new Promise(resolve => { + const session = this.editor.getSession(); + const checkInterval = 25; + + const check = () => { + // If the bgTokenizer doesn't exist, we can assume that the underlying editor has been + // torn down, e.g. by closing the History tab, and we don't need to do anything further. + if (session.bgTokenizer) { + // Wait until the bgTokenizer is done running before executing the callback. + if ((session.bgTokenizer as any).running) { + setTimeout(check, checkInterval); + } else { + resolve(); + } + } + }; + + setTimeout(check, 0); + }); + } + + getLineState(lineNumber: number) { + const session = this.editor.getSession(); + return session.getState(lineNumber - 1); + } + + getValueInRange(range: Range): string { + return this.editor.getSession().getTextRange(rangeToAceRange(range)); + } + + getTokenProvider(): TokensProvider { + return new AceTokensProvider(this.editor.getSession()); + } + + getValue(): string { + return this.editor.getValue(); + } + + setValue(text: string, forceRetokenize: boolean): Promise { + const session = this.editor.getSession(); + session.setValue(text); + return new Promise(resolve => { + if (!forceRetokenize) { + // resolve immediately + resolve(); + return; + } + + // force update of tokens, but not on this thread to allow for ace rendering. + setTimeout(function() { + let i; + for (i = 0; i < session.getLength(); i++) { + session.getTokens(i); + } + resolve(); + }); + }); + } + + getLineValue(lineNumber: number): string { + const session = this.editor.getSession(); + return session.getLine(lineNumber - 1); + } + + getCurrentPosition(): Position { + const cursorPosition = this.editor.getCursorPosition(); + return { + lineNumber: cursorPosition.row + 1, + column: cursorPosition.column + 1, + }; + } + + clearSelection(): void { + this.editor.clearSelection(); + } + + getTokenAt(pos: Position): Token | null { + const provider = this.getTokenProvider(); + return provider.getTokenAt(pos); + } + + insert(valueOrPos: string | Position, value?: string): void { + if (typeof valueOrPos === 'string') { + this.editor.insert(valueOrPos); + return; + } + const document = this.editor.getSession().getDocument(); + document.insert( + { + column: valueOrPos.column - 1, + row: valueOrPos.lineNumber - 1, + }, + value || '' + ); + } + + moveCursorToPosition(pos: Position): void { + this.editor.moveCursorToPosition({ row: pos.lineNumber - 1, column: pos.column - 1 }); + } + + replace(range: Range, value: string): void { + const session = this.editor.getSession(); + session.replace(rangeToAceRange(range), value); + } + + getLines(startLine: number, endLine: number): string[] { + const session = this.editor.getSession(); + return session.getLines(startLine - 1, endLine - 1); + } + + replaceRange(range: Range, value: string) { + const pos = this.editor.getCursorPosition(); + this.editor.getSession().replace(rangeToAceRange(range), value); + + const maxRow = Math.max(range.start.lineNumber - 1 + value.split('\n').length - 1, 1); + pos.row = Math.min(pos.row, maxRow); + this.editor.moveCursorToPosition(pos); + // ACE UPGRADE - check if needed - at the moment the above may trigger a selection. + this.editor.clearSelection(); + } + + getSelectionRange() { + const result = this.editor.getSelectionRange(); + return { + start: { + lineNumber: result.start.row + 1, + column: result.start.column + 1, + }, + end: { + lineNumber: result.end.row + 1, + column: result.end.column + 1, + }, + }; + } + + getLineCount() { + const text = this.getValue(); + return text.split('\n').length; + } + + addMarker(range: Range) { + return this.editor + .getSession() + .addMarker(rangeToAceRange(range), 'ace_snippet-marker', 'fullLine', false); + } + + removeMarker(ref: any) { + this.editor.getSession().removeMarker(ref); + } + + getWrapLimit(): number { + return this.editor.getSession().getWrapLimit(); + } + + on(event: EditorEvent, listener: () => void) { + if (event === 'changeCursor') { + this.editor.getSession().selection.on(event, listener); + } else if (event === 'changeSelection') { + this.editor.on(event, listener); + } else { + this.editor.getSession().on(event, listener); + } + } + + off(event: EditorEvent, listener: () => void) { + if (event === 'changeSelection') { + this.editor.off(event, listener); + } + } + + isCompleterActive() { + // Secrets of the arcane here. + return Boolean((this.editor as any).completer && (this.editor as any).completer.activated); + } + + // eslint-disable-next-line @typescript-eslint/camelcase + private DO_NOT_USE_onPaste(text: string) { + if (text && curl.detectCURL(text)) { + const curlInput = curl.parseCURL(text); + this.editor.insert(curlInput); + return; + } + this._aceOnPaste.call(this.editor, text); + } + + private setActionsBar = (top?: any) => { + if (top === null) { + this.$actions.css('visibility', 'hidden'); + } else { + this.$actions.css({ + top, + visibility: 'visible', + }); + } + }; + + private hideActionsBar = () => { + this.setActionsBar(); + }; + + execCommand(cmd: string) { + this.editor.execCommand(cmd); + } + + getContainer(): HTMLDivElement { + return this.editor.container as HTMLDivElement; + } + + setStyles(styles: { wrapLines: boolean; fontSize: string }) { + this.editor.getSession().setUseWrapMode(styles.wrapLines); + this.editor.container.style.fontSize = styles.fontSize; + } + + registerKeyboardShortcut(opts: { keys: string; fn: () => void; name: string }): void { + this.editor.commands.addCommand({ + exec: opts.fn, + name: opts.name, + bindKey: opts.keys, + }); + } + + legacyUpdateUI(range: any) { + if (!this.$actions) { + return; + } + if (range) { + // elements are positioned relative to the editor's container + // pageY is relative to page, so subtract the offset + // from pageY to get the new top value + const offsetFromPage = $(this.editor.container).offset()!.top; + const startRow = range.start.lineNumber - 1; + const startColumn = range.start.column; + const firstLine = this.getLineValue(startRow); + const maxLineLength = this.getWrapLimit() - 5; + const isWrapping = firstLine.length > maxLineLength; + const getScreenCoords = (row: number) => + this.editor.renderer.textToScreenCoordinates(row, startColumn).pageY - offsetFromPage; + const topOfReq = getScreenCoords(startRow); + + if (topOfReq >= 0) { + let offset = 0; + if (isWrapping) { + // Try get the line height of the text area in pixels. + const textArea = $(this.editor.container.querySelector('textArea')!); + const hasRoomOnNextLine = this.getLineValue(startRow + 1).length < maxLineLength; + if (textArea && hasRoomOnNextLine) { + // Line height + the number of wraps we have on a line. + offset += this.getLineValue(startRow).length * textArea.height()!; + } else { + if (startRow > 0) { + this.setActionsBar(getScreenCoords(startRow - 1)); + return; + } + this.setActionsBar(getScreenCoords(startRow + 1)); + return; + } + } + this.setActionsBar(topOfReq + offset); + return; + } + + const bottomOfReq = + this.editor.renderer.textToScreenCoordinates(range.end.lineNumber, range.end.column).pageY - + offsetFromPage; + + if (bottomOfReq >= 0) { + this.setActionsBar(0); + return; + } + } + } +} diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/input.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/input.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/input.js rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/input.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/input_highlight_rules.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/input_highlight_rules.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/input_highlight_rules.js rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/input_highlight_rules.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/output.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/output.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/output.js rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/output.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/output_highlight_rules.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/output_highlight_rules.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/output_highlight_rules.js rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/output_highlight_rules.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/script.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/script.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/script.js rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/script.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/script_highlight_rules.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/script_highlight_rules.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/script_highlight_rules.js rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/script_highlight_rules.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/worker/index.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/worker/index.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/worker/index.js rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/worker/index.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/worker/worker.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/worker/worker.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/worker/worker.js rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/worker/worker.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/x_json_highlight_rules.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/x_json_highlight_rules.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/mode/x_json_highlight_rules.js rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/mode/x_json_highlight_rules.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/smart_resize.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/smart_resize.ts similarity index 92% rename from src/legacy/core_plugins/console/public/quarantined/src/smart_resize.js rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/smart_resize.ts index 8ac5eda345c23..b88e0e44591d8 100644 --- a/src/legacy/core_plugins/console/public/quarantined/src/smart_resize.js +++ b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/smart_resize.ts @@ -19,7 +19,8 @@ import { get, throttle } from 'lodash'; -export default function (editor) { +// eslint-disable-next-line import/no-default-export +export default function(editor: any) { const resize = editor.resize; const throttledResize = throttle(() => { diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/theme_sense_dark.js b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/theme_sense_dark.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/sense_editor/theme_sense_dark.js rename to src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/theme_sense_dark.js diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/editor_input1.txt b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/editor_input1.txt similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/tests/src/editor_input1.txt rename to src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/editor_input1.txt diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/integration.test.js b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/integration.test.js similarity index 80% rename from src/legacy/core_plugins/console/public/quarantined/tests/src/integration.test.js rename to src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/integration.test.js index 9df4aa5e0bece..0950992f1c0fe 100644 --- a/src/legacy/core_plugins/console/public/quarantined/tests/src/integration.test.js +++ b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/integration.test.js @@ -16,51 +16,44 @@ * specific language governing permissions and limitations * under the License. */ -import './setup_mocks'; -import 'brace'; -import 'brace/mode/json'; -import { initializeEditor } from '../../src/input'; +import '../sense_editor.test.mocks'; +import { create } from '../create'; import _ from 'lodash'; const $ = require('jquery'); -const kb = require('../../src/kb'); -const mappings = require('../../src/mappings'); - - +const kb = require('../../../../lib/kb/kb'); +const mappings = require('../../../../lib/mappings/mappings'); describe('Integration', () => { - let input; + let senseEditor; beforeEach(() => { // Set up our document body document.body.innerHTML = '
    '; - input = initializeEditor( - $('#ConAppEditor'), - $('#ConAppEditorActions') - ); - input.$el.show(); - input.autocomplete._test.removeChangeListener(); + senseEditor = create(document.querySelector('#ConAppEditor')); + $(senseEditor.getCoreEditor().getContainer()).show(); + senseEditor.autocomplete._test.removeChangeListener(); }); afterEach(() => { - input.$el.hide(); - input.autocomplete._test.addChangeListener(); + $(senseEditor.getCoreEditor().getContainer()).hide(); + senseEditor.autocomplete._test.addChangeListener(); }); function processContextTest(data, mapping, kbSchemes, requestLine, testToRun) { test(testToRun.name, async function (done) { - let rowOffset = 0; // add one for the extra method line + let lineOffset = 0; // add one for the extra method line let editorValue = data; if (requestLine != null) { if (data != null) { editorValue = requestLine + '\n' + data; - rowOffset = 1; + lineOffset = 1; } else { editorValue = requestLine; } } - testToRun.cursor.row += rowOffset; + testToRun.cursor.lineNumber += lineOffset; mappings.clear(); mappings.loadMappings(mapping); @@ -81,109 +74,104 @@ describe('Integration', () => { } kb.setActiveApi(testApi); const { cursor } = testToRun; - const { row, column } = cursor; - input.update(editorValue, function () { - input.moveCursorTo(row, column); + await senseEditor.update(editorValue, true); + senseEditor.getCoreEditor().moveCursorToPosition(cursor); - // allow ace rendering to move cursor so it will be seen during test - handy for debugging. - //setTimeout(function () { - input.completer = { - base: {}, - changeListener: function () {}, - }; // mimic auto complete + // allow ace rendering to move cursor so it will be seen during test - handy for debugging. + //setTimeout(function () { + senseEditor.completer = { + base: {}, + changeListener: function () {}, + }; // mimic auto complete - input.autocomplete._test.getCompletions( - input, - input.getSession(), - cursor, - '', - function (err, terms) { - if (testToRun.assertThrows) { - done(); - return; - } + senseEditor.autocomplete._test.getCompletions( + senseEditor, + null, + { row: cursor.lineNumber - 1, column: cursor.column - 1 }, + '', + function (err, terms) { + if (testToRun.assertThrows) { + done(); + return; + } - if (err) { - done(); - throw err; - } + if (err) { + throw err; + } - if (testToRun.no_context) { - expect(!terms || terms.length === 0).toBeTruthy(); - } else { - expect(terms).not.toBeNull(); - expect(terms.length).toBeGreaterThan(0); - } + if (testToRun.no_context) { + expect(!terms || terms.length === 0).toBeTruthy(); + } else { + expect(terms).not.toBeNull(); + expect(terms.length).toBeGreaterThan(0); + } - if (!terms || terms.length === 0) { - done(); - return; - } + if (!terms || terms.length === 0) { + done(); + return; + } - if (testToRun.autoCompleteSet) { - const expectedTerms = _.map(testToRun.autoCompleteSet, function (t) { - if (typeof t !== 'object') { - t = { name: t }; - } - return t; - }); - if (terms.length !== expectedTerms.length) { - expect(_.pluck(terms, 'name')).toEqual(_.pluck(expectedTerms, 'name')); - } else { - const filteredActualTerms = _.map(terms, function ( - actualTerm, - i - ) { - const expectedTerm = expectedTerms[i]; - const filteredTerm = {}; - _.each(expectedTerm, function (v, p) { - filteredTerm[p] = actualTerm[p]; - }); - return filteredTerm; - }); - expect(filteredActualTerms).toEqual(expectedTerms); + if (testToRun.autoCompleteSet) { + const expectedTerms = _.map(testToRun.autoCompleteSet, function (t) { + if (typeof t !== 'object') { + t = { name: t }; } - done(); + return t; + }); + if (terms.length !== expectedTerms.length) { + expect(_.pluck(terms, 'name')).toEqual(_.pluck(expectedTerms, 'name')); + } else { + const filteredActualTerms = _.map(terms, function ( + actualTerm, + i + ) { + const expectedTerm = expectedTerms[i]; + const filteredTerm = {}; + _.each(expectedTerm, function (v, p) { + filteredTerm[p] = actualTerm[p]; + }); + return filteredTerm; + }); + expect(filteredActualTerms).toEqual(expectedTerms); } + } - const context = terms[0].context; - const { cursor: { row, column } } = testToRun; - input.autocomplete._test.addReplacementInfoToContext( - context, - { lineNumber: row + 1, column: column + 1 }, - terms[0].value - ); + const context = terms[0].context; + const { cursor: { lineNumber, column } } = testToRun; + senseEditor.autocomplete._test.addReplacementInfoToContext( + context, + { lineNumber, column }, + terms[0].value + ); - function ac(prop, propTest) { - if (typeof testToRun[prop] !== 'undefined') { - if (propTest) { - propTest(context[prop], testToRun[prop], prop); - } else { - expect(context[prop]).toEqual(testToRun[prop]); - } + function ac(prop, propTest) { + if (typeof testToRun[prop] !== 'undefined') { + if (propTest) { + propTest(context[prop], testToRun[prop], prop); + } else { + expect(context[prop]).toEqual(testToRun[prop]); } } + } - function posCompare(actual, expected) { - expect(actual.lineNumber).toEqual(expected.lineNumber + rowOffset); - expect(actual.column).toEqual(expected.column); - } - - function rangeCompare(actual, expected, name) { - posCompare(actual.start, expected.start, name + '.start'); - posCompare(actual.end, expected.end, name + '.end'); - } + function posCompare(actual, expected) { + expect(actual.lineNumber).toEqual(expected.lineNumber + lineOffset); + expect(actual.column).toEqual(expected.column); + } - ac('prefixToAdd'); - ac('suffixToAdd'); - ac('addTemplate'); - ac('textBoxPosition', posCompare); - ac('rangeToReplace', rangeCompare); - done(); + function rangeCompare(actual, expected, name) { + posCompare(actual.start, expected.start, name + '.start'); + posCompare(actual.end, expected.end, name + '.end'); } - ); - //}); - }); + + ac('prefixToAdd'); + ac('suffixToAdd'); + ac('addTemplate'); + ac('textBoxPosition', posCompare); + ac('rangeToReplace', rangeCompare); + done(); + } + ); }); } @@ -236,7 +224,7 @@ describe('Integration', () => { contextTests({}, MAPPING, SEARCH_KB, 'POST _search', [ { name: 'Empty doc', - cursor: { row: 0, column: 1 }, + cursor: { lineNumber: 1, column: 2 }, initialValue: '', addTemplate: true, prefixToAdd: '', @@ -252,7 +240,7 @@ describe('Integration', () => { contextTests({}, MAPPING, SEARCH_KB, 'POST _no_context', [ { name: 'Missing KB', - cursor: { row: 0, column: 1 }, + cursor: { lineNumber: 1, column: 2 }, no_context: true, }, ]); @@ -276,7 +264,7 @@ describe('Integration', () => { [ { name: 'Missing KB - global auto complete', - cursor: { row: 2, column: 5 }, + cursor: { lineNumber: 3, column: 6 }, autoCompleteSet: ['t1'], }, ] @@ -296,7 +284,7 @@ describe('Integration', () => { [ { name: 'existing dictionary key, no template', - cursor: { row: 1, column: 6 }, + cursor: { lineNumber: 2, column: 6 }, initialValue: 'query', addTemplate: false, prefixToAdd: '', @@ -309,7 +297,7 @@ describe('Integration', () => { }, { name: 'existing inner dictionary key', - cursor: { row: 2, column: 7 }, + cursor: { lineNumber: 3, column: 8 }, initialValue: 'field', addTemplate: false, prefixToAdd: '', @@ -322,7 +310,7 @@ describe('Integration', () => { }, { name: 'existing dictionary key, yes template', - cursor: { row: 4, column: 7 }, + cursor: { lineNumber: 5, column: 8 }, initialValue: 'facets', addTemplate: true, prefixToAdd: '', @@ -335,13 +323,12 @@ describe('Integration', () => { }, { name: 'ignoring meta keys', - cursor: { row: 4, column: 14 }, + cursor: { lineNumber: 5, column: 15 }, no_context: true, }, ] ); - contextTests( '{\n' + ' "query": {\n' + @@ -356,7 +343,7 @@ describe('Integration', () => { [ { name: 'trailing comma, end of line', - cursor: { row: 4, column: 16 }, + cursor: { lineNumber: 5, column: 17 }, initialValue: '', addTemplate: true, prefixToAdd: '', @@ -369,7 +356,7 @@ describe('Integration', () => { }, { name: 'trailing comma, beginning of line', - cursor: { row: 5, column: 1 }, + cursor: { lineNumber: 6, column: 2 }, initialValue: '', addTemplate: true, prefixToAdd: '', @@ -382,7 +369,7 @@ describe('Integration', () => { }, { name: 'prefix comma, beginning of line', - cursor: { row: 6, column: 0 }, + cursor: { lineNumber: 7, column: 1 }, initialValue: '', addTemplate: true, prefixToAdd: ', ', @@ -395,7 +382,7 @@ describe('Integration', () => { }, { name: 'prefix comma, end of line', - cursor: { row: 5, column: 14 }, + cursor: { lineNumber: 6, column: 15 }, initialValue: '', addTemplate: true, prefixToAdd: ', ', @@ -437,31 +424,31 @@ describe('Integration', () => { [ { name: 'not matching object when { is not opened', - cursor: { row: 1, column: 12 }, + cursor: { lineNumber: 2, column: 13 }, initialValue: '', autoCompleteSet: ['{'], }, { name: 'not matching array when [ is not opened', - cursor: { row: 2, column: 12 }, + cursor: { lineNumber: 3, column: 13 }, initialValue: '', autoCompleteSet: ['['], }, { name: 'matching value with one_of', - cursor: { row: 3, column: 19 }, + cursor: { lineNumber: 4, column: 20 }, initialValue: '', autoCompleteSet: [1, 2], }, { name: 'matching value', - cursor: { row: 4, column: 12 }, + cursor: { lineNumber: 5, column: 13 }, initialValue: '', autoCompleteSet: [3], }, { name: 'matching any value with one_of', - cursor: { row: 5, column: 21 }, + cursor: { lineNumber: 6, column: 22 }, initialValue: '', autoCompleteSet: [4, 5], }, @@ -484,7 +471,7 @@ describe('Integration', () => { [ { name: '* matching everything', - cursor: { row: 5, column: 15 }, + cursor: { lineNumber: 6, column: 16 }, initialValue: '', addTemplate: true, prefixToAdd: '', @@ -517,7 +504,7 @@ describe('Integration', () => { [ { name: '{index} matching', - cursor: { row: 1, column: 15 }, + cursor: { lineNumber: 2, column: 16 }, autoCompleteSet: [ { name: 'index1', meta: 'index' }, { name: 'index2', meta: 'index' }, @@ -558,7 +545,7 @@ describe('Integration', () => { [ { name: 'Templates 1', - cursor: { row: 1, column: 0 }, + cursor: { lineNumber: 2, column: 1 }, autoCompleteSet: [ tt('array', []), tt('fixed', { a: 1 }), @@ -569,7 +556,7 @@ describe('Integration', () => { }, { name: 'Templates - one off', - cursor: { row: 4, column: 12 }, + cursor: { lineNumber: 5, column: 13 }, autoCompleteSet: [tt('o1'), tt('o2')], }, ] @@ -612,7 +599,7 @@ describe('Integration', () => { [ { name: 'Conditionals', - cursor: { row: 2, column: 15 }, + cursor: { lineNumber: 3, column: 16 }, autoCompleteSet: [tt('always', {}), tt('match', {})], }, ] @@ -655,7 +642,7 @@ describe('Integration', () => { [ { name: 'Any of - templates', - cursor: { row: 1, column: 0 }, + cursor: { lineNumber: 2, column: 1 }, autoCompleteSet: [ tt('any_of_mixed', []), tt('any_of_numbers', [1, 2]), @@ -664,22 +651,22 @@ describe('Integration', () => { }, { name: 'Any of - numbers', - cursor: { row: 2, column: 2 }, + cursor: { lineNumber: 3, column: 3 }, autoCompleteSet: [1, 2, 3], }, { name: 'Any of - object', - cursor: { row: 6, column: 2 }, + cursor: { lineNumber: 7, column: 3 }, autoCompleteSet: [tt('a', 1), tt('b', 2), tt('c', 1)], }, { name: 'Any of - mixed - obj', - cursor: { row: 11, column: 2 }, + cursor: { lineNumber: 12, column: 3 }, autoCompleteSet: [tt('a', 1)], }, { name: 'Any of - mixed - both', - cursor: { row: 13, column: 2 }, + cursor: { lineNumber: 14, column: 3 }, autoCompleteSet: [tt('{'), tt(3)], }, ] @@ -702,7 +689,7 @@ describe('Integration', () => { [ { name: 'Empty string as default', - cursor: { row: 0, column: 1 }, + cursor: { lineNumber: 1, column: 2 }, autoCompleteSet: [tt('query', '')], }, ] @@ -785,7 +772,7 @@ describe('Integration', () => { [ { name: 'Relative scope link test', - cursor: { row: 2, column: 12 }, + cursor: { lineNumber: 3, column: 13 }, autoCompleteSet: [ tt('b', {}), tt('c', {}), @@ -798,37 +785,37 @@ describe('Integration', () => { }, { name: 'External scope link test', - cursor: { row: 3, column: 12 }, + cursor: { lineNumber: 4, column: 13 }, autoCompleteSet: [tt('t2', 1)], }, { name: 'Global scope link test', - cursor: { row: 4, column: 12 }, + cursor: { lineNumber: 5, column: 13 }, autoCompleteSet: [tt('t1', 2), tt('t1a', {})], }, { name: 'Global scope link with an internal scope link', - cursor: { row: 5, column: 17 }, + cursor: { lineNumber: 6, column: 18 }, autoCompleteSet: [tt('t1', 2), tt('t1a', {})], }, { name: 'Entire endpoint scope link test', - cursor: { row: 7, column: 12 }, + cursor: { lineNumber: 8, column: 13 }, autoCompleteSet: [tt('target', {})], }, { name: 'A scope link within an array', - cursor: { row: 9, column: 10 }, + cursor: { lineNumber: 10, column: 11 }, autoCompleteSet: [tt('t2', 1)], }, { name: 'A function based scope link', - cursor: { row: 11, column: 12 }, + cursor: { lineNumber: 12, column: 13 }, autoCompleteSet: [tt('a', 1), tt('b', 2)], }, { name: 'A global scope link with wrong link', - cursor: { row: 12, column: 12 }, + cursor: { lineNumber: 13, column: 13 }, assertThrows: /broken/, }, ] @@ -857,7 +844,7 @@ describe('Integration', () => { [ { name: 'Top level scope link', - cursor: { row: 0, column: 1 }, + cursor: { lineNumber: 1, column: 2 }, autoCompleteSet: [tt('t1', 2)], }, ] @@ -883,7 +870,7 @@ describe('Integration', () => { [ { name: 'Path after empty object', - cursor: { row: 1, column: 10 }, + cursor: { lineNumber: 2, column: 11 }, autoCompleteSet: ['a', 'b'], }, ] @@ -899,7 +886,7 @@ describe('Integration', () => { [ { name: 'Replace an empty string', - cursor: { row: 1, column: 4 }, + cursor: { lineNumber: 2, column: 5 }, rangeToReplace: { start: { lineNumber: 2, column: 4 }, end: { lineNumber: 2, column: 10 }, @@ -931,12 +918,12 @@ describe('Integration', () => { [ { name: 'List of objects - internal autocomplete', - cursor: { row: 3, column: 10 }, + cursor: { lineNumber: 4, column: 11 }, autoCompleteSet: ['b'], }, { name: 'List of objects - external template', - cursor: { row: 0, column: 1 }, + cursor: { lineNumber: 1, column: 2 }, autoCompleteSet: [tt('a', [{}])], }, ] @@ -964,7 +951,7 @@ describe('Integration', () => { [ { name: 'Field completion as scope', - cursor: { row: 3, column: 10 }, + cursor: { lineNumber: 4, column: 11 }, autoCompleteSet: [ tt('field1.1.1', { f: 1 }, 'string'), tt('field1.1.2', { f: 1 }, 'string'), @@ -972,7 +959,7 @@ describe('Integration', () => { }, { name: 'Field completion as value', - cursor: { row: 9, column: 23 }, + cursor: { lineNumber: 10, column: 24 }, autoCompleteSet: [ { name: 'field1.1.1', meta: 'string' }, { name: 'field1.1.2', meta: 'string' }, @@ -985,7 +972,7 @@ describe('Integration', () => { contextTests('POST _search\n', MAPPING, SEARCH_KB, null, [ { name: 'initial doc start', - cursor: { row: 1, column: 0 }, + cursor: { lineNumber: 2, column: 1 }, autoCompleteSet: ['{'], prefixToAdd: '', suffixToAdd: '', @@ -1000,14 +987,14 @@ describe('Integration', () => { [ { name: 'Cursor rows after request end', - cursor: { row: 4, column: 0 }, + cursor: { lineNumber: 5, column: 1 }, autoCompleteSet: ['GET', 'PUT', 'POST', 'DELETE', 'HEAD'], prefixToAdd: '', suffixToAdd: ' ', }, { name: 'Cursor just after request end', - cursor: { row: 2, column: 1 }, + cursor: { lineNumber: 3, column: 2 }, no_context: true, }, ] @@ -1041,7 +1028,7 @@ describe('Integration', () => { contextTests(null, MAPPING, CLUSTER_KB, 'GET _cluster', [ { name: 'Endpoints with slashes - no slash', - cursor: { row: 0, column: 8 }, + cursor: { lineNumber: 1, column: 9 }, autoCompleteSet: [ '_cluster/nodes/stats', '_cluster/stats', @@ -1057,7 +1044,7 @@ describe('Integration', () => { contextTests(null, MAPPING, CLUSTER_KB, 'GET _cluster/', [ { name: 'Endpoints with slashes - before slash', - cursor: { row: 0, column: 7 }, + cursor: { lineNumber: 1, column: 8 }, autoCompleteSet: [ '_cluster/nodes/stats', '_cluster/stats', @@ -1070,7 +1057,7 @@ describe('Integration', () => { }, { name: 'Endpoints with slashes - on slash', - cursor: { row: 0, column: 12 }, + cursor: { lineNumber: 1, column: 13 }, autoCompleteSet: [ '_cluster/nodes/stats', '_cluster/stats', @@ -1083,7 +1070,7 @@ describe('Integration', () => { }, { name: 'Endpoints with slashes - after slash', - cursor: { row: 0, column: 13 }, + cursor: { lineNumber: 1, column: 14 }, autoCompleteSet: ['nodes/stats', 'stats'], prefixToAdd: '', suffixToAdd: '', @@ -1093,7 +1080,7 @@ describe('Integration', () => { contextTests(null, MAPPING, CLUSTER_KB, 'GET _cluster/no', [ { name: 'Endpoints with slashes - after slash', - cursor: { row: 0, column: 14 }, + cursor: { lineNumber: 1, column: 15 }, autoCompleteSet: [ { name: 'nodes/stats', meta: 'endpoint' }, { name: 'stats', meta: 'endpoint' }, @@ -1107,7 +1094,7 @@ describe('Integration', () => { contextTests(null, MAPPING, CLUSTER_KB, 'GET _cluster/nodes/st', [ { name: 'Endpoints with two slashes', - cursor: { row: 0, column: 20 }, + cursor: { lineNumber: 1, column: 21 }, autoCompleteSet: ['stats'], prefixToAdd: '', suffixToAdd: '', @@ -1118,7 +1105,7 @@ describe('Integration', () => { contextTests(null, MAPPING, CLUSTER_KB, 'GET ', [ { name: 'Immediately after space + method', - cursor: { row: 0, column: 4 }, + cursor: { lineNumber: 1, column: 5 }, autoCompleteSet: [ { name: '_cluster/nodes/stats', meta: 'endpoint' }, { name: '_cluster/stats', meta: 'endpoint' }, @@ -1135,7 +1122,7 @@ describe('Integration', () => { contextTests(null, MAPPING, CLUSTER_KB, 'GET cl', [ { name: 'Endpoints by subpart GET', - cursor: { row: 0, column: 6 }, + cursor: { lineNumber: 1, column: 7 }, autoCompleteSet: [ { name: '_cluster/nodes/stats', meta: 'endpoint' }, { name: '_cluster/stats', meta: 'endpoint' }, @@ -1153,7 +1140,7 @@ describe('Integration', () => { contextTests(null, MAPPING, CLUSTER_KB, 'POST cl', [ { name: 'Endpoints by subpart POST', - cursor: { row: 0, column: 7 }, + cursor: { lineNumber: 1, column: 8 }, no_context: true, prefixToAdd: '', suffixToAdd: '', @@ -1164,7 +1151,7 @@ describe('Integration', () => { contextTests(null, MAPPING, CLUSTER_KB, 'GET _search?', [ { name: 'Params just after ?', - cursor: { row: 0, column: 12 }, + cursor: { lineNumber: 1, column: 13 }, autoCompleteSet: [ { name: 'filter_path', meta: 'param', insertValue: 'filter_path=' }, { name: 'format', meta: 'param', insertValue: 'format=' }, @@ -1180,7 +1167,7 @@ describe('Integration', () => { contextTests(null, MAPPING, CLUSTER_KB, 'GET _search?format=', [ { name: 'Params values', - cursor: { row: 0, column: 19 }, + cursor: { lineNumber: 1, column: 20 }, autoCompleteSet: [ { name: 'json', meta: 'format' }, { name: 'yaml', meta: 'format' }, @@ -1193,7 +1180,7 @@ describe('Integration', () => { contextTests(null, MAPPING, CLUSTER_KB, 'GET _search?format=yaml&', [ { name: 'Params after amp', - cursor: { row: 0, column: 24 }, + cursor: { lineNumber: 1, column: 25 }, autoCompleteSet: [ { name: 'filter_path', meta: 'param', insertValue: 'filter_path=' }, { name: 'format', meta: 'param', insertValue: 'format=' }, @@ -1209,7 +1196,7 @@ describe('Integration', () => { contextTests(null, MAPPING, CLUSTER_KB, 'GET _search?format=yaml&search', [ { name: 'Params on existing param', - cursor: { row: 0, column: 26 }, + cursor: { lineNumber: 1, column: 27 }, rangeToReplace: { start: { lineNumber: 1, column: 25 }, end: { lineNumber: 1, column: 31 }, @@ -1234,7 +1221,7 @@ describe('Integration', () => { [ { name: 'Params on existing value', - cursor: { row: 0, column: 37 }, + cursor: { lineNumber: 1, column: 38 }, rangeToReplace: { start: { lineNumber: 1, column: 37 }, end: { lineNumber: 1, column: 40 }, @@ -1257,7 +1244,7 @@ describe('Integration', () => { [ { name: 'Params on just after = with existing value', - cursor: { row: 0, column: 36 }, + cursor: { lineNumber: 1, column: 37 }, rangeToReplace: { start: { lineNumber: 1, column: 37 }, end: { lineNumber: 1, column: 37 }, @@ -1286,7 +1273,7 @@ describe('Integration', () => { [ { name: 'fullurl - existing dictionary key, no template', - cursor: { row: 1, column: 6 }, + cursor: { lineNumber: 2, column: 7 }, initialValue: 'query', addTemplate: false, prefixToAdd: '', @@ -1299,7 +1286,7 @@ describe('Integration', () => { }, { name: 'fullurl - existing inner dictionary key', - cursor: { row: 2, column: 7 }, + cursor: { lineNumber: 3, column: 8 }, initialValue: 'field', addTemplate: false, prefixToAdd: '', @@ -1312,7 +1299,7 @@ describe('Integration', () => { }, { name: 'fullurl - existing dictionary key, yes template', - cursor: { row: 4, column: 7 }, + cursor: { lineNumber: 5, column: 8 }, initialValue: 'facets', addTemplate: true, prefixToAdd: '', diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/editor.test.js b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/sense_editor.test.js similarity index 77% rename from src/legacy/core_plugins/console/public/quarantined/tests/src/editor.test.js rename to src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/sense_editor.test.js index f828106e2bd41..ae66b1aa8e755 100644 --- a/src/legacy/core_plugins/console/public/quarantined/tests/src/editor.test.js +++ b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/__tests__/sense_editor.test.js @@ -16,17 +16,14 @@ * specific language governing permissions and limitations * under the License. */ -import './setup_mocks'; +import '../sense_editor.test.mocks'; + import $ from 'jquery'; import _ from 'lodash'; -import ace from 'brace'; -import 'brace/mode/json'; -import { initializeEditor } from '../../src/input'; +import { create } from '../create'; const editorInput1 = require('./editor_input1.txt'); -const utils = require('../../src/utils'); - -const aceRange = ace.acequire('ace/range'); +const utils = require('../../../../lib/utils/utils'); describe('Editor', () => { let input; @@ -40,26 +37,22 @@ describe('Editor', () => {
    `; - input = initializeEditor( - $('#ConAppEditor'), - $('#ConAppEditorActions'), + input = create( + document.querySelector('#ConAppEditor') ); - input.$el.show(); + $(input.getCoreEditor().getContainer()).show(); input.autocomplete._test.removeChangeListener(); }); afterEach(function () { - input.$el.hide(); + $(input.getCoreEditor().getContainer()).hide(); input.autocomplete._test.addChangeListener(); }); let testCount = 0; - const callWithEditorMethod = (editorMethod, fn) => (done) => { - try { - input[editorMethod](results => fn(results, done)); - } catch { - done(); - } + const callWithEditorMethod = (editorMethod, fn) => async (done) => { + const results = await input[editorMethod](); + fn(results, done); }; function utilsTest(name, prefix, data, testToRun) { @@ -79,10 +72,9 @@ describe('Editor', () => { data = prefix; } - test('Utils test ' + id + ' : ' + name, function (done) { - input.update(data, function () { - testToRun(done); - }); + test('Utils test ' + id + ' : ' + name, async function (done) { + await input.update(data, true); + testToRun(done); }); } @@ -126,8 +118,7 @@ describe('Editor', () => { simpleRequest.prefix, simpleRequest.data, callWithEditorMethod('getRequestRange', (range, done) => { - const expected = new aceRange.Range(0, 0, 3, 1); - compareRequest(range, expected); + compareRequest(range, { start: { lineNumber: 1, column: 1 }, end: { lineNumber: 4, column: 2 } }); done(); }) ); @@ -152,8 +143,10 @@ describe('Editor', () => { ' ' + simpleRequest.prefix, simpleRequest.data, callWithEditorMethod('getRequestRange', (range, done) => { - const expected = new aceRange.Range(0, 0, 3, 1); - expect(range).toEqual(expected); + expect(range).toEqual({ + start: { lineNumber: 1, column: 1 }, + end: { lineNumber: 4, column: 2 } + }); done(); }) ); @@ -180,8 +173,10 @@ describe('Editor', () => { simpleRequest.prefix + ' ', simpleRequest.data + ' ', callWithEditorMethod('getRequestRange', (range, done) => { - const expected = new aceRange.Range(0, 0, 3, 1); - compareRequest(range, expected); + compareRequest(range, { + start: { lineNumber: 1, column: 1 }, + end: { lineNumber: 4, column: 2 } + }); done(); }) ); @@ -208,8 +203,10 @@ describe('Editor', () => { singleLineRequest.prefix, singleLineRequest.data, callWithEditorMethod('getRequestRange', (range, done) => { - const expected = new aceRange.Range(0, 0, 1, 32); - compareRequest(range, expected); + compareRequest(range, { + start: { lineNumber: 1, column: 1 }, + end: { lineNumber: 2, column: 33 } + }); done(); }) ); @@ -234,8 +231,10 @@ describe('Editor', () => { getRequestNoData.prefix, '\n', callWithEditorMethod('getRequestRange', (range, done) => { - const expected = new aceRange.Range(0, 0, 0, 10); - compareRequest(range, expected); + compareRequest(range, { + start: { lineNumber: 1, column: 1 }, + end: { lineNumber: 1, column: 11 }, + }); done(); }) ); @@ -260,8 +259,10 @@ describe('Editor', () => { getRequestNoData.prefix, getRequestNoData.data, callWithEditorMethod('getRequestRange', (range, done) => { - const expected = new aceRange.Range(0, 0, 0, 10); - expect(range).toEqual(expected); + expect(range).toEqual({ + start: { lineNumber: 1, column: 1 }, + end: { lineNumber: 1, column: 11 }, + }); done(); }) ); @@ -286,8 +287,10 @@ describe('Editor', () => { multiDocRequest.prefix, multiDocRequest.data, callWithEditorMethod('getRequestRange', (range, done) => { - const expected = new aceRange.Range(0, 0, 2, 14); - expect(range).toEqual(expected); + expect(range).toEqual({ + start: { lineNumber: 1, column: 1 }, + end: { lineNumber: 3, column: 15 }, + }); done(); }) ); @@ -323,8 +326,10 @@ describe('Editor', () => { scriptRequest.prefix, scriptRequest.data, callWithEditorMethod('getRequestRange', (range, done) => { - const expected = new aceRange.Range(0, 0, 5, 1); - compareRequest(range, expected); + compareRequest(range, { + start: { lineNumber: 1, column: 1 }, + end: { lineNumber: 6, column: 2 }, + }); done(); }) ); @@ -347,24 +352,23 @@ describe('Editor', () => { ); function multiReqTest(name, editorInput, range, expected) { - utilsTest('multi request select - ' + name, editorInput, function (done) { - input.getRequestsInRange(range, function (requests) { - // convert to format returned by request. - _.each(expected, function (req) { - req.data = - req.data == null ? [] : [JSON.stringify(req.data, null, 2)]; - }); - - compareRequest(requests, expected); - done(); + utilsTest('multi request select - ' + name, editorInput, async function (done) { + const requests = await input.getRequestsInRange(range, false); + // convert to format returned by request. + _.each(expected, function (req) { + req.data = + req.data == null ? [] : [JSON.stringify(req.data, null, 2)]; }); + + compareRequest(requests, expected); + done(); }); } multiReqTest( 'mid body to mid body', editorInput1, - { start: { row: 12 }, end: { row: 17 } }, + { start: { lineNumber: 13 }, end: { lineNumber: 18 } }, [ { method: 'PUT', @@ -386,7 +390,7 @@ describe('Editor', () => { multiReqTest( 'single request start to end', editorInput1, - { start: { row: 10 }, end: { row: 13 } }, + { start: { lineNumber: 11 }, end: { lineNumber: 14 } }, [ { method: 'PUT', @@ -401,7 +405,7 @@ describe('Editor', () => { multiReqTest( 'start to end, with comment', editorInput1, - { start: { row: 6 }, end: { row: 13 } }, + { start: { lineNumber: 7 }, end: { lineNumber: 14 } }, [ { method: 'GET', @@ -421,7 +425,7 @@ describe('Editor', () => { multiReqTest( 'before start to after end, with comments', editorInput1, - { start: { row: 4 }, end: { row: 14 } }, + { start: { lineNumber: 5 }, end: { lineNumber: 15 } }, [ { method: 'GET', @@ -441,37 +445,36 @@ describe('Editor', () => { multiReqTest( 'between requests', editorInput1, - { start: { row: 21 }, end: { row: 22 } }, + { start: { lineNumber: 22 }, end: { lineNumber: 23 } }, [] ); multiReqTest( 'between requests - with comment', editorInput1, - { start: { row: 20 }, end: { row: 22 } }, + { start: { lineNumber: 21 }, end: { lineNumber: 23 } }, [] ); multiReqTest( 'between requests - before comment', editorInput1, - { start: { row: 19 }, end: { row: 22 } }, + { start: { lineNumber: 20 }, end: { lineNumber: 23 } }, [] ); function multiReqCopyAsCurlTest(name, editorInput, range, expected) { - utilsTest('multi request copy as curl - ' + name, editorInput, function (done) { - input.getRequestsAsCURL(range, function (curl) { - expect(curl).toEqual(expected); - done(); - }); + utilsTest('multi request copy as curl - ' + name, editorInput, async function (done) { + const curl = await input.getRequestsAsCURL('http://localhost:9200', range); + expect(curl).toEqual(expected); + done(); }); } multiReqCopyAsCurlTest( 'start to end, with comment', editorInput1, - { start: { row: 6 }, end: { row: 13 } }, + { start: { lineNumber: 7 }, end: { lineNumber: 14 } }, ` curl -XGET "http://localhost:9200/_stats?level=shards" diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/create.ts b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/create.ts new file mode 100644 index 0000000000000..33508a2f63299 --- /dev/null +++ b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/create.ts @@ -0,0 +1,32 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { SenseEditor } from './sense_editor'; +import * as core from '../legacy_core_editor'; + +export function create(element: HTMLElement) { + const coreEditor = core.create(element); + const senseEditor = new SenseEditor(coreEditor); + + /** + * Init the editor + */ + senseEditor.highlightCurrentRequestsAndUpdateActionBar(); + return senseEditor; +} diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/curl.ts b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/curl.ts new file mode 100644 index 0000000000000..d56a9cca0ef32 --- /dev/null +++ b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/curl.ts @@ -0,0 +1,204 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +function detectCURLinLine(line: string) { + // returns true if text matches a curl request + return line.match(/^\s*?curl\s+(-X[A-Z]+)?\s*['"]?.*?['"]?(\s*$|\s+?-d\s*?['"])/); +} + +export function detectCURL(text: string) { + // returns true if text matches a curl request + if (!text) return false; + for (const line of text.split('\n')) { + if (detectCURLinLine(line)) { + return true; + } + } + return false; +} + +export function parseCURL(text: string) { + let state = 'NONE'; + const out = []; + let body: any[] = []; + let line = ''; + const lines = text.trim().split('\n'); + let matches; + + const EmptyLine = /^\s*$/; + const Comment = /^\s*(?:#|\/{2,})(.*)\n?$/; + const ExecutionComment = /^\s*#!/; + const ClosingSingleQuote = /^([^']*)'/; + const ClosingDoubleQuote = /^((?:[^\\"]|\\.)*)"/; + const EscapedQuotes = /^((?:[^\\"']|\\.)+)/; + + const LooksLikeCurl = /^\s*curl\s+/; + const CurlVerb = /-X ?(GET|HEAD|POST|PUT|DELETE)/; + + const HasProtocol = /[\s"']https?:\/\//; + const CurlRequestWithProto = /[\s"']https?:\/\/[^\/ ]+\/+([^\s"']+)/; + const CurlRequestWithoutProto = /[\s"'][^\/ ]+\/+([^\s"']+)/; + const CurlData = /^.+\s(--data|-d)\s*/; + const SenseLine = /^\s*(GET|HEAD|POST|PUT|DELETE)\s+\/?(.+)/; + + if (lines.length > 0 && ExecutionComment.test(lines[0])) { + lines.shift(); + } + + function nextLine() { + if (line.length > 0) { + return true; + } + if (lines.length === 0) { + return false; + } + line = lines.shift()!.replace(/[\r\n]+/g, '\n') + '\n'; + return true; + } + + function unescapeLastBodyEl() { + const str = body.pop().replace(/\\([\\"'])/g, '$1'); + body.push(str); + } + + // Is the next char a single or double quote? + // If so remove it + function detectQuote() { + if (line.substr(0, 1) === "'") { + line = line.substr(1); + state = 'SINGLE_QUOTE'; + } else if (line.substr(0, 1) === '"') { + line = line.substr(1); + state = 'DOUBLE_QUOTE'; + } else { + state = 'UNQUOTED'; + } + } + + // Body is finished - append to output with final LF + function addBodyToOut() { + if (body.length > 0) { + out.push(body.join('')); + body = []; + } + state = 'LF'; + out.push('\n'); + } + + // If the pattern matches, then the state is about to change, + // so add the capture to the body and detect the next state + // Otherwise add the whole line + function consumeMatching(pattern: string | RegExp) { + const result = line.match(pattern); + if (result) { + body.push(result[1]); + line = line.substr(result[0].length); + detectQuote(); + } else { + body.push(line); + line = ''; + } + } + + function parseCurlLine() { + let verb = 'GET'; + let request = ''; + let result; + if ((result = line.match(CurlVerb))) { + verb = result[1]; + } + + // JS regexen don't support possessive quantifiers, so + // we need two distinct patterns + const pattern = HasProtocol.test(line) ? CurlRequestWithProto : CurlRequestWithoutProto; + + if ((result = line.match(pattern))) { + request = result[1]; + } + + out.push(verb + ' /' + request + '\n'); + + if ((result = line.match(CurlData))) { + line = line.substr(result[0].length); + detectQuote(); + if (EmptyLine.test(line)) { + line = ''; + } + } else { + state = 'NONE'; + line = ''; + out.push(''); + } + } + + while (nextLine()) { + if (state === 'SINGLE_QUOTE') { + consumeMatching(ClosingSingleQuote); + } else if (state === 'DOUBLE_QUOTE') { + consumeMatching(ClosingDoubleQuote); + unescapeLastBodyEl(); + } else if (state === 'UNQUOTED') { + consumeMatching(EscapedQuotes); + if (body.length) { + unescapeLastBodyEl(); + } + if (state === 'UNQUOTED') { + addBodyToOut(); + line = ''; + } + } + + // the BODY state (used to match the body of a Sense request) + // can be terminated early if it encounters + // a comment or an empty line + else if (state === 'BODY') { + if (Comment.test(line) || EmptyLine.test(line)) { + addBodyToOut(); + } else { + body.push(line); + line = ''; + } + } else if (EmptyLine.test(line)) { + if (state !== 'LF') { + out.push('\n'); + state = 'LF'; + } + line = ''; + } else if ((matches = line.match(Comment))) { + out.push('#' + matches[1] + '\n'); + state = 'NONE'; + line = ''; + } else if (LooksLikeCurl.test(line)) { + parseCurlLine(); + } else if ((matches = line.match(SenseLine))) { + out.push(matches[1] + ' /' + matches[2] + '\n'); + line = ''; + state = 'BODY'; + } + + // Nothing else matches, so output with a prefix of ### for debugging purposes + else { + out.push('### ' + line); + line = ''; + } + } + + addBodyToOut(); + return out.join('').trim(); +} diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/index.ts b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/index.ts new file mode 100644 index 0000000000000..9310de2724fbe --- /dev/null +++ b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/index.ts @@ -0,0 +1,23 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export * from './create'; +export * from '../legacy_core_editor/create_readonly'; +export { MODE } from '../../../lib/row_parser'; +export { SenseEditor } from './sense_editor'; diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/sense_editor.test.mocks.ts b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/sense_editor.test.mocks.ts new file mode 100644 index 0000000000000..8df9bb8ef9a0b --- /dev/null +++ b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/sense_editor.test.mocks.ts @@ -0,0 +1,32 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +/* eslint no-undef: 0 */ + +import '../legacy_core_editor/legacy_core_editor.test.mocks'; + +// TODO: Remove this mock +jest.mock('../../../application', () => ({ legacyBackDoorToSettings: () => {} })); + +import jQuery from 'jquery'; +jest.spyOn(jQuery, 'ajax').mockImplementation( + () => + new Promise(() => { + // never resolve + }) as any +); diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/sense_editor.ts b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/sense_editor.ts new file mode 100644 index 0000000000000..9679eaa2884ce --- /dev/null +++ b/src/legacy/core_plugins/console/public/np_ready/application/models/sense_editor/sense_editor.ts @@ -0,0 +1,502 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import _ from 'lodash'; +import RowParser from '../../../lib/row_parser'; +import * as utils from '../../../lib/utils/utils'; +// @ts-ignore +import * as es from '../../../lib/es/es'; + +import { CoreEditor, Position, Range } from '../../../types'; +import { createTokenIterator } from '../../factories'; + +import Autocomplete from '../../../lib/autocomplete/autocomplete'; + +export class SenseEditor { + currentReqRange: (Range & { markerRef: any }) | null; + parser: any; + + // @ts-ignore + private readonly autocomplete: any; + + constructor(private readonly coreEditor: CoreEditor) { + this.currentReqRange = null; + this.parser = new RowParser(this.coreEditor); + this.autocomplete = new (Autocomplete as any)({ + coreEditor, + parser: this.parser, + }); + this.coreEditor.on( + 'tokenizerUpdate', + this.highlightCurrentRequestsAndUpdateActionBar.bind(this) + ); + this.coreEditor.on('changeCursor', this.highlightCurrentRequestsAndUpdateActionBar.bind(this)); + this.coreEditor.on('changeScrollTop', this.updateActionsBar.bind(this)); + } + + prevRequestStart = (rowOrPos?: number | Position): Position => { + let curRow: number; + + if (rowOrPos == null) { + curRow = this.coreEditor.getCurrentPosition().lineNumber; + } else if (_.isObject(rowOrPos)) { + curRow = (rowOrPos as Position).lineNumber; + } else { + curRow = rowOrPos as number; + } + + while (curRow > 0 && !this.parser.isStartRequestRow(curRow, this.coreEditor)) curRow--; + + return { + lineNumber: curRow, + column: 1, + }; + }; + + nextRequestStart = (rowOrPos?: number | Position) => { + let curRow: number; + if (rowOrPos == null) { + curRow = this.coreEditor.getCurrentPosition().lineNumber; + } else if (_.isObject(rowOrPos)) { + curRow = (rowOrPos as Position).lineNumber; + } else { + curRow = rowOrPos as number; + } + const maxLines = this.coreEditor.getValue().split('\n').length; + for (; curRow < maxLines - 1; curRow++) { + if (this.parser.isStartRequestRow(curRow, this.coreEditor)) { + break; + } + } + return { + row: curRow, + column: 0, + }; + }; + + autoIndent = _.debounce(async () => { + await this.coreEditor.waitForLatestTokens(); + const reqRange = await this.getRequestRange(); + if (!reqRange) { + return; + } + const parsedReq = await this.getRequest(); + + if (!parsedReq) { + return; + } + + if (parsedReq.data && parsedReq.data.length > 0) { + let indent = parsedReq.data.length === 1; // unindent multi docs by default + let formattedData = utils.formatRequestBodyDoc(parsedReq.data, indent); + if (!formattedData.changed) { + // toggle. + indent = !indent; + formattedData = utils.formatRequestBodyDoc(parsedReq.data, indent); + } + parsedReq.data = formattedData.data; + + this.replaceRequestRange(parsedReq, reqRange); + } + }, 25); + + update = async (data: string, reTokenizeAll = false) => { + return this.coreEditor.setValue(data, reTokenizeAll); + }; + + replaceRequestRange = (newRequest: any, requestRange: Range) => { + const text = utils.textFromRequest(newRequest); + if (requestRange) { + this.coreEditor.replaceRange(requestRange, text); + } else { + // just insert where we are + this.coreEditor.insert(this.coreEditor.getCurrentPosition(), text); + } + }; + + getRequestRange = async (lineNumber?: number): Promise => { + await this.coreEditor.waitForLatestTokens(); + + if (this.parser.isInBetweenRequestsRow(lineNumber)) { + return null; + } + + const reqStart = this.prevRequestStart(lineNumber); + const reqEnd = this.nextRequestEnd(reqStart); + + return { + start: { + ...reqStart, + }, + end: { + ...reqEnd, + }, + }; + }; + + expandRangeToRequestEdges = async ( + range = this.coreEditor.getSelectionRange() + ): Promise => { + await this.coreEditor.waitForLatestTokens(); + + let startLineNumber = range.start.lineNumber; + let endLineNumber = range.end.lineNumber; + const maxLine = Math.max(1, this.coreEditor.getLineCount()); + + if (this.parser.isInBetweenRequestsRow(startLineNumber)) { + /* Do nothing... */ + } else { + for (; startLineNumber >= 1; startLineNumber--) { + if (this.parser.isStartRequestRow(startLineNumber)) { + break; + } + } + } + + if (startLineNumber < 1 || startLineNumber > endLineNumber) { + return null; + } + // move end row to the previous request end if between requests, otherwise walk forward + if (this.parser.isInBetweenRequestsRow(endLineNumber)) { + for (; endLineNumber >= startLineNumber; endLineNumber--) { + if (this.parser.isEndRequestRow(endLineNumber)) { + break; + } + } + } else { + for (; endLineNumber <= maxLine; endLineNumber++) { + if (this.parser.isEndRequestRow(endLineNumber)) { + break; + } + } + } + + if (endLineNumber < startLineNumber || endLineNumber > maxLine) { + return null; + } + + const endColumn = + (this.coreEditor.getLineValue(endLineNumber) || '').replace(/\s+$/, '').length + 1; + return { + start: { + lineNumber: startLineNumber, + column: 1, + }, + end: { + lineNumber: endLineNumber, + column: endColumn, + }, + }; + }; + + getRequestInRange = async (range?: Range) => { + await this.coreEditor.waitForLatestTokens(); + if (!range) { + return null; + } + const request: { + method: string; + data: string[]; + url: string | null; + range: Range; + } = { + method: '', + data: [], + url: null, + range, + }; + + const pos = range.start; + const tokenIter = createTokenIterator({ editor: this.coreEditor, position: pos }); + let t = tokenIter.getCurrentToken(); + if (this.parser.isEmptyToken(t)) { + // if the row starts with some spaces, skip them. + t = this.parser.nextNonEmptyToken(tokenIter); + } + if (t == null) { + return null; + } + + request.method = t.value; + t = this.parser.nextNonEmptyToken(tokenIter); + + if (!t || t.type === 'method') { + return null; + } + + request.url = ''; + + while (t && t.type && t.type.indexOf('url') === 0) { + request.url += t.value; + t = tokenIter.stepForward(); + } + if (this.parser.isEmptyToken(t)) { + // if the url row ends with some spaces, skip them. + t = this.parser.nextNonEmptyToken(tokenIter); + } + let bodyStartLineNumber = (t ? 0 : 1) + tokenIter.getCurrentPosition().lineNumber; // artificially increase end of docs. + let dataEndPos: Position; + while ( + bodyStartLineNumber < range.end.lineNumber || + (bodyStartLineNumber === range.end.lineNumber && 1 < range.end.column) + ) { + dataEndPos = this.nextDataDocEnd({ + lineNumber: bodyStartLineNumber, + column: 1, + }); + const bodyRange: Range = { + start: { + lineNumber: bodyStartLineNumber, + column: 1, + }, + end: dataEndPos, + }; + const data = this.coreEditor.getValueInRange(bodyRange)!; + request.data.push(data.trim()); + bodyStartLineNumber = dataEndPos.lineNumber + 1; + } + + return request; + }; + + getRequestsInRange = async ( + range = this.coreEditor.getSelectionRange(), + includeNonRequestBlocks = false + ): Promise => { + await this.coreEditor.waitForLatestTokens(); + if (!range) { + return []; + } + + const expandedRange = await this.expandRangeToRequestEdges(range); + + if (!expandedRange) { + return []; + } + + const requests: any = []; + + let rangeStartCursor = expandedRange.start.lineNumber; + const endLineNumber = expandedRange.end.lineNumber; + + // move to the next request start (during the second iterations this may not be exactly on a request + let currentLineNumber = expandedRange.start.lineNumber; + + const flushNonRequestBlock = () => { + if (includeNonRequestBlocks) { + const nonRequestPrefixBlock = this.coreEditor + .getLines(rangeStartCursor, currentLineNumber - 1) + .join('\n'); + if (nonRequestPrefixBlock) { + requests.push(nonRequestPrefixBlock); + } + } + }; + + while (currentLineNumber <= endLineNumber) { + if (this.parser.isStartRequestRow(currentLineNumber)) { + flushNonRequestBlock(); + const request = await this.getRequest(currentLineNumber); + if (!request) { + // Something has probably gone wrong. + return requests; + } else { + requests.push(request); + rangeStartCursor = currentLineNumber = request.range.end.lineNumber + 1; + } + } else { + ++currentLineNumber; + } + } + + flushNonRequestBlock(); + + return requests; + }; + + getRequest = async (row?: number) => { + await this.coreEditor.waitForLatestTokens(); + if (this.parser.isInBetweenRequestsRow(row)) { + return null; + } + + const range = await this.getRequestRange(row); + return this.getRequestInRange(range!); + }; + + moveToPreviousRequestEdge = async () => { + await this.coreEditor.waitForLatestTokens(); + const pos = this.coreEditor.getCurrentPosition(); + for ( + pos.lineNumber--; + pos.lineNumber > 1 && !this.parser.isRequestEdge(pos.lineNumber); + pos.lineNumber-- + ) { + // loop for side effects + } + this.coreEditor.moveCursorToPosition({ + lineNumber: pos.lineNumber, + column: 1, + }); + }; + + moveToNextRequestEdge = async (moveOnlyIfNotOnEdge: boolean) => { + await this.coreEditor.waitForLatestTokens(); + const pos = this.coreEditor.getCurrentPosition(); + const maxRow = this.coreEditor.getLineCount(); + if (!moveOnlyIfNotOnEdge) { + pos.lineNumber++; + } + for ( + ; + pos.lineNumber < maxRow && !this.parser.isRequestEdge(pos.lineNumber); + pos.lineNumber++ + ) { + // loop for side effects + } + this.coreEditor.moveCursorToPosition({ + lineNumber: pos.lineNumber, + column: 1, + }); + }; + + nextRequestEnd = (pos: Position): Position => { + pos = pos || this.coreEditor.getCurrentPosition(); + const maxLines = this.coreEditor.getLineCount(); + let curLineNumber = pos.lineNumber; + for (; curLineNumber <= maxLines; ++curLineNumber) { + const curRowMode = this.parser.getRowParseMode(curLineNumber); + // eslint-disable-next-line no-bitwise + if ((curRowMode & this.parser.MODE.REQUEST_END) > 0) { + break; + } + // eslint-disable-next-line no-bitwise + if (curLineNumber !== pos.lineNumber && (curRowMode & this.parser.MODE.REQUEST_START) > 0) { + break; + } + } + + const column = + (this.coreEditor.getLineValue(curLineNumber) || '').replace(/\s+$/, '').length + 1; + + return { + lineNumber: curLineNumber, + column, + }; + }; + + nextDataDocEnd = (pos: Position): Position => { + pos = pos || this.coreEditor.getCurrentPosition(); + let curLineNumber = pos.lineNumber; + const maxLines = this.coreEditor.getLineCount(); + for (; curLineNumber < maxLines; curLineNumber++) { + const curRowMode = this.parser.getRowParseMode(curLineNumber); + // eslint-disable-next-line no-bitwise + if ((curRowMode & this.parser.MODE.REQUEST_END) > 0) { + break; + } + // eslint-disable-next-line no-bitwise + if ((curRowMode & this.parser.MODE.MULTI_DOC_CUR_DOC_END) > 0) { + break; + } + // eslint-disable-next-line no-bitwise + if (curLineNumber !== pos.lineNumber && (curRowMode & this.parser.MODE.REQUEST_START) > 0) { + break; + } + } + + const column = + (this.coreEditor.getLineValue(curLineNumber) || '').length + + 1 /* Range goes to 1 after last char */; + + return { + lineNumber: curLineNumber, + column, + }; + }; + + highlightCurrentRequestsAndUpdateActionBar = _.debounce(async () => { + await this.coreEditor.waitForLatestTokens(); + const expandedRange = await this.expandRangeToRequestEdges(); + if (expandedRange === null && this.currentReqRange === null) { + return; + } + if ( + expandedRange !== null && + this.currentReqRange !== null && + expandedRange.start.lineNumber === this.currentReqRange.start.lineNumber && + expandedRange.end.lineNumber === this.currentReqRange.end.lineNumber + ) { + // same request, now see if we are on the first line and update the action bar + const cursorLineNumber = this.coreEditor.getCurrentPosition().lineNumber; + if (cursorLineNumber === this.currentReqRange.start.lineNumber) { + this.updateActionsBar(); + } + return; // nothing to do.. + } + + if (this.currentReqRange) { + this.coreEditor.removeMarker(this.currentReqRange.markerRef); + } + + this.currentReqRange = expandedRange as any; + if (this.currentReqRange) { + this.currentReqRange.markerRef = this.coreEditor.addMarker(this.currentReqRange); + } + this.updateActionsBar(); + }, 25); + + getRequestsAsCURL = async (elasticsearchBaseUrl: string, range?: Range): Promise => { + const requests = await this.getRequestsInRange(range, true); + const result = _.map(requests, req => { + if (typeof req === 'string') { + // no request block + return req; + } + + const esPath = req.url; + const esMethod = req.method; + const esData = req.data; + + // this is the first url defined in elasticsearch.hosts + const url = es.constructESUrl(elasticsearchBaseUrl, esPath); + + let ret = 'curl -X' + esMethod + ' "' + url + '"'; + if (esData && esData.length) { + ret += " -H 'Content-Type: application/json' -d'\n"; + const dataAsString = utils.collapseLiteralStrings(esData.join('\n')); + // since Sense doesn't allow single quote json string any single qoute is within a string. + ret += dataAsString.replace(/'/g, '\\"'); + if (esData.length > 1) { + ret += '\n'; + } // end with a new line + ret += "'"; + } + return ret; + }); + + return result.join('\n'); + }; + + updateActionsBar = () => this.coreEditor.legacyUpdateUI(this.currentReqRange); + + getCoreEditor() { + return this.coreEditor; + } +} diff --git a/src/legacy/core_plugins/console/np_ready/public/application/stores/editor.ts b/src/legacy/core_plugins/console/public/np_ready/application/stores/editor.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/stores/editor.ts rename to src/legacy/core_plugins/console/public/np_ready/application/stores/editor.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/application/stores/request.ts b/src/legacy/core_plugins/console/public/np_ready/application/stores/request.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/application/stores/request.ts rename to src/legacy/core_plugins/console/public/np_ready/application/stores/request.ts diff --git a/src/legacy/core_plugins/console/public/quarantined/_app.scss b/src/legacy/core_plugins/console/public/np_ready/application/styles/_app.scss similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/_app.scss rename to src/legacy/core_plugins/console/public/np_ready/application/styles/_app.scss diff --git a/src/legacy/core_plugins/console/public/quarantined/src/directives/_help.scss b/src/legacy/core_plugins/console/public/np_ready/application/styles/components/_help.scss similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/directives/_help.scss rename to src/legacy/core_plugins/console/public/np_ready/application/styles/components/_help.scss diff --git a/src/legacy/core_plugins/console/public/quarantined/src/directives/_history.scss b/src/legacy/core_plugins/console/public/np_ready/application/styles/components/_history.scss similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/directives/_history.scss rename to src/legacy/core_plugins/console/public/np_ready/application/styles/components/_history.scss diff --git a/src/legacy/core_plugins/console/public/np_ready/application/styles/components/_index.scss b/src/legacy/core_plugins/console/public/np_ready/application/styles/components/_index.scss new file mode 100644 index 0000000000000..9dfef202d1254 --- /dev/null +++ b/src/legacy/core_plugins/console/public/np_ready/application/styles/components/_index.scss @@ -0,0 +1,2 @@ +@import 'help'; +@import 'history'; diff --git a/src/legacy/core_plugins/console/public/quarantined/index.scss b/src/legacy/core_plugins/console/public/np_ready/application/styles/index.scss similarity index 81% rename from src/legacy/core_plugins/console/public/quarantined/index.scss rename to src/legacy/core_plugins/console/public/np_ready/application/styles/index.scss index ce40b2c6f1102..dc45f6cfdacf5 100644 --- a/src/legacy/core_plugins/console/public/quarantined/index.scss +++ b/src/legacy/core_plugins/console/public/np_ready/application/styles/index.scss @@ -7,5 +7,5 @@ // conChart__legend--small // conChart__legend-isLoading -@import './app'; -@import './src/directives/index'; +@import 'app'; +@import 'components/index'; diff --git a/src/legacy/core_plugins/console/np_ready/public/index.ts b/src/legacy/core_plugins/console/public/np_ready/index.ts similarity index 93% rename from src/legacy/core_plugins/console/np_ready/public/index.ts rename to src/legacy/core_plugins/console/public/np_ready/index.ts index 3f8d162f62d44..045420f401e3b 100644 --- a/src/legacy/core_plugins/console/np_ready/public/index.ts +++ b/src/legacy/core_plugins/console/public/np_ready/index.ts @@ -17,7 +17,7 @@ * under the License. */ -import { PluginInitializerContext } from '../../../../../core/public'; +import { PluginInitializerContext } from 'kibana/public'; import { ConsoleUIPlugin } from './plugin'; diff --git a/src/legacy/core_plugins/console/np_ready/public/lib/ace_token_provider/index.ts b/src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/index.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/lib/ace_token_provider/index.ts rename to src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/index.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/lib/ace_token_provider/token_provider.test.ts b/src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/token_provider.test.ts similarity index 84% rename from src/legacy/core_plugins/console/np_ready/public/lib/ace_token_provider/token_provider.test.ts rename to src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/token_provider.test.ts index aecb6cb37ee81..00bfe32c85906 100644 --- a/src/legacy/core_plugins/console/np_ready/public/lib/ace_token_provider/token_provider.test.ts +++ b/src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/token_provider.test.ts @@ -17,15 +17,17 @@ * under the License. */ -// @ts-ignore -import '../../../../public/quarantined/tests/src/setup_mocks'; +import '../../application/models/sense_editor/sense_editor.test.mocks'; -import { Editor } from 'brace'; import $ from 'jquery'; -// @ts-ignore -import { initializeEditor } from '../../../../public/quarantined/src/input.ts'; -import { AceTokensProvider } from '.'; +// TODO: +// We import from application models as a convenient way to bootstrap loading up of an editor using +// this lib. We also need to import application specific mocks which is not ideal. +// In this situation, the token provider lib knows about app models in tests, which it really shouldn't. Should create +// a better sandbox in future. +import { create, SenseEditor } from '../../application/models/sense_editor'; + import { Position, Token, TokensProvider } from '../../types'; interface RunTestArgs { @@ -34,7 +36,7 @@ interface RunTestArgs { } describe('Ace (legacy) token provider', () => { - let aceEditor: Editor & { $el: any; autocomplete: any; update: any }; + let senseEditor: SenseEditor; let tokenProvider: TokensProvider; beforeEach(() => { // Set up our document body @@ -44,16 +46,18 @@ describe('Ace (legacy) token provider', () => {
    `; - aceEditor = initializeEditor($('#ConAppEditor'), $('#ConAppEditorActions')); + senseEditor = create(document.querySelector('#ConAppEditor')!); + + $(senseEditor.getCoreEditor().getContainer())!.show(); - aceEditor.$el.show(); - aceEditor.autocomplete._test.removeChangeListener(); - tokenProvider = new AceTokensProvider(aceEditor.session); + (senseEditor as any).autocomplete._test.removeChangeListener(); + tokenProvider = senseEditor.getCoreEditor().getTokenProvider(); }); - afterEach(done => { - aceEditor.$el.hide(); - aceEditor.autocomplete._test.addChangeListener(); - aceEditor.update('', done); + + afterEach(async () => { + $(senseEditor.getCoreEditor().getContainer())!.hide(); + (senseEditor as any).autocomplete._test.addChangeListener(); + await senseEditor.update('', true); }); describe('#getTokens', () => { @@ -63,7 +67,7 @@ describe('Ace (legacy) token provider', () => { done, lineNumber = 1, }: RunTestArgs & { expectedTokens: Token[] | null; lineNumber?: number }) => { - aceEditor.update(input, function() { + senseEditor.update(input, true).then(() => { const tokens = tokenProvider.getTokens(lineNumber); expect(tokens).toEqual(expectedTokens); if (done) done(); @@ -160,7 +164,7 @@ describe('Ace (legacy) token provider', () => { test('case 2 - empty lines', done => { runTest({ input: `GET http://test:user@somehost/ - + @@ -182,7 +186,7 @@ describe('Ace (legacy) token provider', () => { done, position, }: RunTestArgs & { expectedToken: Token | null; position: Position }) => { - aceEditor.update(input, function() { + senseEditor.update(input, true).then(() => { const tokens = tokenProvider.getTokenAt(position); expect(tokens).toEqual(expectedToken); if (done) done(); diff --git a/src/legacy/core_plugins/console/np_ready/public/lib/ace_token_provider/token_provider.ts b/src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/token_provider.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/lib/ace_token_provider/token_provider.ts rename to src/legacy/core_plugins/console/public/np_ready/lib/ace_token_provider/token_provider.ts diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/url_autocomplete.test.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/__tests__/url_autocomplete.test.js similarity index 98% rename from src/legacy/core_plugins/console/public/quarantined/tests/src/url_autocomplete.test.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/__tests__/url_autocomplete.test.js index 154a7e9ba2b4b..77c211a71d986 100644 --- a/src/legacy/core_plugins/console/public/quarantined/tests/src/url_autocomplete.test.js +++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/__tests__/url_autocomplete.test.js @@ -16,18 +16,16 @@ * specific language governing permissions and limitations * under the License. */ -import './setup_mocks'; -import 'brace'; -import 'brace/mode/javascript'; -import 'brace/mode/json'; +import '../../../application/models/sense_editor/sense_editor.test.mocks'; + const _ = require('lodash'); import { URL_PATH_END_MARKER, UrlPatternMatcher, ListComponent -} from '../../src/autocomplete/components'; +} from '../../autocomplete/components'; -import { populateContext } from '../../src/autocomplete/engine'; +import { populateContext } from '../../autocomplete/engine'; describe('Url autocomplete', () => { function patternsTest( diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/url_params.test.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/__tests__/url_params.test.js similarity index 94% rename from src/legacy/core_plugins/console/public/quarantined/tests/src/url_params.test.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/__tests__/url_params.test.js index 7b44d91fa503a..b91c463bb14ff 100644 --- a/src/legacy/core_plugins/console/public/quarantined/tests/src/url_params.test.js +++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/__tests__/url_params.test.js @@ -16,13 +16,13 @@ * specific language governing permissions and limitations * under the License. */ -import './setup_mocks'; +import '../../../application/models/sense_editor/sense_editor.test.mocks'; import 'brace'; import 'brace/mode/javascript'; import 'brace/mode/json'; const _ = require('lodash'); -import { UrlParams } from '../../src/autocomplete/url_params'; -import { populateContext } from '../../src/autocomplete/engine'; +import { UrlParams } from '../../autocomplete/url_params'; +import { populateContext } from '../../autocomplete/engine'; describe('Url params', () => { function paramTest( diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete.ts b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/autocomplete.ts similarity index 94% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete.ts rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/autocomplete.ts index 47edf42f0eec5..8edb26f7817e4 100644 --- a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete.ts +++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/autocomplete.ts @@ -18,7 +18,7 @@ */ import _ from 'lodash'; -import ace, { Editor as AceEditor, IEditSession, Position as AcePosition } from 'brace'; +import ace, { Editor as AceEditor, IEditSession } from 'brace'; import { i18n } from '@kbn/i18n'; import { @@ -27,17 +27,18 @@ import { getGlobalAutocompleteComponents, getUnmatchedEndpointComponents, // @ts-ignore -} from './kb'; -// @ts-ignore -import utils from './utils'; +} from '../kb/kb'; + +import * as utils from '../utils/utils'; + // @ts-ignore -import { populateContext } from './autocomplete/engine'; +import { populateContext } from './engine'; // @ts-ignore -import { URL_PATH_END_MARKER } from './autocomplete/components'; -import { createTokenIterator } from '../../../np_ready/public/application/factories'; +import { URL_PATH_END_MARKER } from './components/index'; +import { createTokenIterator } from '../../application/factories'; -import { Position, Token, Range } from '../../../np_ready/public/types'; -import { LegacyEditor } from '../../../np_ready/public/application/models'; +import { Position, Token, Range, CoreEditor } from '../../types'; +import { SenseEditor } from '../../application/models/sense_editor'; let LAST_EVALUATED_TOKEN: any = null; @@ -54,7 +55,7 @@ function isUrlParamsToken(token: any) { } } function getCurrentMethodAndTokenPaths( - editor: LegacyEditor, + editor: CoreEditor, pos: Position, parser: any, forceEndOfUrl?: boolean @@ -297,12 +298,12 @@ function getCurrentMethodAndTokenPaths( } return ret; } -export function getEndpointFromPosition(aceEditor: AceEditor, pos: AcePosition, parser: any) { - const editor = new LegacyEditor(aceEditor); +export function getEndpointFromPosition(senseEditor: SenseEditor, pos: Position, parser: any) { + const editor = senseEditor.getCoreEditor(); const context = { ...getCurrentMethodAndTokenPaths( editor, - { column: pos.column + 1, lineNumber: pos.row + 1 }, + { column: pos.column, lineNumber: pos.lineNumber }, parser, true ), @@ -313,23 +314,7 @@ export function getEndpointFromPosition(aceEditor: AceEditor, pos: AcePosition, } // eslint-disable-next-line -export default function({ - coreEditor: editor, - parser, - execCommand, - getCursorPosition, - isCompleterActive, - addChangeListener, - removeChangeListener, -}: { - coreEditor: LegacyEditor; - parser: any; - execCommand: (cmd: string) => void; - getCursorPosition: () => Position | null; - isCompleterActive: () => boolean; - addChangeListener: (fn: any) => void; - removeChangeListener: (fn: any) => void; -}) { +export default function({ coreEditor: editor, parser }: { coreEditor: CoreEditor; parser: any }) { function isUrlPathToken(token: Token | null) { switch ((token || ({} as any)).type) { case 'url.slash': @@ -404,7 +389,7 @@ export default function({ valueToInsert = context.prefixToAdd + valueToInsert + context.suffixToAdd; // disable listening to the changes we are making. - removeChangeListener(editorChangeListener); + editor.off('changeSelection', editorChangeListener); if (context.rangeToReplace.start.column !== context.rangeToReplace.end.column) { editor.replace(context.rangeToReplace, valueToInsert); @@ -456,10 +441,10 @@ export default function({ } // re-enable listening to typing - addChangeListener(editorChangeListener); + editor.on('changeSelection', editorChangeListener); } - function getAutoCompleteContext(ctxEditor: LegacyEditor, pos: Position) { + function getAutoCompleteContext(ctxEditor: CoreEditor, pos: Position) { // deduces all the parameters need to position and insert the auto complete const context: any = { autoCompleteSet: null, // instructions for what can be here @@ -567,10 +552,8 @@ export default function({ // in between request on an empty if (editor.getLineValue(pos.lineNumber).trim() === '') { - // check if the previous line is a single line begging of a new request - rowMode = parser.getRowParseMode( - pos.lineNumber - 1 - 1 /* see RowParser for why the added -1, for now */ - ); + // check if the previous line is a single line beginning of a new request + rowMode = parser.getRowParseMode(pos.lineNumber - 1); // eslint-disable-next-line no-bitwise if ( // eslint-disable-next-line no-bitwise @@ -964,23 +947,23 @@ export default function({ } LAST_EVALUATED_TOKEN = currentToken; - execCommand('startAutocomplete'); + editor.execCommand('startAutocomplete'); }, 100); function editorChangeListener() { - const position = getCursorPosition(); - if (position && !isCompleterActive()) { + const position = editor.getCurrentPosition(); + if (position && !editor.isCompleterActive()) { evaluateCurrentTokenAfterAChange(position); } } function getCompletions( DO_NOT_USE: AceEditor, - session: IEditSession, - pos: any, - prefix: any, - callback: any + DO_NOT_USE_SESSION: IEditSession, + pos: { row: number; column: number }, + prefix: string, + callback: (...args: any[]) => void ) { const position: Position = { lineNumber: pos.row + 1, @@ -1054,7 +1037,7 @@ export default function({ } } - addChangeListener(editorChangeListener); + editor.on('changeSelection', editorChangeListener); // Hook into Ace @@ -1090,8 +1073,8 @@ export default function({ _test: { getCompletions, addReplacementInfoToContext, - addChangeListener: () => addChangeListener(editorChangeListener), - removeChangeListener: () => removeChangeListener(editorChangeListener), + addChangeListener: () => editor.on('changeSelection', editorChangeListener), + removeChangeListener: () => editor.off('changeSelection', editorChangeListener), }, }; } diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/body_completer.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/body_completer.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/body_completer.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/body_completer.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/accept_endpoint_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/accept_endpoint_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/accept_endpoint_component.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/accept_endpoint_component.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/autocomplete_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/autocomplete_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/autocomplete_component.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/autocomplete_component.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/conditional_proxy.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/conditional_proxy.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/conditional_proxy.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/conditional_proxy.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/constant_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/constant_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/constant_component.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/constant_component.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/field_autocomplete_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/field_autocomplete_component.js similarity index 96% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/field_autocomplete_component.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/field_autocomplete_component.js index b2424bebf1b9d..e07db78c4cca9 100644 --- a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/field_autocomplete_component.js +++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/field_autocomplete_component.js @@ -17,7 +17,7 @@ * under the License. */ import _ from 'lodash'; -import mappings from '../../mappings'; +import mappings from '../../mappings/mappings'; import { ListComponent } from './list_component'; function FieldGenerator(context) { diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/global_only_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/global_only_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/global_only_component.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/global_only_component.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/id_autocomplete_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/id_autocomplete_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/id_autocomplete_component.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/id_autocomplete_component.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/index.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/index.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/index.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/index.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/index_autocomplete_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/index_autocomplete_component.js similarity index 96% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/index_autocomplete_component.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/index_autocomplete_component.js index 33e27852caff2..03d67c9e27ee8 100644 --- a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/index_autocomplete_component.js +++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/index_autocomplete_component.js @@ -17,7 +17,7 @@ * under the License. */ import _ from 'lodash'; -import mappings from '../../mappings'; +import mappings from '../../mappings/mappings'; import { ListComponent } from './list_component'; function nonValidIndexType(token) { return !(token === '_all' || token[0] !== '_'); diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/list_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/list_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/list_component.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/list_component.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/object_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/object_component.js similarity index 98% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/object_component.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/object_component.js index 4db392e60ff83..5cff4a15647ce 100644 --- a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/object_component.js +++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/object_component.js @@ -18,7 +18,7 @@ */ import _ from 'lodash'; -import { SharedComponent } from '.'; +import { SharedComponent } from './index'; /** * @param constants list of components that represent constant keys * @param patternsAndWildCards list of components that represent patterns and should be matched only if diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/shared_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/shared_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/shared_component.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/shared_component.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/simple_param_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/simple_param_component.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/simple_param_component.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/simple_param_component.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/template_autocomplete_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/template_autocomplete_component.js similarity index 95% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/template_autocomplete_component.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/template_autocomplete_component.js index 0c00b2f93ee6f..cc62a2f9eeea6 100644 --- a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/template_autocomplete_component.js +++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/template_autocomplete_component.js @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import mappings from '../../mappings'; +import mappings from '../../mappings/mappings'; import { ListComponent } from './list_component'; export class TemplateAutocompleteComponent extends ListComponent { diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/type_autocomplete_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/type_autocomplete_component.js similarity index 96% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/type_autocomplete_component.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/type_autocomplete_component.js index 4f1c85213b689..ca317fec9e27f 100644 --- a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/type_autocomplete_component.js +++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/type_autocomplete_component.js @@ -18,7 +18,7 @@ */ import _ from 'lodash'; import { ListComponent } from './list_component'; -import mappings from '../../mappings'; +import mappings from '../../mappings/mappings'; function TypeGenerator(context) { return mappings.getTypes(context.indices); } diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/url_pattern_matcher.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/url_pattern_matcher.js similarity index 99% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/url_pattern_matcher.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/url_pattern_matcher.js index 20978c2fbea60..dfae1382bed9b 100644 --- a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/url_pattern_matcher.js +++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/url_pattern_matcher.js @@ -23,7 +23,7 @@ import { AcceptEndpointComponent, ListComponent, SimpleParamComponent, -} from '.'; +} from './index'; /** * @param parametrizedComponentFactories a dict of the following structure diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/username_autocomplete_component.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/username_autocomplete_component.js similarity index 96% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/username_autocomplete_component.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/username_autocomplete_component.js index da3c63b69c610..26b7bd5c48c99 100644 --- a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/components/username_autocomplete_component.js +++ b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/components/username_autocomplete_component.js @@ -17,7 +17,7 @@ * under the License. */ import _ from 'lodash'; -import mappings from '../../mappings'; +import mappings from '../../mappings/mappings'; import { ListComponent } from './list_component'; function nonValidUsernameType(token) { return token[0] === '_'; diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/engine.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/engine.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/engine.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/engine.js diff --git a/src/legacy/core_plugins/console/public/quarantined/src/autocomplete/url_params.js b/src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/url_params.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/autocomplete/url_params.js rename to src/legacy/core_plugins/console/public/np_ready/lib/autocomplete/url_params.js diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/curl_parsing.test.js b/src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/__tests__/curl_parsing.test.js similarity index 97% rename from src/legacy/core_plugins/console/public/quarantined/tests/src/curl_parsing.test.js rename to src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/__tests__/curl_parsing.test.js index e1bed169bb730..bf783b3dfe8ae 100644 --- a/src/legacy/core_plugins/console/public/quarantined/tests/src/curl_parsing.test.js +++ b/src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/__tests__/curl_parsing.test.js @@ -18,7 +18,7 @@ */ const _ = require('lodash'); -const curl = require('../../src/curl'); +const curl = require('../curl'); import curlTests from './curl_parsing.txt'; describe('CURL', () => { diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/curl_parsing.txt b/src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/__tests__/curl_parsing.txt similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/tests/src/curl_parsing.txt rename to src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/__tests__/curl_parsing.txt diff --git a/src/legacy/core_plugins/console/public/quarantined/src/curl.js b/src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/curl.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/curl.js rename to src/legacy/core_plugins/console/public/np_ready/lib/curl_parsing/curl.js diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/content_type.test.js b/src/legacy/core_plugins/console/public/np_ready/lib/es/__tests__/content_type.test.js similarity index 96% rename from src/legacy/core_plugins/console/public/quarantined/tests/src/content_type.test.js rename to src/legacy/core_plugins/console/public/np_ready/lib/es/__tests__/content_type.test.js index 224eab7dc925d..acc33e331c9f9 100644 --- a/src/legacy/core_plugins/console/public/quarantined/tests/src/content_type.test.js +++ b/src/legacy/core_plugins/console/public/np_ready/lib/es/__tests__/content_type.test.js @@ -17,7 +17,7 @@ * under the License. */ -import { getContentType } from '../../src/es'; +import { getContentType } from '../es'; const APPLICATION_JSON = 'application/json'; describe('Content type', () => { diff --git a/src/legacy/core_plugins/console/public/quarantined/src/es.js b/src/legacy/core_plugins/console/public/np_ready/lib/es/es.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/es.js rename to src/legacy/core_plugins/console/public/np_ready/lib/es/es.js diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/kb.test.js b/src/legacy/core_plugins/console/public/np_ready/lib/kb/__tests__/kb.test.js similarity index 95% rename from src/legacy/core_plugins/console/public/quarantined/tests/src/kb.test.js rename to src/legacy/core_plugins/console/public/np_ready/lib/kb/__tests__/kb.test.js index 1618573f911ed..ad29f9808a6c2 100644 --- a/src/legacy/core_plugins/console/public/quarantined/tests/src/kb.test.js +++ b/src/legacy/core_plugins/console/public/np_ready/lib/kb/__tests__/kb.test.js @@ -18,14 +18,11 @@ */ import _ from 'lodash'; -import { populateContext } from '../../src/autocomplete/engine'; - -import './setup_mocks'; -import 'brace'; -import 'brace/mode/javascript'; -import 'brace/mode/json'; -const kb = require('../../src/kb'); -const mappings = require('../../src/mappings'); +import { populateContext } from '../../autocomplete/engine'; + +import '../../../application/models/sense_editor/sense_editor.test.mocks'; +const kb = require('../../kb'); +const mappings = require('../../mappings/mappings'); describe('Knowledge base', () => { beforeEach(() => { diff --git a/src/legacy/core_plugins/console/public/quarantined/src/kb/api.js b/src/legacy/core_plugins/console/public/np_ready/lib/kb/api.js similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/src/kb/api.js rename to src/legacy/core_plugins/console/public/np_ready/lib/kb/api.js diff --git a/src/legacy/core_plugins/console/np_ready/public/application/models/index.ts b/src/legacy/core_plugins/console/public/np_ready/lib/kb/index.js similarity index 96% rename from src/legacy/core_plugins/console/np_ready/public/application/models/index.ts rename to src/legacy/core_plugins/console/public/np_ready/lib/kb/index.js index c4ac6f1454b7f..383ebef57da92 100644 --- a/src/legacy/core_plugins/console/np_ready/public/application/models/index.ts +++ b/src/legacy/core_plugins/console/public/np_ready/lib/kb/index.js @@ -17,4 +17,4 @@ * under the License. */ -export * from './legacy_editor'; +export * from './kb'; diff --git a/src/legacy/core_plugins/console/public/quarantined/src/kb.js b/src/legacy/core_plugins/console/public/np_ready/lib/kb/kb.js similarity index 98% rename from src/legacy/core_plugins/console/public/quarantined/src/kb.js rename to src/legacy/core_plugins/console/public/np_ready/lib/kb/kb.js index 6a7edf5bc337f..ffba14fad3f37 100644 --- a/src/legacy/core_plugins/console/public/quarantined/src/kb.js +++ b/src/legacy/core_plugins/console/public/np_ready/lib/kb/kb.js @@ -24,12 +24,12 @@ import { ListComponent, TemplateAutocompleteComponent, UsernameAutocompleteComponent, -} from './autocomplete/components'; +} from '../autocomplete/components'; import $ from 'jquery'; import _ from 'lodash'; -import Api from './kb/api'; +import Api from './api'; let ACTIVE_API = new Api(); const isNotAnIndexName = name => name[0] === '_' && name !== '_all'; diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/mapping.test.js b/src/legacy/core_plugins/console/public/np_ready/lib/mappings/__tests__/mapping.test.js similarity index 97% rename from src/legacy/core_plugins/console/public/quarantined/tests/src/mapping.test.js rename to src/legacy/core_plugins/console/public/np_ready/lib/mappings/__tests__/mapping.test.js index d79f3c50b8373..875a16402e394 100644 --- a/src/legacy/core_plugins/console/public/quarantined/tests/src/mapping.test.js +++ b/src/legacy/core_plugins/console/public/np_ready/lib/mappings/__tests__/mapping.test.js @@ -16,11 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -import './setup_mocks'; -import 'brace'; -import 'brace/mode/javascript'; -import 'brace/mode/json'; -const mappings = require('../../src/mappings'); +import '../../../application/models/sense_editor/sense_editor.test.mocks'; +const mappings = require('../mappings'); describe('Mappings', () => { beforeEach(() => { diff --git a/src/legacy/core_plugins/console/public/quarantined/src/mappings.js b/src/legacy/core_plugins/console/public/np_ready/lib/mappings/mappings.js similarity index 98% rename from src/legacy/core_plugins/console/public/quarantined/src/mappings.js rename to src/legacy/core_plugins/console/public/np_ready/lib/mappings/mappings.js index 69f122a607836..b0acf369260e9 100644 --- a/src/legacy/core_plugins/console/public/quarantined/src/mappings.js +++ b/src/legacy/core_plugins/console/public/np_ready/lib/mappings/mappings.js @@ -17,11 +17,11 @@ * under the License. */ -import { legacyBackDoorToSettings } from '../../../np_ready/public/application'; +import { legacyBackDoorToSettings } from '../../application'; const $ = require('jquery'); const _ = require('lodash'); -const es = require('./es'); +const es = require('../es/es'); // NOTE: If this value ever changes to be a few seconds or less, it might introduce flakiness // due to timing issues in our app.js tests. diff --git a/src/legacy/core_plugins/console/public/np_ready/lib/row_parser.ts b/src/legacy/core_plugins/console/public/np_ready/lib/row_parser.ts new file mode 100644 index 0000000000000..b56d15e178810 --- /dev/null +++ b/src/legacy/core_plugins/console/public/np_ready/lib/row_parser.ts @@ -0,0 +1,151 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { CoreEditor, Token } from '../types'; +import { TokenIterator } from './token_iterator'; + +export const MODE = { + REQUEST_START: 2, + IN_REQUEST: 4, + MULTI_DOC_CUR_DOC_END: 8, + REQUEST_END: 16, + BETWEEN_REQUESTS: 32, +}; + +// eslint-disable-next-line import/no-default-export +export default class RowParser { + constructor(private readonly editor: CoreEditor) {} + + MODE = MODE; + + getRowParseMode(lineNumber = this.editor.getCurrentPosition().lineNumber) { + const linesCount = this.editor.getLineCount(); + if (lineNumber > linesCount || lineNumber < 1) { + return MODE.BETWEEN_REQUESTS; + } + const mode = this.editor.getLineState(lineNumber); + if (!mode) { + return MODE.BETWEEN_REQUESTS; + } // shouldn't really happen + + if (mode !== 'start') { + return MODE.IN_REQUEST; + } + let line = (this.editor.getLineValue(lineNumber) || '').trim(); + if (!line || line[0] === '#') { + return MODE.BETWEEN_REQUESTS; + } // empty line or a comment waiting for a new req to start + + if (line.indexOf('}', line.length - 1) >= 0) { + // check for a multi doc request (must start a new json doc immediately after this one end. + lineNumber++; + if (lineNumber < linesCount + 1) { + line = (this.editor.getLineValue(lineNumber) || '').trim(); + if (line.indexOf('{') === 0) { + // next line is another doc in a multi doc + // eslint-disable-next-line no-bitwise + return MODE.MULTI_DOC_CUR_DOC_END | MODE.IN_REQUEST; + } + } + // eslint-disable-next-line no-bitwise + return MODE.REQUEST_END | MODE.MULTI_DOC_CUR_DOC_END; // end of request + } + + // check for single line requests + lineNumber++; + if (lineNumber >= linesCount + 1) { + // eslint-disable-next-line no-bitwise + return MODE.REQUEST_START | MODE.REQUEST_END; + } + line = (this.editor.getLineValue(lineNumber) || '').trim(); + if (line.indexOf('{') !== 0) { + // next line is another request + // eslint-disable-next-line no-bitwise + return MODE.REQUEST_START | MODE.REQUEST_END; + } + + return MODE.REQUEST_START; + } + + rowPredicate(lineNumber: number | undefined, editor: CoreEditor, value: any) { + const mode = this.getRowParseMode(lineNumber); + // eslint-disable-next-line no-bitwise + return (mode & value) > 0; + } + + isEndRequestRow(row?: number, _e?: CoreEditor) { + const editor = _e || this.editor; + return this.rowPredicate(row, editor, MODE.REQUEST_END); + } + + isRequestEdge(row?: number, _e?: CoreEditor) { + const editor = _e || this.editor; + // eslint-disable-next-line no-bitwise + return this.rowPredicate(row, editor, MODE.REQUEST_END | MODE.REQUEST_START); + } + + isStartRequestRow(row?: number, _e?: CoreEditor) { + const editor = _e || this.editor; + return this.rowPredicate(row, editor, MODE.REQUEST_START); + } + + isInBetweenRequestsRow(row?: number, _e?: CoreEditor) { + const editor = _e || this.editor; + return this.rowPredicate(row, editor, MODE.BETWEEN_REQUESTS); + } + + isInRequestsRow(row?: number, _e?: CoreEditor) { + const editor = _e || this.editor; + return this.rowPredicate(row, editor, MODE.IN_REQUEST); + } + + isMultiDocDocEndRow(row?: number, _e?: CoreEditor) { + const editor = _e || this.editor; + return this.rowPredicate(row, editor, MODE.MULTI_DOC_CUR_DOC_END); + } + + isEmptyToken(tokenOrTokenIter: TokenIterator | Token | null) { + const token = + tokenOrTokenIter && (tokenOrTokenIter as TokenIterator).getCurrentToken + ? (tokenOrTokenIter as TokenIterator).getCurrentToken() + : tokenOrTokenIter; + return !token || (token as Token).type === 'whitespace'; + } + + isUrlOrMethodToken(tokenOrTokenIter: TokenIterator | Token) { + const t = (tokenOrTokenIter as TokenIterator)?.getCurrentToken() ?? (tokenOrTokenIter as Token); + return t && t.type && (t.type === 'method' || t.type.indexOf('url') === 0); + } + + nextNonEmptyToken(tokenIter: TokenIterator) { + let t = tokenIter.stepForward(); + while (t && this.isEmptyToken(t)) { + t = tokenIter.stepForward(); + } + return t; + } + + prevNonEmptyToken(tokenIter: TokenIterator) { + let t = tokenIter.stepBackward(); + // empty rows return null token. + while ((t || tokenIter.getCurrentPosition().lineNumber > 1) && this.isEmptyToken(t)) + t = tokenIter.stepBackward(); + return t; + } +} diff --git a/src/legacy/core_plugins/console/np_ready/public/lib/token_iterator/index.ts b/src/legacy/core_plugins/console/public/np_ready/lib/token_iterator/index.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/lib/token_iterator/index.ts rename to src/legacy/core_plugins/console/public/np_ready/lib/token_iterator/index.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/lib/token_iterator/token_iterator.test.ts b/src/legacy/core_plugins/console/public/np_ready/lib/token_iterator/token_iterator.test.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/lib/token_iterator/token_iterator.test.ts rename to src/legacy/core_plugins/console/public/np_ready/lib/token_iterator/token_iterator.test.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/lib/token_iterator/token_iterator.ts b/src/legacy/core_plugins/console/public/np_ready/lib/token_iterator/token_iterator.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/lib/token_iterator/token_iterator.ts rename to src/legacy/core_plugins/console/public/np_ready/lib/token_iterator/token_iterator.ts diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/utils.test.js b/src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils.test.js similarity index 91% rename from src/legacy/core_plugins/console/public/quarantined/tests/src/utils.test.js rename to src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils.test.js index a139aa47b911f..827beadee0f0b 100644 --- a/src/legacy/core_plugins/console/public/quarantined/tests/src/utils.test.js +++ b/src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils.test.js @@ -18,12 +18,25 @@ */ const _ = require('lodash'); -const utils = require('../../src/utils'); +const utils = require('../utils'); const collapsingTests = require('./utils_string_collapsing.txt'); const expandingTests = require('./utils_string_expanding.txt'); describe('Utils class', () => { + describe('collapseLiteralStrings', () => { + it('will collapse multiline strings', () => { + const multiline = '{ "foo": """bar\nbaz""" }'; + expect(utils.collapseLiteralStrings(multiline)).toEqual('{ "foo": "bar\\nbaz" }'); + }); + + it('will collapse multiline strings with CRLF endings', () => { + const multiline = '{ "foo": """bar\r\nbaz""" }'; + expect(utils.collapseLiteralStrings(multiline)).toEqual('{ "foo": "bar\\r\\nbaz" }'); + }); + }); + + _.each(collapsingTests.split(/^=+$/m), function (fixture) { if (fixture.trim() === '') { return; diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/utils_string_collapsing.txt b/src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils_string_collapsing.txt similarity index 100% rename from src/legacy/core_plugins/console/public/quarantined/tests/src/utils_string_collapsing.txt rename to src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils_string_collapsing.txt diff --git a/src/legacy/core_plugins/console/public/quarantined/tests/src/utils_string_expanding.txt b/src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils_string_expanding.txt similarity index 79% rename from src/legacy/core_plugins/console/public/quarantined/tests/src/utils_string_expanding.txt rename to src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils_string_expanding.txt index 34bf0f3bc20e7..88467ab3672cd 100644 --- a/src/legacy/core_plugins/console/public/quarantined/tests/src/utils_string_expanding.txt +++ b/src/legacy/core_plugins/console/public/np_ready/lib/utils/__tests__/utils_string_expanding.txt @@ -40,3 +40,15 @@ Correctly parse with JSON embedded inside values "content\\\\": """ { "json": "inside\\" ok! 1 " } """ } +========== +Correctly handle new lines in triple quotes +------------------------------------- +{ + "query": "\n SELECT * FROM \"TABLE\"\n " +} +------------------------------------- +{ + "query": """ + SELECT * FROM "TABLE" + """ +} diff --git a/src/legacy/core_plugins/console/public/quarantined/src/utils.js b/src/legacy/core_plugins/console/public/np_ready/lib/utils/utils.ts similarity index 77% rename from src/legacy/core_plugins/console/public/quarantined/src/utils.js rename to src/legacy/core_plugins/console/public/np_ready/lib/utils/utils.ts index 5b6bd1646c300..a7f59acf1d77b 100644 --- a/src/legacy/core_plugins/console/public/quarantined/src/utils.js +++ b/src/legacy/core_plugins/console/public/np_ready/lib/utils/utils.ts @@ -19,52 +19,50 @@ import _ from 'lodash'; -const utils = {}; - -utils.textFromRequest = function (request) { +export function textFromRequest(request: any) { let data = request.data; if (typeof data !== 'string') { data = data.join('\n'); } return request.method + ' ' + request.url + '\n' + data; -}; +} -utils.jsonToString = function (data, indent) { +export function jsonToString(data: any, indent: boolean) { return JSON.stringify(data, null, indent ? 2 : 0); -}; +} -utils.reformatData = function (data, indent) { +export function formatRequestBodyDoc(data: string[], indent: boolean) { let changed = false; const formattedData = []; for (let i = 0; i < data.length; i++) { const curDoc = data[i]; try { - let newDoc = utils.jsonToString(JSON.parse(utils.collapseLiteralStrings(curDoc)), indent ? 2 : 0); + let newDoc = jsonToString(JSON.parse(collapseLiteralStrings(curDoc)), indent); if (indent) { - newDoc = utils.expandLiteralStrings(newDoc); + newDoc = expandLiteralStrings(newDoc); } changed = changed || newDoc !== curDoc; formattedData.push(newDoc); - } - catch (e) { + } catch (e) { + // eslint-disable-next-line no-console console.log(e); formattedData.push(curDoc); } } return { - changed: changed, - data: formattedData + changed, + data: formattedData, }; -}; +} -utils.collapseLiteralStrings = function (data) { +export function collapseLiteralStrings(data: any) { const splitData = data.split(`"""`); for (let idx = 1; idx < splitData.length - 1; idx += 2) { splitData[idx] = JSON.stringify(splitData[idx]); } return splitData.join(''); -}; +} /* The following regex describes global match on: @@ -81,39 +79,38 @@ utils.collapseLiteralStrings = function (data) { const LITERAL_STRING_CANDIDATES = /((:[\s\r\n]*)([^\\])"(\\"|[^"\n])*\\?")/g; -utils.expandLiteralStrings = function (data) { - return data.replace(LITERAL_STRING_CANDIDATES, function (match, string) { +export function expandLiteralStrings(data: string) { + return data.replace(LITERAL_STRING_CANDIDATES, (match, string) => { // Expand to triple quotes if there are _any_ slashes if (string.match(/\\./)) { const firstDoubleQuoteIdx = string.indexOf('"'); const colonAndAnySpacing = string.slice(0, firstDoubleQuoteIdx); const rawStringifiedValue = string.slice(firstDoubleQuoteIdx, string.length); - const jsonValue = JSON.parse(rawStringifiedValue) - .replace('^\s*\n', '') - .replace('\n\s*^', ''); + // Remove one level of JSON stringification + const jsonValue = JSON.parse(rawStringifiedValue); return `${colonAndAnySpacing}"""${jsonValue}"""`; } else { return string; } }); -}; +} -utils.extractDeprecationMessages = function (warnings) { +export function extractDeprecationMessages(warnings: string) { // pattern for valid warning header const re = /\d{3} [0-9a-zA-Z!#$%&'*+-.^_`|~]+ \"((?:\t| |!|[\x23-\x5b]|[\x5d-\x7e]|[\x80-\xff]|\\\\|\\")*)\"(?: \"[^"]*\")?/; // split on any comma that is followed by an even number of quotes - return _.map(utils.splitOnUnquotedCommaSpace(warnings), function (warning) { + return _.map(splitOnUnquotedCommaSpace(warnings), warning => { const match = re.exec(warning); // extract the actual warning if there was a match - return '#! Deprecation: ' + (match !== null ? utils.unescape(match[1]) : warning); + return '#! Deprecation: ' + (match !== null ? unescape(match[1]) : warning); }); -}; +} -utils.unescape = function (s) { +export function unescape(s: string) { return s.replace(/\\\\/g, '\\').replace(/\\"/g, '"'); -}; +} -utils.splitOnUnquotedCommaSpace = function (s) { +export function splitOnUnquotedCommaSpace(s: string) { let quoted = false; const arr = []; let buffer = ''; @@ -136,6 +133,4 @@ utils.splitOnUnquotedCommaSpace = function (s) { } arr.push(buffer); return arr; -}; - -export default utils; +} diff --git a/src/legacy/core_plugins/console/np_ready/public/plugin.ts b/src/legacy/core_plugins/console/public/np_ready/plugin.ts similarity index 90% rename from src/legacy/core_plugins/console/np_ready/public/plugin.ts rename to src/legacy/core_plugins/console/public/np_ready/plugin.ts index 37758adc98d11..cbe262b124677 100644 --- a/src/legacy/core_plugins/console/np_ready/public/plugin.ts +++ b/src/legacy/core_plugins/console/public/np_ready/plugin.ts @@ -20,9 +20,8 @@ import { render, unmountComponentAtNode } from 'react-dom'; import { i18n } from '@kbn/i18n'; -import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue'; -import { PluginInitializerContext, Plugin, CoreStart, CoreSetup } from '../../../../../core/public'; -import { XPluginSet } from './legacy'; +import { PluginInitializerContext, Plugin, CoreStart, CoreSetup } from 'src/core/public'; +import { XPluginSet } from '../legacy'; export class ConsoleUIPlugin implements Plugin { // @ts-ignore @@ -30,7 +29,7 @@ export class ConsoleUIPlugin implements Plugin { async setup({ notifications }: CoreSetup, pluginSet: XPluginSet) { const { - __LEGACY: { I18nContext }, + __LEGACY: { I18nContext, elasticsearchUrl, category }, dev_tools, home, } = pluginSet; @@ -46,7 +45,7 @@ export class ConsoleUIPlugin implements Plugin { icon: 'consoleApp', path: '/app/kibana#/dev_tools/console', showOnHomePage: true, - category: FeatureCatalogueCategory.ADMIN, + category, }); dev_tools.register({ @@ -63,6 +62,7 @@ export class ConsoleUIPlugin implements Plugin { docLinkVersion: ctx.core.docLinks.DOC_LINK_VERSION, I18nContext, notifications, + elasticsearchUrl, }), element ); diff --git a/src/legacy/core_plugins/console/np_ready/public/services/history.ts b/src/legacy/core_plugins/console/public/np_ready/services/history.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/services/history.ts rename to src/legacy/core_plugins/console/public/np_ready/services/history.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/services/index.ts b/src/legacy/core_plugins/console/public/np_ready/services/index.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/services/index.ts rename to src/legacy/core_plugins/console/public/np_ready/services/index.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/services/settings.ts b/src/legacy/core_plugins/console/public/np_ready/services/settings.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/services/settings.ts rename to src/legacy/core_plugins/console/public/np_ready/services/settings.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/services/storage.ts b/src/legacy/core_plugins/console/public/np_ready/services/storage.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/services/storage.ts rename to src/legacy/core_plugins/console/public/np_ready/services/storage.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/types/common.ts b/src/legacy/core_plugins/console/public/np_ready/types/common.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/types/common.ts rename to src/legacy/core_plugins/console/public/np_ready/types/common.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/types/core_editor.ts b/src/legacy/core_plugins/console/public/np_ready/types/core_editor.ts similarity index 62% rename from src/legacy/core_plugins/console/np_ready/public/types/core_editor.ts rename to src/legacy/core_plugins/console/public/np_ready/types/core_editor.ts index fdd2e2639e554..8de4c78333fee 100644 --- a/src/legacy/core_plugins/console/np_ready/public/types/core_editor.ts +++ b/src/legacy/core_plugins/console/public/np_ready/types/core_editor.ts @@ -20,6 +20,15 @@ import { TokensProvider } from './tokens_provider'; import { Token } from './token'; +type MarkerRef = any; + +export type EditorEvent = + | 'tokenizerUpdate' + | 'changeCursor' + | 'changeScrollTop' + | 'change' + | 'changeSelection'; + export interface Position { /** * The line number, not zero-indexed. @@ -95,6 +104,13 @@ export interface CoreEditor { */ getValue(): string; + /** + * Sets the contents of the editor. + * + * Returns a promise so that callers can wait for re-tokenizing to complete. + */ + setValue(value: string, forceRetokenize: boolean): Promise; + /** * Get the contents of the editor at a specific line. */ @@ -120,6 +136,11 @@ export interface CoreEditor { */ clearSelection(): void; + /** + * Returns the {@link Range} for currently selected text + */ + getSelectionRange(): Range; + /** * Move the cursor to the indicated position. */ @@ -152,4 +173,83 @@ export interface CoreEditor { * Get line content between and including the start and end lines provided. */ getLines(startLine: number, endLine: number): string[]; + + /** + * Replace a range in the current buffer with the provided value. + */ + replaceRange(range: Range, value: string): void; + + /** + * Return the current line count in the buffer. + */ + getLineCount(): number; + + /** + * A legacy mechanism which gives consumers of this interface a chance to wait for + * latest tokenization to complete. + */ + waitForLatestTokens(): Promise; + + /** + * Mark a range in the current buffer + */ + addMarker(range: Range): MarkerRef; + + /** + * Mark a range in the current buffer + */ + removeMarker(ref: MarkerRef): void; + + /** + * Get a number that represents the current wrap limit on a line + */ + getWrapLimit(): number; + + /** + * Register a listener for predefined editor events + */ + on(event: EditorEvent, listener: () => void): void; + + /** + * Unregister a listener for predefined editor events + */ + off(event: EditorEvent, listener: () => void): void; + + /** + * Execute a predefined editor command. + */ + execCommand(cmd: string): void; + + /** + * Returns a boolean value indicating whether or not the completer UI is currently showing in + * the editor + */ + isCompleterActive(): boolean; + + /** + * Get the HTML container element for this editor instance + */ + getContainer(): HTMLDivElement; + + /** + * Because the core editor should not know about requests, but can know about ranges we still + * have this backdoor to update UI in response to request range changes, for example, as the user + * moves the cursor around + */ + legacyUpdateUI(opts: any): void; + + /** + * A method to for the editor to resize, useful when, for instance, window size changes. + */ + resize(): void; + + /** + * Expose a way to set styles on the editor + */ + setStyles(styles: { wrapLines: boolean; fontSize: string }): void; + + /** + * Register a keyboard shortcut and provide a function to be called. + */ + registerKeyboardShortcut(opts: { keys: any; fn: () => void; name: string }): void; } diff --git a/src/legacy/core_plugins/console/np_ready/public/types/index.ts b/src/legacy/core_plugins/console/public/np_ready/types/index.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/types/index.ts rename to src/legacy/core_plugins/console/public/np_ready/types/index.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/types/token.ts b/src/legacy/core_plugins/console/public/np_ready/types/token.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/types/token.ts rename to src/legacy/core_plugins/console/public/np_ready/types/token.ts diff --git a/src/legacy/core_plugins/console/np_ready/public/types/tokens_provider.ts b/src/legacy/core_plugins/console/public/np_ready/types/tokens_provider.ts similarity index 100% rename from src/legacy/core_plugins/console/np_ready/public/types/tokens_provider.ts rename to src/legacy/core_plugins/console/public/np_ready/types/tokens_provider.ts diff --git a/src/legacy/core_plugins/console/public/quarantined/src/directives/_index.scss b/src/legacy/core_plugins/console/public/quarantined/src/directives/_index.scss deleted file mode 100644 index 56bd7ed20bda4..0000000000000 --- a/src/legacy/core_plugins/console/public/quarantined/src/directives/_index.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import './help'; -@import './history'; diff --git a/src/legacy/core_plugins/console/public/quarantined/src/input.ts b/src/legacy/core_plugins/console/public/quarantined/src/input.ts deleted file mode 100644 index eb93f8e165cb5..0000000000000 --- a/src/legacy/core_plugins/console/public/quarantined/src/input.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -// @ts-ignore -import Autocomplete from './autocomplete'; - -import { LegacyEditor } from '../../../np_ready/public/application/models'; - -// @ts-ignore -import SenseEditor from './sense_editor/editor'; -import { Position } from '../../../np_ready/public/types'; - -let input: any; -export function initializeEditor($el: JQuery, $actionsEl: JQuery) { - input = new SenseEditor($el); - - // Autocomplete should not use any Ace functionality directly - // so we build a shim here. - const editorShim = { - coreEditor: new LegacyEditor(input), - parser: input.parser, - execCommand: (cmd: string) => input.execCommand(cmd), - getCursorPosition: (): Position | null => { - if (input.selection && input.selection.lead) { - return { - lineNumber: input.selection.lead.row + 1, - column: input.selection.lead.column + 1, - }; - } - return null; - }, - isCompleterActive: () => { - return Boolean(input.__ace.completer && input.__ace.completer.activated); - }, - addChangeListener: (fn: any) => input.on('changeSelection', fn), - removeChangeListener: (fn: any) => input.off('changeSelection', fn), - }; - - input.autocomplete = new (Autocomplete as any)(editorShim); - input.setOptions({ - enableBasicAutocompletion: true, - }); - input.$blockScrolling = Infinity; - input.$actions = $actionsEl; - - /** - * Init the editor - */ - input.focus(); - input.highlightCurrentRequestsAndUpdateActionBar(); - - return input; -} - -// eslint-disable-next-line -export default function getInput() { - return input; -} diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/editor.js b/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/editor.js deleted file mode 100644 index 9c34860df35ff..0000000000000 --- a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/editor.js +++ /dev/null @@ -1,676 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -const _ = require('lodash'); -const ace = require('brace'); -const $ = require('jquery'); -const curl = require('../curl'); -const RowParser = require('./row_parser'); -const InputMode = require('./mode/input'); -const utils = require('../utils'); -const es = require('../es'); -const chrome = require('ui/chrome'); - -const smartResize = require('../smart_resize'); - -function createInstance($el) { - const aceEditor = ace.edit($el[0]); - - // we must create a custom class for each instance, so that the prototype - // can be the unique aceEditor it extends - const CustomSenseEditor = function () { - }; - CustomSenseEditor.prototype = {}; - - function bindProp(key) { - Object.defineProperty(CustomSenseEditor.prototype, key, { - get: function () { - return aceEditor[key]; - }, - set: function (val) { - aceEditor[key] = val; - } - }); - } - - // iterate all of the accessible properties/method, on the prototype and beyond - // eslint-disable-next-line guard-for-in - for (const key in aceEditor) { - switch (typeof aceEditor[key]) { - case 'function': - CustomSenseEditor.prototype[key] = _.bindKey(aceEditor, key); - break; - default: - bindProp(key); - break; - } - } - - const editor = new CustomSenseEditor(); - editor.__ace = aceEditor; - return editor; -} - -export default function SenseEditor($el) { - const editor = createInstance($el); - let CURRENT_REQ_RANGE = null; - - editor.$el = $el; - // place holder for an action bar, needs to be set externally. - editor.$actions = null; - - // mixin the RowParser - editor.parser = new RowParser(editor); - editor.resize = smartResize(editor); - - // dirty check for tokenizer state, uses a lot less cycles - // than listening for tokenizerUpdate - const onceDoneTokenizing = function (callback, cancelAlreadyScheduledCalls) { - const session = editor.getSession(); - let timer = false; - const checkInterval = 25; - - return function () { - const self = this; - const args = [].slice.call(arguments, 0); - - if (cancelAlreadyScheduledCalls) { - timer = clearTimeout(timer); - } - - setTimeout(function check() { - // If the bgTokenizer doesn't exist, we can assume that the underlying editor has been - // torn down, e.g. by closing the History tab, and we don't need to do anything further. - if (session.bgTokenizer) { - // Wait until the bgTokenizer is done running before executing the callback. - if (session.bgTokenizer.running) { - timer = setTimeout(check, checkInterval); - } else { - callback.apply(self, args); - } - } - }); - }; - }; - - editor.setShowPrintMargin(false); - (function (session) { - session.setMode(new InputMode.Mode()); - session.setFoldStyle('markbeginend'); - session.setTabSize(2); - session.setUseWrapMode(true); - }(editor.getSession())); - - editor.prevRequestStart = function (rowOrPos) { - rowOrPos = _.isUndefined(rowOrPos) || rowOrPos === null ? editor.getCursorPosition() : rowOrPos; - - let curRow = _.isObject(rowOrPos) ? rowOrPos.row : rowOrPos; - while (curRow > 0 && !editor.parser.isStartRequestRow(curRow, editor)) curRow--; - - return { - row: curRow, - column: 0 - }; - }; - - editor.nextRequestStart = function (rowOrPos) { - rowOrPos = _.isUndefined(rowOrPos) || rowOrPos === null ? editor.getCursorPosition() : rowOrPos; - const session = editor.getSession(); - let curRow = _.isObject(rowOrPos) ? rowOrPos.row : rowOrPos; - const maxLines = session.getLength(); - for (; curRow < maxLines - 1; curRow++) { - if (editor.parser.isStartRequestRow(curRow, editor)) { - break; - } - } - return { - row: curRow, - column: 0 - }; - }; - - editor.autoIndent = onceDoneTokenizing(function () { - editor.getRequestRange(function (reqRange) { - if (!reqRange) { - return; - } - editor.getRequest(function (parsedReq) { - if (parsedReq.data && parsedReq.data.length > 0) { - let indent = parsedReq.data.length === 1; // unindent multi docs by default - let formattedData = utils.reformatData(parsedReq.data, indent); - if (!formattedData.changed) { - // toggle. - indent = !indent; - formattedData = utils.reformatData(parsedReq.data, indent); - } - parsedReq.data = formattedData.data; - - editor.replaceRequestRange(parsedReq, reqRange); - } - }); - }); - }, true); - - editor.update = function (data, callback) { - callback = typeof callback === 'function' ? callback : null; - const session = editor.getSession(); - - session.setValue(data); - if (callback) { - // force update of tokens, but not on this thread to allow for ace rendering. - setTimeout(function () { - let i; - for (i = 0; i < session.getLength(); i++) { - session.getTokens(i); - } - callback(); - }); - } - - }; - - editor.replaceRequestRange = function (newRequest, requestRange) { - const text = utils.textFromRequest(newRequest); - if (requestRange) { - const pos = editor.getCursorPosition(); - editor.getSession().replace(requestRange, text); - const maxRow = Math.max(requestRange.start.row + text.split('\n').length - 1, 0); - pos.row = Math.min(pos.row, maxRow); - editor.moveCursorToPosition(pos); - // ACE UPGRADE - check if needed - at the moment the above may trigger a selection. - editor.clearSelection(); - } - else { - // just insert where we are - editor.insert(text); - } - }; - - editor.iterForCurrentLoc = function () { - const pos = editor.getCursorPosition(); - return editor.iterForPosition(pos.row, pos.column, editor); - }; - - editor.iterForPosition = function (row, column) { - return new (ace.acequire('ace/token_iterator').TokenIterator)(editor.getSession(), row, column); - }; - - editor.getRequestRange = onceDoneTokenizing(function (row, cb) { - if (_.isUndefined(cb)) { - cb = row; - row = null; - } - if (typeof cb !== 'function') { - return; - } - - if (editor.parser.isInBetweenRequestsRow(row)) { - cb(null); - return; - } - - const reqStart = editor.prevRequestStart(row, editor); - const reqEnd = editor.nextRequestEnd(reqStart, editor); - cb(new (ace.acequire('ace/range').Range)( - reqStart.row, reqStart.column, - reqEnd.row, reqEnd.column - )); - }); - - editor.getEngulfingRequestsRange = onceDoneTokenizing(function (range, cb) { - if (_.isUndefined(cb)) { - cb = range; - range = null; - } - - range = range || editor.getSelectionRange(); - - const session = editor.getSession(); - let startRow = range.start.row; - let endRow = range.end.row; - const maxLine = Math.max(0, session.getLength() - 1); - - // move start row to the previous request start if in body, o.w. forward - if (editor.parser.isInBetweenRequestsRow(startRow)) { - //for (; startRow <= endRow; startRow++) { - // if (editor.parser.isStartRequestRow(startRow)) { - // break; - // } - //} - } - else { - for (; startRow >= 0; startRow--) { - if (editor.parser.isStartRequestRow(startRow)) { - break; - } - } - } - - if (startRow < 0 || startRow > endRow) { - cb(null); - return; - } - // move end row to the previous request end if between requests, o.w. walk forward - if (editor.parser.isInBetweenRequestsRow(endRow)) { - for (; endRow >= startRow; endRow--) { - if (editor.parser.isEndRequestRow(endRow)) { - break; - } - } - } - else { - - for (; endRow <= maxLine; endRow++) { - if (editor.parser.isEndRequestRow(endRow)) { - break; - } - } - - } - - if (endRow < startRow || endRow > maxLine) { - cb(null); - return; - } - - const endColumn = (session.getLine(endRow) || '').replace(/\s+$/, '').length; - cb(new (ace.acequire('ace/range').Range)(startRow, 0, endRow, endColumn)); - }); - - - editor.getRequestInRange = onceDoneTokenizing(function (range, cb) { - if (!range) { - return; - } - const request = { - method: '', - data: [], - url: null, - range: range - }; - - const pos = range.start; - const tokenIter = editor.iterForPosition(pos.row, pos.column, editor); - let t = tokenIter.getCurrentToken(); - if (editor.parser.isEmptyToken(t)) { - // if the row starts with some spaces, skip them. - t = editor.parser.nextNonEmptyToken(tokenIter); - } - request.method = t.value; - t = editor.parser.nextNonEmptyToken(tokenIter); - if (!t || t.type === 'method') { - return null; - } - request.url = ''; - while (t && t.type && t.type.indexOf('url') === 0) { - request.url += t.value; - t = tokenIter.stepForward(); - } - if (editor.parser.isEmptyToken(t)) { - // if the url row ends with some spaces, skip them. - t = editor.parser.nextNonEmptyToken(tokenIter); - } - - let bodyStartRow = (t ? 0 : 1) + tokenIter.getCurrentTokenRow(); // artificially increase end of docs. - let dataEndPos; - while (bodyStartRow < range.end.row || ( - bodyStartRow === range.end.row && 0 < range.end.column - )) { - dataEndPos = editor.nextDataDocEnd({ - row: bodyStartRow, - column: 0 - }); - const bodyRange = new (ace.acequire('ace/range').Range)( - bodyStartRow, 0, - dataEndPos.row, dataEndPos.column - ); - const data = editor.getSession().getTextRange(bodyRange); - request.data.push(data.trim()); - bodyStartRow = dataEndPos.row + 1; - } - - cb(request); - }); - - editor.getRequestsInRange = function (range, includeNonRequestBlocks, cb) { - if (_.isUndefined(includeNonRequestBlocks)) { - includeNonRequestBlocks = false; - cb = range; - range = null; - } else if (_.isUndefined(cb)) { - cb = includeNonRequestBlocks; - includeNonRequestBlocks = false; - } - - function explicitRangeToRequests(requestsRange, tempCb) { - if (!requestsRange) { - tempCb([]); - return; - } - - const startRow = requestsRange.start.row; - const endRow = requestsRange.end.row; - - // move to the next request start (during the second iterations this may not be exactly on a request - let currentRow = startRow; - for (; currentRow <= endRow; currentRow++) { - if (editor.parser.isStartRequestRow(currentRow)) { - break; - } - } - - let nonRequestPrefixBlock = null; - if (includeNonRequestBlocks && currentRow !== startRow) { - nonRequestPrefixBlock = editor.getSession().getLines(startRow, currentRow - 1).join('\n'); - } - - if (currentRow > endRow) { - tempCb(nonRequestPrefixBlock ? [nonRequestPrefixBlock] : []); - return; - } - - editor.getRequest(currentRow, function (request) { - if (!request) { - return; - } - explicitRangeToRequests({ - start: { - row: request.range.end.row + 1 - }, - end: { - row: requestsRange.end.row - } - }, - function (restOfRequests) { - restOfRequests.unshift(request); - if (nonRequestPrefixBlock !== null) { - restOfRequests.unshift(nonRequestPrefixBlock); - } - tempCb(restOfRequests); - } - ); - }); - } - - editor.getEngulfingRequestsRange(range, function (requestRange) { - explicitRangeToRequests(requestRange, cb); - }); - }; - - editor.getRequest = onceDoneTokenizing(function (row, cb) { - if (_.isUndefined(cb)) { - cb = row; - row = null; - } - if (typeof cb !== 'function') { - return; - } - if (editor.parser.isInBetweenRequestsRow(row)) { - cb(null); - return; - } - editor.getRequestRange(row, function (range) { - editor.getRequestInRange(range, cb); - }); - }); - - editor.moveToPreviousRequestEdge = onceDoneTokenizing(function () { - const pos = editor.getCursorPosition(); - for (pos.row--; pos.row > 0 && !editor.parser.isRequestEdge(pos.row); pos.row--) { - // loop for side effects - } - editor.moveCursorTo(pos.row, 0); - }); - - editor.moveToNextRequestEdge = onceDoneTokenizing(function (moveOnlyIfNotOnEdge) { - const pos = editor.getCursorPosition(); - const maxRow = editor.getSession().getLength(); - if (!moveOnlyIfNotOnEdge) { - pos.row++; - } - for (; pos.row < maxRow && !editor.parser.isRequestEdge(pos.row); pos.row++) { - // loop for side effects - } - editor.moveCursorTo(pos.row, 0); - }); - - editor.nextRequestEnd = function (pos) { - pos = pos || editor.getCursorPosition(); - const session = editor.getSession(); - let curRow = pos.row; - const maxLines = session.getLength(); - for (; curRow < maxLines - 1; curRow++) { - const curRowMode = editor.parser.getRowParseMode(curRow, editor); - if ((curRowMode & editor.parser.MODE.REQUEST_END) > 0) { - break; - } - if (curRow !== pos.row && (curRowMode & editor.parser.MODE.REQUEST_START) > 0) { - break; - } - } - - const column = (session.getLine(curRow) || '').replace(/\s+$/, '').length; - - return { - row: curRow, - column: column - }; - }; - - editor.nextDataDocEnd = function (pos) { - pos = pos || editor.getCursorPosition(); - const session = editor.getSession(); - let curRow = pos.row; - const maxLines = session.getLength(); - for (; curRow < maxLines - 1; curRow++) { - const curRowMode = editor.parser.getRowParseMode(curRow, editor); - if ((curRowMode & RowParser.REQUEST_END) > 0) { - break; - } - if ((curRowMode & editor.parser.MODE.MULTI_DOC_CUR_DOC_END) > 0) { - break; - } - if (curRow !== pos.row && (curRowMode & editor.parser.MODE.REQUEST_START) > 0) { - break; - } - } - - const column = (session.getLine(curRow) || '').length; - - return { - row: curRow, - column: column - }; - }; - - // overwrite the actual aceEditor's onPaste method - const origOnPaste = editor.__ace.onPaste; - editor.__ace.onPaste = function (text) { - if (text && curl.detectCURL(text)) { - editor.handleCURLPaste(text); - return; - } - origOnPaste.call(this, text); - }; - - editor.handleCURLPaste = function (text) { - const curlInput = curl.parseCURL(text); - - editor.insert(curlInput); - }; - - editor.highlightCurrentRequestsAndUpdateActionBar = onceDoneTokenizing(function () { - const session = editor.getSession(); - editor.getEngulfingRequestsRange(function (newCurrentReqRange) { - if (newCurrentReqRange === null && CURRENT_REQ_RANGE === null) { - return; - } - if (newCurrentReqRange !== null && CURRENT_REQ_RANGE !== null && - newCurrentReqRange.start.row === CURRENT_REQ_RANGE.start.row && - newCurrentReqRange.end.row === CURRENT_REQ_RANGE.end.row - ) { - // same request, now see if we are on the first line and update the action bar - const cursorRow = editor.getCursorPosition().row; - if (cursorRow === CURRENT_REQ_RANGE.start.row) { - editor.updateActionsBar(); - } - return; // nothing to do.. - } - - if (CURRENT_REQ_RANGE) { - session.removeMarker(CURRENT_REQ_RANGE.marker_id); - } - - CURRENT_REQ_RANGE = newCurrentReqRange; - if (CURRENT_REQ_RANGE) { - CURRENT_REQ_RANGE.marker_id = session.addMarker(CURRENT_REQ_RANGE, 'ace_snippet-marker', 'fullLine'); - } - editor.updateActionsBar(); - }); - }, true); - - editor.getRequestsAsCURL = function (range, cb) { - if (_.isUndefined(cb)) { - cb = range; - range = null; - } - - if (_.isUndefined(cb)) { - cb = $.noop; - } - - editor.getRequestsInRange(range, true, function (requests) { - - const result = _.map(requests, function requestToCurl(req) { - - if (typeof req === 'string') { - // no request block - return req; - } - - const esPath = req.url; - const esMethod = req.method; - const esData = req.data; - - // this is the first url defined in elasticsearch.hosts - const elasticsearchBaseUrl = chrome.getInjected('elasticsearchUrl'); - const url = es.constructESUrl(elasticsearchBaseUrl, esPath); - - let ret = 'curl -X' + esMethod + ' "' + url + '"'; - if (esData && esData.length) { - ret += ' -H \'Content-Type: application/json\' -d\'\n'; - const dataAsString = utils.collapseLiteralStrings(esData.join('\n')); - // since Sense doesn't allow single quote json string any single qoute is within a string. - ret += dataAsString.replace(/'/g, '\\"'); - if (esData.length > 1) { - ret += '\n'; - } // end with a new line - ret += '\''; - } - return ret; - }); - - cb(result.join('\n')); - }); - }; - - editor.getSession().on('tokenizerUpdate', function () { - editor.highlightCurrentRequestsAndUpdateActionBar(); - }); - - editor.getSession().selection.on('changeCursor', function () { - editor.highlightCurrentRequestsAndUpdateActionBar(); - }); - - editor.updateActionsBar = (function () { - const set = function (top) { - if (top === null) { - editor.$actions.css('visibility', 'hidden'); - } - else { - editor.$actions.css({ - top: top, - visibility: 'visible' - }); - } - }; - - const hide = function () { - set(); - }; - - return function () { - if (!editor.$actions) { - return; - } - if (CURRENT_REQ_RANGE) { - // elements are positioned relative to the editor's container - // pageY is relative to page, so subtract the offset - // from pageY to get the new top value - const offsetFromPage = editor.$el.offset().top; - const startRow = CURRENT_REQ_RANGE.start.row; - const startColumn = CURRENT_REQ_RANGE.start.column; - const session = editor.session; - const firstLine = session.getLine(startRow); - const maxLineLength = session.getWrapLimit() - 5; - const isWrapping = firstLine.length > maxLineLength; - const getScreenCoords = (row) => editor.renderer.textToScreenCoordinates(row, startColumn).pageY - offsetFromPage; - const topOfReq = getScreenCoords(startRow); - - if (topOfReq >= 0) { - let offset = 0; - if (isWrapping) { - // Try get the line height of the text area in pixels. - const textArea = editor.$el.find('textArea'); - const hasRoomOnNextLine = session.getLine(startRow + 1).length < maxLineLength; - if (textArea && hasRoomOnNextLine) { - // Line height + the number of wraps we have on a line. - offset += (session.getRowLength(startRow) * textArea.height()); - } else { - if (startRow > 0) { - set(getScreenCoords(startRow - 1, startColumn)); - return; - } - set(getScreenCoords(startRow + 1, startColumn)); - return; - } - } - set(topOfReq + offset); - return; - } - - const bottomOfReq = editor.renderer.textToScreenCoordinates( - CURRENT_REQ_RANGE.end.row, - CURRENT_REQ_RANGE.end.column - ).pageY - offsetFromPage; - - if (bottomOfReq >= 0) { - set(0); - return; - } - } - - hide(); - }; - }()); - - editor.getSession().on('changeScrollTop', editor.updateActionsBar); - - return editor; -} diff --git a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/row_parser.js b/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/row_parser.js deleted file mode 100644 index c1bba107de784..0000000000000 --- a/src/legacy/core_plugins/console/public/quarantined/src/sense_editor/row_parser.js +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -const MODE = { - REQUEST_START: 2, - IN_REQUEST: 4, - MULTI_DOC_CUR_DOC_END: 8, - REQUEST_END: 16, - BETWEEN_REQUESTS: 32 -}; - -/** - * The RowParser is still using Ace editor directly for now. - * - * This will be cleaned up when we implement the editor interface everywhere - * in the next pass. - */ -function RowParser(editor) { - const defaultEditor = editor; - - this.getRowParseMode = function (row) { - if (row === null || typeof row === 'undefined') { - row = editor.getCursorPosition().row; - } - - const session = editor.getSession(); - if (row >= session.getLength() || row < 0) { - return MODE.BETWEEN_REQUESTS; - } - const mode = session.getState(row); - if (!mode) { - return MODE.BETWEEN_REQUESTS; - } // shouldn't really happen - - if (mode !== 'start') { - return MODE.IN_REQUEST; - } - let line = (session.getLine(row) || '').trim(); - if (!line || line[0] === '#') { - return MODE.BETWEEN_REQUESTS; - } // empty line or a comment waiting for a new req to start - - if (line.indexOf('}', line.length - 1) >= 0) { - // check for a multi doc request (must start a new json doc immediately after this one end. - row++; - if (row < session.getLength()) { - line = (session.getLine(row) || '').trim(); - if (line.indexOf('{') === 0) { // next line is another doc in a multi doc - return MODE.MULTI_DOC_CUR_DOC_END | MODE.IN_REQUEST; - } - - } - return MODE.REQUEST_END | MODE.MULTI_DOC_CUR_DOC_END; // end of request - } - - // check for single line requests - row++; - if (row >= session.getLength()) { - return MODE.REQUEST_START | MODE.REQUEST_END; - } - line = (session.getLine(row) || '').trim(); - if (line.indexOf('{') !== 0) { // next line is another request - return MODE.REQUEST_START | MODE.REQUEST_END; - } - - return MODE.REQUEST_START; - }; - - this.rowPredicate = function (row, editor, value) { - const mode = this.getRowParseMode(row, editor); - return (mode & value) > 0; - }; - - this.isEndRequestRow = function (row, _e) { - const editor = _e || defaultEditor; - return this.rowPredicate(row, editor, MODE.REQUEST_END); - }; - - this.isRequestEdge = function (row, _e) { - const editor = _e || defaultEditor; - return this.rowPredicate(row, editor, MODE.REQUEST_END | MODE.REQUEST_START); - }; - - this.isStartRequestRow = function (row, _e) { - const editor = _e || defaultEditor; - return this.rowPredicate(row, editor, MODE.REQUEST_START); - }; - - this.isInBetweenRequestsRow = function (row, _e) { - const editor = _e || defaultEditor; - return this.rowPredicate(row, editor, MODE.BETWEEN_REQUESTS); - }; - - this.isInRequestsRow = function (row, _e) { - const editor = _e || defaultEditor; - return this.rowPredicate(row, editor, MODE.IN_REQUEST); - }; - - this.isMultiDocDocEndRow = function (row, _e) { - const editor = _e || defaultEditor; - return this.rowPredicate(row, editor, MODE.MULTI_DOC_CUR_DOC_END); - }; - - this.isEmptyToken = function (tokenOrTokenIter) { - const token = tokenOrTokenIter && tokenOrTokenIter.getCurrentToken ? tokenOrTokenIter.getCurrentToken() : tokenOrTokenIter; - return !token || token.type === 'whitespace'; - }; - - this.isUrlOrMethodToken = function (tokenOrTokenIter) { - const t = tokenOrTokenIter.getCurrentToken ? tokenOrTokenIter.getCurrentToken() : tokenOrTokenIter; - return t && t.type && (t.type === 'method' || t.type.indexOf('url') === 0); - }; - - - this.nextNonEmptyToken = function (tokenIter) { - let t = tokenIter.stepForward(); - while (t && this.isEmptyToken(t)) t = tokenIter.stepForward(); - return t; - }; - - this.prevNonEmptyToken = function (tokenIter) { - let t = tokenIter.stepBackward(); - // empty rows return null token. - while ((t || tokenIter.getCurrentPosition().lineNumber > 1) && this.isEmptyToken(t)) t = tokenIter.stepBackward(); - return t; - }; -} - -RowParser.prototype.MODE = MODE; - -export default RowParser;