From 3521a928d57adf531ac8331ed1008ac8e5e46ce8 Mon Sep 17 00:00:00 2001 From: Joe Portner <5295965+jportner@users.noreply.github.com> Date: Fri, 3 Dec 2021 14:56:01 -0500 Subject: [PATCH 01/25] More descriptive audit integration test errors (#120354) --- .../security_api_integration/tests/audit/audit_log.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/x-pack/test/security_api_integration/tests/audit/audit_log.ts b/x-pack/test/security_api_integration/tests/audit/audit_log.ts index fd7db8faadd54..bb4c27976c857 100644 --- a/x-pack/test/security_api_integration/tests/audit/audit_log.ts +++ b/x-pack/test/security_api_integration/tests/audit/audit_log.ts @@ -22,7 +22,14 @@ class FileWrapper { } async readJSON() { const content = await this.read(); - return content.map((l) => JSON.parse(l)); + try { + return content.map((l) => JSON.parse(l)); + } catch (err) { + const contentString = content.join('\n'); + throw new Error( + `Failed to parse audit log JSON, error: "${err.message}", audit.log contents:\n${contentString}` + ); + } } // writing in a file is an async operation. we use this method to make sure logs have been written. async isNotEmpty() { From b5895ec0b441befa5d0a4ada2ac602efd5ffe386 Mon Sep 17 00:00:00 2001 From: ymao1 Date: Fri, 3 Dec 2021 15:05:24 -0500 Subject: [PATCH 02/25] [Alerting] Skip writing alerts when rule execution times out (#114518) * Added cancel() to alerting task runner and writing event log document * Updating rule saved object with timeout execution status * Skip scheduling actions and logging event log for alerts if rule execution is cancelled * Adding config for disabling skipping actions * Fixing types * Adding flag for rule types to opt out of skipping acitons * Passing function into rule executor to determine whether to write AAD * Using task runner uuid to differentiate between task instances * Adding functional test * Fixing types * Updating service function name and adding logic to persistence rule type Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/alerting/server/mocks.ts | 1 + .../server/task_runner/task_runner.ts | 1 + x-pack/plugins/alerting/server/types.ts | 1 + .../server/routes/alerts/test_utils/index.ts | 1 + .../utils/create_lifecycle_executor.test.ts | 27 +++++++++++++++++++ .../server/utils/create_lifecycle_executor.ts | 14 +++++++--- .../utils/create_lifecycle_rule_type.test.ts | 23 +++++++++++++++- .../create_persistence_rule_type_wrapper.ts | 11 +++++++- .../server/utils/rule_executor_test_utils.ts | 3 +++ .../routes/rules/preview_rules_route.ts | 3 +++ .../rule_types/__mocks__/rule_type.ts | 1 + 11 files changed, 81 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/alerting/server/mocks.ts b/x-pack/plugins/alerting/server/mocks.ts index 7fb748a305037..f23dbf05449ad 100644 --- a/x-pack/plugins/alerting/server/mocks.ts +++ b/x-pack/plugins/alerting/server/mocks.ts @@ -74,6 +74,7 @@ const createAlertServicesMock = < .mockReturnValue(alertInstanceFactoryMock), savedObjectsClient: savedObjectsClientMock.create(), scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), + shouldWriteAlerts: () => true, }; }; export type AlertServicesMock = ReturnType; diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.ts index fb7268ef529da..0cf5202787392 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.ts @@ -323,6 +323,7 @@ export class TaskRunner< InstanceContext, WithoutReservedActionGroups >(alertInstances), + shouldWriteAlerts: () => this.shouldLogAndScheduleActionsForAlerts(), }, params, state: alertTypeState as State, diff --git a/x-pack/plugins/alerting/server/types.ts b/x-pack/plugins/alerting/server/types.ts index c1645936c06e9..343b717dcb1aa 100644 --- a/x-pack/plugins/alerting/server/types.ts +++ b/x-pack/plugins/alerting/server/types.ts @@ -75,6 +75,7 @@ export interface AlertServices< alertInstanceFactory: ( id: string ) => PublicAlertInstance; + shouldWriteAlerts: () => boolean; } export interface AlertExecutorOptions< diff --git a/x-pack/plugins/apm/server/routes/alerts/test_utils/index.ts b/x-pack/plugins/apm/server/routes/alerts/test_utils/index.ts index 22649a7010461..a8610bbcc8d37 100644 --- a/x-pack/plugins/apm/server/routes/alerts/test_utils/index.ts +++ b/x-pack/plugins/apm/server/routes/alerts/test_utils/index.ts @@ -45,6 +45,7 @@ export const createRuleTypeMocks = () => { alertInstanceFactory: jest.fn(() => ({ scheduleActions })), alertWithLifecycle: jest.fn(), logger: loggerMock, + shouldWriteAlerts: () => true, }; return { diff --git a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.test.ts b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.test.ts index fcddcab378bc6..2c5fe09d80563 100644 --- a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.test.ts +++ b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.test.ts @@ -350,6 +350,33 @@ describe('createLifecycleExecutor', () => { }) ); }); + + it('does not write alert documents when rule execution is cancelled and feature flags indicate to skip', async () => { + const logger = loggerMock.create(); + const ruleDataClientMock = createRuleDataClientMock(); + const executor = createLifecycleExecutor( + logger, + ruleDataClientMock + )<{}, TestRuleState, never, never, never>(async (options) => { + expect(options.state).toEqual(initialRuleState); + + const nextRuleState: TestRuleState = { + aRuleStateKey: 'NEXT_RULE_STATE_VALUE', + }; + + return nextRuleState; + }); + + await executor( + createDefaultAlertExecutorOptions({ + params: {}, + state: { wrapped: initialRuleState, trackedAlerts: {} }, + shouldWriteAlerts: false, + }) + ); + + expect(ruleDataClientMock.getWriter).not.toHaveBeenCalled(); + }); }); type TestRuleState = Record & { diff --git a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts index 1acbc0c3f43bd..c30b1654a3587 100644 --- a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts +++ b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts @@ -140,7 +140,7 @@ export const createLifecycleExecutor = > ): Promise> => { const { - services: { alertInstanceFactory }, + services: { alertInstanceFactory, shouldWriteAlerts }, state: previousState, } = options; @@ -281,7 +281,15 @@ export const createLifecycleExecutor = const newEventsToIndex = makeEventsDataMapFor(newAlertIds); const allEventsToIndex = [...trackedEventsToIndex, ...newEventsToIndex]; - if (allEventsToIndex.length > 0 && ruleDataClient.isWriteEnabled()) { + // Only write alerts if: + // - writing is enabled + // AND + // - rule execution has not been cancelled due to timeout + // OR + // - if execution has been cancelled due to timeout, if feature flags are configured to write alerts anyway + const writeAlerts = ruleDataClient.isWriteEnabled() && shouldWriteAlerts(); + + if (allEventsToIndex.length > 0 && writeAlerts) { logger.debug(`Preparing to index ${allEventsToIndex.length} alerts.`); await ruleDataClient.getWriter().bulk({ @@ -307,6 +315,6 @@ export const createLifecycleExecutor = return { wrapped: nextWrappedState ?? ({} as State), - trackedAlerts: ruleDataClient.isWriteEnabled() ? nextTrackedAlerts : {}, + trackedAlerts: writeAlerts ? nextTrackedAlerts : {}, }; }; diff --git a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts index 2284ad5e796ee..f0e2412629bb1 100644 --- a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts +++ b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts @@ -21,7 +21,7 @@ import { createLifecycleRuleTypeFactory } from './create_lifecycle_rule_type_fac type RuleTestHelpers = ReturnType; -function createRule() { +function createRule(shouldWriteAlerts: boolean = true) { const ruleDataClientMock = createRuleDataClientMock(); const factory = createLifecycleRuleTypeFactory({ @@ -110,6 +110,7 @@ function createRule() { alertInstanceFactory, savedObjectsClient: {} as any, scopedClusterClient: {} as any, + shouldWriteAlerts: () => shouldWriteAlerts, }, spaceId: 'spaceId', state, @@ -152,6 +153,26 @@ describe('createLifecycleRuleTypeFactory', () => { }); }); + describe('when rule is cancelled due to timeout and config flags indicate to skip actions', () => { + beforeEach(() => { + helpers = createRule(false); + helpers.ruleDataClientMock.isWriteEnabled.mockReturnValue(true); + }); + + it("doesn't persist anything", async () => { + await helpers.alertWithLifecycle([ + { + id: 'opbeans-java', + fields: { + 'service.name': 'opbeans-java', + }, + }, + ]); + + expect(helpers.ruleDataClientMock.getWriter().bulk).toHaveBeenCalledTimes(0); + }); + }); + describe('when alerts are new', () => { beforeEach(async () => { await helpers.alertWithLifecycle([ diff --git a/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts b/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts index afdcf856a872f..de1193771dd95 100644 --- a/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts +++ b/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts @@ -25,7 +25,16 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper const numAlerts = alerts.length; logger.debug(`Found ${numAlerts} alerts.`); - if (ruleDataClient.isWriteEnabled() && numAlerts) { + // Only write alerts if: + // - writing is enabled + // AND + // - rule execution has not been cancelled due to timeout + // OR + // - if execution has been cancelled due to timeout, if feature flags are configured to write alerts anyway + const writeAlerts = + ruleDataClient.isWriteEnabled() && options.services.shouldWriteAlerts(); + + if (writeAlerts && numAlerts) { const commonRuleFields = getCommonAlertFields(options); const CHUNK_SIZE = 10000; diff --git a/x-pack/plugins/rule_registry/server/utils/rule_executor_test_utils.ts b/x-pack/plugins/rule_registry/server/utils/rule_executor_test_utils.ts index 95a6761152371..288830f4b3804 100644 --- a/x-pack/plugins/rule_registry/server/utils/rule_executor_test_utils.ts +++ b/x-pack/plugins/rule_registry/server/utils/rule_executor_test_utils.ts @@ -31,6 +31,7 @@ export const createDefaultAlertExecutorOptions = < createdAt = new Date(), startedAt = new Date(), updatedAt = new Date(), + shouldWriteAlerts = true, }: { alertId?: string; ruleName?: string; @@ -39,6 +40,7 @@ export const createDefaultAlertExecutorOptions = < createdAt?: Date; startedAt?: Date; updatedAt?: Date; + shouldWriteAlerts?: boolean; }): AlertExecutorOptions => ({ alertId, createdBy: 'CREATED_BY', @@ -69,6 +71,7 @@ export const createDefaultAlertExecutorOptions = < .alertInstanceFactory, savedObjectsClient: savedObjectsClientMock.create(), scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), + shouldWriteAlerts: () => shouldWriteAlerts, }, state, updatedBy: null, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts index 882732544dcbb..3949e71582020 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts @@ -122,6 +122,7 @@ export const previewRulesRoute = async ( ruleTypeId: string, ruleTypeName: string, params: TParams, + shouldWriteAlerts: () => boolean, alertInstanceFactory: ( id: string ) => Pick< @@ -157,6 +158,7 @@ export const previewRulesRoute = async ( previousStartedAt, rule, services: { + shouldWriteAlerts, alertInstanceFactory, savedObjectsClient: context.core.savedObjects.client, scopedClusterClient: context.core.elasticsearch.client, @@ -191,6 +193,7 @@ export const previewRulesRoute = async ( signalRuleAlertType.id, signalRuleAlertType.name, previewRuleParams, + () => true, alertInstanceFactoryStub ); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule_type.ts index c6f818f04fc5d..aaab81a4c66ff 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule_type.ts @@ -78,6 +78,7 @@ export const createRuleTypeMocks = ( findAlerts: jest.fn(), // TODO: does this stay? alertWithPersistence: jest.fn(), logger: loggerMock, + shouldWriteAlerts: () => true, }; return { From dbde0a75f92303b525d7845735085d08329006a1 Mon Sep 17 00:00:00 2001 From: Stacey Gammon Date: Fri, 3 Dec 2021 15:43:32 -0500 Subject: [PATCH 03/25] Update performance docs to touch on server-side considerations (#120356) * Update performance docs to touch on server-side considerations * update edited date --- dev_docs/key_concepts/performance.mdx | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/dev_docs/key_concepts/performance.mdx b/dev_docs/key_concepts/performance.mdx index 0201c7774f854..5d955c789ddeb 100644 --- a/dev_docs/key_concepts/performance.mdx +++ b/dev_docs/key_concepts/performance.mdx @@ -3,11 +3,13 @@ id: kibDevPerformance slug: /kibana-dev-docs/key-concepts/performance title: Performance summary: Performance tips for Kibana development. -date: 2021-09-02 +date: 2021-12-03 tags: ['kibana', 'onboarding', 'dev', 'performance'] --- -## Keep Kibana fast +## Client-side considerations + +### Lazy load code _tl;dr_: Load as much code lazily as possible. Everyone loves snappy applications with a responsive UI and hates spinners. Users deserve the @@ -105,3 +107,15 @@ Many OSS tools allow you to analyze the generated stats file: Webpack authors - [webpack-visualizer](https://chrisbateman.github.io/webpack-visualizer/) - [webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) + +## Server-side considerations + +### Don't block the event loop + +[Node.js is single threaded](https://nodejs.dev/learn/introduction-to-nodejs) which means a single CPU-intensive server-side, synchronous operation will block any other functionality waiting to execute on the Kibana server. The affects background tasks, like alerts, and search sessions, as well as search requests and page loads. + +**When writing code that will run on the server, [don't block the event loop](https://nodejs.org/en/docs/guides/dont-block-the-event-loop/)**. Instead consider: + +- Writing async code. For example, leverage [setImmediate](https://nodejs.dev/learn/understanding-setimmediate) inside for loops. +- Executing logic on the client instead. This may not be a good option if you require a lot of data going back and forth between the server and the client, as that can also slow down the user's experience, especially over slower bandwidth internet connections. +- Worker threads are also an option if the code doesn't rely on stateful Kibana services. If you are interested in using worker threads, please reach out to a tech-lead before doing so. We will likely want to implement a worker threads pool to ensure worker threads cooperate appropriately. \ No newline at end of file From d21d721bd1104a3e231baa5775fcc6749423aafa Mon Sep 17 00:00:00 2001 From: Clint Andrew Hall Date: Fri, 3 Dec 2021 12:44:50 -0800 Subject: [PATCH 04/25] [presentation] Create Expression Input (#119411) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- src/plugins/presentation_util/common/index.ts | 6 + src/plugins/presentation_util/kibana.json | 13 +- .../expression_input}/autocomplete.ts | 24 +- .../components/expression_input/constants.ts | 28 ++ .../expression_input.stories.tsx | 94 +++++ .../expression_input/expression_input.tsx | 82 +++++ .../components/expression_input/index.tsx | 16 + .../components/expression_input/language.ts | 23 +- .../components/expression_input/providers.ts | 189 ++++++++++ .../components/expression_input/reference.ts | 24 +- .../public/components/index.tsx | 5 + .../public/components/types.ts | 43 +++ src/plugins/presentation_util/public/index.ts | 19 +- src/plugins/presentation_util/public/mocks.ts | 2 + .../presentation_util/public/plugin.ts | 3 + .../public/services/index.ts | 3 + src/plugins/presentation_util/public/types.ts | 2 + .../presentation_util/storybook/decorator.tsx | 20 +- .../presentation_util/storybook/main.ts | 4 +- .../presentation_util/storybook/manager.ts | 5 + .../canvas/common/lib/autocomplete.test.ts | 198 ---------- x-pack/plugins/canvas/common/lib/index.ts | 1 - x-pack/plugins/canvas/public/application.tsx | 3 - .../components/expression/expression.tsx | 19 +- .../public/components/expression/index.tsx | 7 +- .../expression_input.stories.storyshot | 33 +- .../__stories__/expression_input.stories.tsx | 76 ++-- .../expression_input/expression_input.tsx | 344 ++---------------- x-pack/plugins/canvas/public/plugin.tsx | 5 + .../canvas/storybook/storyshots.test.tsx | 5 + .../translations/translations/ja-JP.json | 12 +- .../translations/translations/zh-CN.json | 12 +- 32 files changed, 663 insertions(+), 657 deletions(-) rename {x-pack/plugins/canvas/common/lib => src/plugins/presentation_util/public/components/expression_input}/autocomplete.ts (98%) create mode 100644 src/plugins/presentation_util/public/components/expression_input/constants.ts create mode 100644 src/plugins/presentation_util/public/components/expression_input/expression_input.stories.tsx create mode 100644 src/plugins/presentation_util/public/components/expression_input/expression_input.tsx create mode 100644 src/plugins/presentation_util/public/components/expression_input/index.tsx rename x-pack/plugins/canvas/public/lib/monaco_language_def.ts => src/plugins/presentation_util/public/components/expression_input/language.ts (74%) create mode 100644 src/plugins/presentation_util/public/components/expression_input/providers.ts rename {x-pack/plugins/canvas => src/plugins/presentation_util}/public/components/expression_input/reference.ts (79%) delete mode 100644 x-pack/plugins/canvas/common/lib/autocomplete.test.ts diff --git a/src/plugins/presentation_util/common/index.ts b/src/plugins/presentation_util/common/index.ts index 4510a0aac5a0b..a84a78c823a5f 100644 --- a/src/plugins/presentation_util/common/index.ts +++ b/src/plugins/presentation_util/common/index.ts @@ -12,4 +12,10 @@ export const PLUGIN_ID = 'presentationUtil'; export const PLUGIN_NAME = 'presentationUtil'; +/** + * The unique identifier for the Expressions Language for use in the ExpressionInput + * and CodeEditor components. + */ +export const EXPRESSIONS_LANGUAGE_ID = 'kibana-expressions'; + export * from './labs'; diff --git a/src/plugins/presentation_util/kibana.json b/src/plugins/presentation_util/kibana.json index 210937b335e50..32460a8455152 100644 --- a/src/plugins/presentation_util/kibana.json +++ b/src/plugins/presentation_util/kibana.json @@ -9,7 +9,16 @@ "kibanaVersion": "kibana", "server": true, "ui": true, - "extraPublicDirs": ["common/lib"], - "requiredPlugins": ["savedObjects", "data", "dataViews", "embeddable", "kibanaReact"], + "extraPublicDirs": [ + "common/lib" + ], + "requiredPlugins": [ + "savedObjects", + "data", + "dataViews", + "embeddable", + "kibanaReact", + "expressions" + ], "optionalPlugins": [] } diff --git a/x-pack/plugins/canvas/common/lib/autocomplete.ts b/src/plugins/presentation_util/public/components/expression_input/autocomplete.ts similarity index 98% rename from x-pack/plugins/canvas/common/lib/autocomplete.ts rename to src/plugins/presentation_util/public/components/expression_input/autocomplete.ts index 88fb6b052b957..5f0c9cab6215c 100644 --- a/x-pack/plugins/canvas/common/lib/autocomplete.ts +++ b/src/plugins/presentation_util/public/components/expression_input/autocomplete.ts @@ -1,8 +1,9 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ import { uniq } from 'lodash'; @@ -15,9 +16,9 @@ import { ExpressionFunction, ExpressionFunctionParameter, getByAlias, -} from '../../../../../src/plugins/expressions/common'; +} from '../../../../expressions/common'; -const MARKER = 'CANVAS_SUGGESTION_MARKER'; +const MARKER = 'EXPRESSIONS_SUGGESTION_MARKER'; interface BaseSuggestion { text: string; @@ -25,11 +26,6 @@ interface BaseSuggestion { end: number; } -export interface FunctionSuggestion extends BaseSuggestion { - type: 'function'; - fnDef: ExpressionFunction; -} - interface ArgSuggestionValue extends Omit { name: string; } @@ -43,8 +39,6 @@ interface ValueSuggestion extends BaseSuggestion { type: 'value'; } -export type AutocompleteSuggestion = FunctionSuggestion | ArgSuggestion | ValueSuggestion; - interface FnArgAtPosition { ast: ExpressionASTWithMeta; fnIndex: number; @@ -57,6 +51,7 @@ interface FnArgAtPosition { // If this function is a sub-expression function, we need the parent function and argument // name to determine the return type of the function parentFn?: string; + // If this function is a sub-expression function, the context could either be local or it // could be the parent's previous function. contextFn?: string | null; @@ -101,6 +96,13 @@ type ExpressionASTWithMeta = ASTMetaInformation< > >; +export interface FunctionSuggestion extends BaseSuggestion { + type: 'function'; + fnDef: ExpressionFunction; +} + +export type AutocompleteSuggestion = FunctionSuggestion | ArgSuggestion | ValueSuggestion; + // Typeguard for checking if ExpressionArg is a new expression function isExpression( maybeExpression: ExpressionArgASTWithMeta diff --git a/src/plugins/presentation_util/public/components/expression_input/constants.ts b/src/plugins/presentation_util/public/components/expression_input/constants.ts new file mode 100644 index 0000000000000..f937d55cbf9bb --- /dev/null +++ b/src/plugins/presentation_util/public/components/expression_input/constants.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { CodeEditorProps } from '../../../../kibana_react/public'; + +export const LANGUAGE_CONFIGURATION = { + autoClosingPairs: [ + { + open: '{', + close: '}', + }, + ], +}; + +export const CODE_EDITOR_OPTIONS: CodeEditorProps['options'] = { + scrollBeyondLastLine: false, + quickSuggestions: true, + minimap: { + enabled: false, + }, + wordWrap: 'on', + wrappingIndent: 'indent', +}; diff --git a/src/plugins/presentation_util/public/components/expression_input/expression_input.stories.tsx b/src/plugins/presentation_util/public/components/expression_input/expression_input.stories.tsx new file mode 100644 index 0000000000000..648171959791f --- /dev/null +++ b/src/plugins/presentation_util/public/components/expression_input/expression_input.stories.tsx @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { action } from '@storybook/addon-actions'; +import { Meta } from '@storybook/react'; + +import { ExpressionFunction, ExpressionFunctionParameter, Style } from 'src/plugins/expressions'; +import { ExpressionInput } from '../expression_input'; +import { registerExpressionsLanguage } from './language'; + +const content: ExpressionFunctionParameter<'string'> = { + name: 'content', + required: false, + help: 'A string of text that contains Markdown. To concatenate, pass the `string` function multiple times.', + types: ['string'], + default: '', + aliases: ['_', 'expression'], + multi: true, + resolve: false, + options: [], + accepts: () => true, +}; + +const font: ExpressionFunctionParameter