From 9014e113f5f3e3dd8989698ba8f925ad1f824af5 Mon Sep 17 00:00:00 2001 From: Michael Olorunnisola Date: Tue, 24 Aug 2021 07:44:27 -0400 Subject: [PATCH 1/8] [Security Solution][RAC] - Hide hover actions overflow (#109693) * add overflow * fix types error --- .../public/components/t_grid/body/helpers.tsx | 6 +++++- .../timelines/public/components/t_grid/body/index.tsx | 11 +++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/timelines/public/components/t_grid/body/helpers.tsx b/x-pack/plugins/timelines/public/components/t_grid/body/helpers.tsx index 3dea3e71445a1..6c98884451d8f 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/body/helpers.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/body/helpers.tsx @@ -192,11 +192,14 @@ export const allowSorting = ({ export const addBuildingBlockStyle = ( ecs: Ecs, theme: EuiTheme, - setCellProps: EuiDataGridCellValueElementProps['setCellProps'] + setCellProps: EuiDataGridCellValueElementProps['setCellProps'], + defaultStyles?: React.CSSProperties ) => { + const currentStyles = defaultStyles ?? {}; if (isEventBuildingBlockType(ecs)) { setCellProps({ style: { + ...currentStyles, backgroundColor: `${theme.eui.euiColorHighlight}`, }, }); @@ -204,6 +207,7 @@ export const addBuildingBlockStyle = ( // reset cell style setCellProps({ style: { + ...currentStyles, backgroundColor: 'inherit', }, }); diff --git a/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx index cfb292288cd2c..001e405fc10e0 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/body/index.tsx @@ -596,10 +596,17 @@ export const BodyComponent = React.memo( const rowData = rowIndex < data.length ? data[rowIndex].data : null; const header = columnHeaders.find((h) => h.id === columnId); const eventId = rowIndex < data.length ? data[rowIndex]._id : null; + const defaultStyles = useMemo( + () => ({ + overflow: 'hidden', + }), + [] + ); + setCellProps({ style: { ...defaultStyles } }); useEffect(() => { - addBuildingBlockStyle(data[rowIndex].ecs, theme, setCellProps); - }, [rowIndex, setCellProps]); + addBuildingBlockStyle(data[rowIndex].ecs, theme, setCellProps, defaultStyles); + }, [rowIndex, setCellProps, defaultStyles]); if (rowData == null || header == null || eventId == null) { return null; From be2ca2201cd1f33efcdfad3cca37e2fbe217109c Mon Sep 17 00:00:00 2001 From: ymao1 Date: Tue, 24 Aug 2021 08:23:33 -0400 Subject: [PATCH 2/8] [Alerting][Docs] Updating alerting setup docs (#109285) * Updating alerting authorization docs * Apply suggestions from code review Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- docs/user/alerting/alerting-setup.asciidoc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/user/alerting/alerting-setup.asciidoc b/docs/user/alerting/alerting-setup.asciidoc index 4cd26dbc13e4d..3f12925bbef07 100644 --- a/docs/user/alerting/alerting-setup.asciidoc +++ b/docs/user/alerting/alerting-setup.asciidoc @@ -61,9 +61,13 @@ Rules and connectors are isolated to the {kib} space in which they were created. [[alerting-authorization]] === Authorization -Rules, including all background detection and the actions they generate are authorized using an <> associated with the last user to edit the rule. Upon creating or modifying a rule, an API key is generated for that user, capturing a snapshot of their privileges at that moment in time. The API key is then used to run all background tasks associated with the rule including detection checks and executing actions. +Rules are authorized using an <> associated with the last user to edit the rule. This API key captures a snapshot of the user's privileges at the time of edit and is subsequently used to run all background tasks associated with the rule, including condition checks, like {es} queries, and action executions. The following rule actions will re-generate the API key: + +* Creating a rule +* Enabling a disabled rule +* Updating a rule [IMPORTANT] ============================================== -If a rule requires certain privileges to run, such as index privileges, keep in mind that if a user without those privileges updates the rule, the rule will no longer function. +If a rule requires certain privileges, such as index privileges, to run, and a user without those privileges updates, disables, or re-enables the rule, the rule will no longer function. Conversely, if a user with greater or administrator privileges modifies the rule, it will begin running with increased privileges. ============================================== From 3534450317095c9f3484f54fb0b6bcb1b45cdbe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Tue, 24 Aug 2021 13:56:07 +0100 Subject: [PATCH 3/8] =?UTF-8?q?[Form=20lib]=C2=A0Allow=20dynamic=20data=20?= =?UTF-8?q?to=20be=20passed=20to=20validator=20functions=20(#109238)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../docs/core/use_async_validation_data.mdx | 36 ++ .../static/forms/docs/core/use_field.mdx | 12 + .../static/forms/docs/examples/validation.mdx | 135 +++++++ .../components/use_field.test.tsx | 331 +++++++++++++++++- .../hook_form_lib/components/use_field.tsx | 33 +- .../static/forms/hook_form_lib/hooks/index.ts | 1 + .../hooks/use_async_validation_data.ts | 36 ++ .../forms/hook_form_lib/hooks/use_field.ts | 60 +++- .../forms/hook_form_lib/hooks/use_form.ts | 2 +- .../hook_form_lib/hooks/use_form_data.ts | 22 +- .../static/forms/hook_form_lib/index.ts | 2 +- .../static/forms/hook_form_lib/types.ts | 5 + .../rules/step_rule_actions/schema.test.tsx | 3 + 13 files changed, 650 insertions(+), 28 deletions(-) create mode 100644 src/plugins/es_ui_shared/static/forms/docs/core/use_async_validation_data.mdx create mode 100644 src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_async_validation_data.ts diff --git a/src/plugins/es_ui_shared/static/forms/docs/core/use_async_validation_data.mdx b/src/plugins/es_ui_shared/static/forms/docs/core/use_async_validation_data.mdx new file mode 100644 index 0000000000000..8020a54596b46 --- /dev/null +++ b/src/plugins/es_ui_shared/static/forms/docs/core/use_async_validation_data.mdx @@ -0,0 +1,36 @@ +--- +id: formLibCoreUseAsyncValidationData +slug: /form-lib/core/use-async-validation-data +title: useAsyncValidationData() +summary: Provide dynamic data to your validators... asynchronously +tags: ['forms', 'kibana', 'dev'] +date: 2021-08-20 +--- + +**Returns:** `[Observable, (nextValue: T|undefined) => void]` + +This hook creates for you an observable and a handler to update its value. You can then pass the observable directly to . + +See an example on how to use this hook in the section. + +## Options + +### state (optional) + +**Type:** `any` + +If you provide a state when calling the hook, the observable value will keep in sync with the state. + +```js +const MyForm = () => { + ... + const [indices, setIndices] = useState([]); + // Whenever the "indices" state changes, the "indices$" Observable will be updated + const [indices$] = useAsyncValidationData(indices); + + ... + + + +} +``` \ No newline at end of file diff --git a/src/plugins/es_ui_shared/static/forms/docs/core/use_field.mdx b/src/plugins/es_ui_shared/static/forms/docs/core/use_field.mdx index b1d70d05c8d27..fd5f3b26cdf0d 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/core/use_field.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/core/use_field.mdx @@ -336,6 +336,18 @@ If you provide a `component` you can pass here any prop you want to forward to t By default if you don't provide a `defaultValue` prop to ``, it will try to read the default value on . If you want to prevent this behaviour you can set `readDefaultValueOnForm` to false. This can be usefull for dynamic fields, as . +### validationData + +Use this prop to pass down dynamic data to your field validator. The data is then accessible in the validator through the `customData.value` property. + +See an example on how to use this prop in the section. + +### validationData$ + +Use this prop to pass down an Observable into which you can send, asynchronously, dynamic data required inside your validation. + +See an example on how to use this prop in the section. + ### onChange **Type:** `(value:T) => void` diff --git a/src/plugins/es_ui_shared/static/forms/docs/examples/validation.mdx b/src/plugins/es_ui_shared/static/forms/docs/examples/validation.mdx index bbd89d707e4fe..8526a8912ba08 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/examples/validation.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/examples/validation.mdx @@ -272,3 +272,138 @@ export const MyComponent = () => { ``` Great, but that's **a lot** of code for a simple tags field input. Fortunatelly the `` helper component takes care of all the heavy lifting for us. . + +## Dynamic data inside your validation + +If your validator requires dynamic data you can provide it through the `validationData` prop on the `` component. The data is then available in the validator through the `customData.value` property. + +```typescript +// Form schema +const schema = { + name: { + validations: [{ + validator: ({ customData: { value } }) => { + // value === [1, 2 ,3] as passed below + } + }] + } +}; + +// Component JSX + +``` + +### Asynchronous dynamic data in the validator + +There might be times where you validator requires dynamic data asynchronously that is not immediately available when the field value changes (and the validation is triggered) but at a later stage. + +Let's imagine that you have a form with an `indexName` text field and that you want to display below the form the list of indices in your cluster that match the index name entered by the user. + +You would probably have something like this + +```js +const MyForm = () => { + const { form } = useForm(); + const [{ indexName }] = useFormData({ watch: 'indexName' }); + const [indices, setIndices] = useState([]); + + const fetchIndices = useCallback(async () => { + const result = await httpClient.get(`/api/search/${indexName}`); + setIndices(result); + }, [indexName]); + + // Whenever the indexName changes we fetch the indices + useEffet(() => { + fetchIndices(); + }, [fetchIndices]); + + return ( + <> +
+ + + + /* Display the list of indices that match the index name entered */ +
    + {indices.map((index, i) =>
  • {index}
  • )} +
+ <> + ); +} +``` + +Great. Now let's imagine that you want to add a validation to the `indexName` field and mark it as invalid if it does not match at least one index in the cluster. For that you need to provide dynamic data (the list of indices fetched) which is not immediately accesible when the field value changes (and the validation kicks in). We need to ask the validation to **wait** until we have fetched the indices and then have access to the dynamic data. + +For that we will use the `validationData$` Observable that you can pass to the field. Whenever a value is sent to the observable (**after** the field value has changed, important!), it will be available in the validator through the `customData.provider()` handler. + +```js +// form.schema.ts +const schema = { + indexName: { + validations: [{ + validator: async ({ value, customData: { provider } }) => { + // Whenever a new value is sent to the `validationData$` Observable + // the Promise will resolve with that value + const indices = await provider(); + + if (!indices.include(value)) { + return { + message: `This index does not match any of your indices` + } + } + } + }] + } as FieldConfig +} + +// myform.tsx +const MyForm = () => { + ... + const [indices, setIndices] = useState([]); + const [indices$, nextIndices] = useAsyncValidationData(); // Use the provided hook to create the Observable + + const fetchIndices = useCallback(async () => { + const result = await httpClient.get(`/api/search/${indexName}`); + setIndices(result); + nextIndices(result); // Send the indices to your validator "provider()" + }, [indexName]); + + // Whenever the indexName changes we fetch the indices + useEffet(() => { + fetchIndices(); + }, [fetchIndices]); + + return ( + <> +
+ /* Pass the Observable to your field */ + + + + ... + <> + ); +} +``` + +Et voilĂ ! We have provided dynamic data asynchronously to our validator. + +The above example could be simplified a bit by using the optional `state` argument of the `useAsyncValidationData(/* state */)` hook. + +```js +const MyForm = () => { + ... + const [indices, setIndices] = useState([]); + // We don't need the second element of the array (the "nextIndices()" handler) + // as whenever the "indices" state changes the "indices$" Observable will receive its value + const [indices$] = useAsyncValidationData(indices); + + ... + + const fetchIndices = useCallback(async () => { + const result = await httpClient.get(`/api/search/${indexName}`); + setIndices(result); // This will also update the Observable + }, [indexName]); + + ... +``` \ No newline at end of file diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_field.test.tsx b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_field.test.tsx index 2106bd50dad03..0950f2dabb1b7 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_field.test.tsx +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_field.test.tsx @@ -6,16 +6,25 @@ * Side Public License, v 1. */ -import React, { useEffect, FunctionComponent } from 'react'; +import React, { useEffect, FunctionComponent, useState } from 'react'; import { act } from 'react-dom/test-utils'; import { registerTestBed, TestBed } from '../shared_imports'; import { FormHook, OnUpdateHandler, FieldConfig, FieldHook } from '../types'; import { useForm } from '../hooks/use_form'; +import { useAsyncValidationData } from '../hooks/use_async_validation_data'; import { Form } from './form'; import { UseField } from './use_field'; describe('', () => { + beforeAll(() => { + jest.useFakeTimers(); + }); + + afterAll(() => { + jest.useRealTimers(); + }); + test('should read the default value from the prop and fallback to the config object', () => { const onFormData = jest.fn(); @@ -195,26 +204,54 @@ describe('', () => { describe('validation', () => { let formHook: FormHook | null = null; + let fieldHook: FieldHook | null = null; beforeEach(() => { formHook = null; + fieldHook = null; }); const onFormHook = (form: FormHook) => { formHook = form; }; + const onFieldHook = (field: FieldHook) => { + fieldHook = field; + }; + const getTestComp = (fieldConfig: FieldConfig) => { - const TestComp = ({ onForm }: { onForm: (form: FormHook) => void }) => { + const TestComp = () => { const { form } = useForm(); + const [isFieldActive, setIsFieldActive] = useState(true); + + const unmountField = () => { + setIsFieldActive(false); + }; useEffect(() => { - onForm(form); - }, [onForm, form]); + onFormHook(form); + }, [form]); return (
- + {isFieldActive && ( + + {(field) => { + onFieldHook(field); + + return ( + + ); + }} + + )} + ); }; @@ -224,7 +261,6 @@ describe('', () => { const setup = (fieldConfig: FieldConfig) => { return registerTestBed(getTestComp(fieldConfig), { memoryRouter: { wrapComponent: false }, - defaultProps: { onForm: onFormHook }, })() as TestBed; }; @@ -278,6 +314,289 @@ describe('', () => { ({ isValid } = formHook); expect(isValid).toBe(false); }); + + test('should not update the state if the field has unmounted while validating', async () => { + const fieldConfig: FieldConfig = { + validations: [ + { + validator: () => { + // The validation will return its value after 5s + return new Promise((resolve) => { + setTimeout(() => { + resolve({ message: 'Invalid field' }); + }, 5000); + }); + }, + }, + ], + }; + + const { + find, + form: { setInputValue }, + } = setup(fieldConfig); + + expect(fieldHook?.isValidating).toBe(false); + + // Trigger validation... + await act(async () => { + setInputValue('myField', 'changedValue'); + }); + + expect(fieldHook?.isValidating).toBe(true); + + // Unmount the field + await act(async () => { + find('unmountFieldBtn').simulate('click'); + }); + + const originalConsoleError = console.error; // eslint-disable-line no-console + const spyConsoleError = jest.fn((message) => { + originalConsoleError(message); + }); + console.error = spyConsoleError; // eslint-disable-line no-console + + // Move the timer to resolve the validator + await act(async () => { + jest.advanceTimersByTime(5000); + }); + + // The test should not display any warning + // "Can't perform a React state update on an unmounted component." + expect(spyConsoleError.mock.calls.length).toBe(0); + + console.error = originalConsoleError; // eslint-disable-line no-console + }); + + describe('dynamic data', () => { + let nameFieldHook: FieldHook | null = null; + let lastNameFieldHook: FieldHook | null = null; + + const schema = { + name: { + validations: [ + { + validator: async ({ customData: { provider } }) => { + // Async validator that requires the observable to emit a value + // to complete the validation. Once it emits a value, the dataProvider + // Promise fullfills. + const dynamicData = await provider(); + if (dynamicData === 'bad') { + return { + message: 'Invalid dynamic data', + }; + } + }, + }, + ], + } as FieldConfig, + lastName: { + validations: [ + { + validator: ({ customData: { value: validationData } }) => { + // Sync validator that receives the validationData passed through + // props on + if (validationData === 'bad') { + return { + message: `Invalid dynamic data: ${validationData}`, + }; + } + }, + }, + ], + } as FieldConfig, + }; + + const onNameFieldHook = (field: FieldHook) => { + nameFieldHook = field; + }; + const onLastNameFieldHook = (field: FieldHook) => { + lastNameFieldHook = field; + }; + + interface DynamicValidationDataProps { + validationData?: unknown; + } + + const TestComp = ({ validationData }: DynamicValidationDataProps) => { + const { form } = useForm({ schema }); + const [stateValue, setStateValue] = useState('initialValue'); + const [validationData$, next] = useAsyncValidationData(stateValue); + + const setInvalidDynamicData = () => { + next('bad'); + }; + + const setValidDynamicData = () => { + next('good'); + }; + + // Updating the state should emit a new value in the observable + // which in turn should be available in the validation and allow it to complete. + const setStateValueWithValidValue = () => { + setStateValue('good'); + }; + + const setStateValueWithInValidValue = () => { + setStateValue('bad'); + }; + + return ( +
+ <> + {/* Dynamic async validation data with an observable. The validation + will complete **only after** the observable has emitted a value. */} + path="name" validationData$={validationData$}> + {(field) => { + onNameFieldHook(field); + return ( + + ); + }} + + + {/* Dynamic validation data passed synchronously through props */} + path="lastName" validationData={validationData}> + {(field) => { + onLastNameFieldHook(field); + return ( + + ); + }} + + + + + + + + + ); + }; + + const setupDynamicData = (defaultProps?: Partial) => { + return registerTestBed(TestComp, { + memoryRouter: { wrapComponent: false }, + defaultProps, + })() as TestBed; + }; + + beforeEach(() => { + nameFieldHook = null; + }); + + test('it should access dynamic data provided **after** the field value changed', async () => { + const { form, find } = setupDynamicData(); + + await act(async () => { + form.setInputValue('nameField', 'newValue'); + }); + // If the field is validating this will prevent the form from being submitted as + // it will wait for all the fields to finish validating to return the form validity. + expect(nameFieldHook?.isValidating).toBe(true); + + // Let's wait 10 sec to make sure the validation does not complete + // until the observable receives a value + await act(async () => { + jest.advanceTimersByTime(10000); + }); + // The field is still validating as no value has been sent to the observable + expect(nameFieldHook?.isValidating).toBe(true); + + // We now send a valid value to the observable + await act(async () => { + find('setValidValueBtn').simulate('click'); + }); + + expect(nameFieldHook?.isValidating).toBe(false); + expect(nameFieldHook?.isValid).toBe(true); + + // Let's change the input value to trigger the validation once more + await act(async () => { + form.setInputValue('nameField', 'anotherValue'); + }); + expect(nameFieldHook?.isValidating).toBe(true); + + // And send an invalid value to the observable + await act(async () => { + find('setInvalidValueBtn').simulate('click'); + }); + expect(nameFieldHook?.isValidating).toBe(false); + expect(nameFieldHook?.isValid).toBe(false); + expect(nameFieldHook?.getErrorsMessages()).toBe('Invalid dynamic data'); + }); + + test('it should access dynamic data coming after the field value changed, **in sync** with a state change', async () => { + const { form, find } = setupDynamicData(); + + await act(async () => { + form.setInputValue('nameField', 'newValue'); + }); + expect(nameFieldHook?.isValidating).toBe(true); + + // We now update the state with a valid value + // this should update the observable + await act(async () => { + find('setValidStateValueBtn').simulate('click'); + }); + + expect(nameFieldHook?.isValidating).toBe(false); + expect(nameFieldHook?.isValid).toBe(true); + + // Let's change the input value to trigger the validation once more + await act(async () => { + form.setInputValue('nameField', 'anotherValue'); + }); + expect(nameFieldHook?.isValidating).toBe(true); + + // And change the state with an invalid value + await act(async () => { + find('setInvalidStateValueBtn').simulate('click'); + }); + + expect(nameFieldHook?.isValidating).toBe(false); + expect(nameFieldHook?.isValid).toBe(false); + }); + + test('it should access dynamic data provided through props', async () => { + let { form } = setupDynamicData({ validationData: 'good' }); + + await act(async () => { + form.setInputValue('lastNameField', 'newValue'); + }); + // As this is a sync validation it should not be validating anymore at this stage + expect(lastNameFieldHook?.isValidating).toBe(false); + expect(lastNameFieldHook?.isValid).toBe(true); + + // Now let's provide invalid dynamic data through props + ({ form } = setupDynamicData({ validationData: 'bad' })); + await act(async () => { + form.setInputValue('lastNameField', 'newValue'); + }); + expect(lastNameFieldHook?.isValidating).toBe(false); + expect(lastNameFieldHook?.isValid).toBe(false); + expect(lastNameFieldHook?.getErrorsMessages()).toBe('Invalid dynamic data: bad'); + }); + }); }); describe('serializer(), deserializer(), formatter()', () => { diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_field.tsx b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_field.tsx index 45fa2e977a6c7..89eacfc0cb9df 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_field.tsx +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_field.tsx @@ -7,6 +7,7 @@ */ import React, { FunctionComponent } from 'react'; +import { Observable } from 'rxjs'; import { FieldHook, FieldConfig, FormData } from '../types'; import { useField } from '../hooks'; @@ -19,6 +20,31 @@ export interface Props { component?: FunctionComponent; componentProps?: Record; readDefaultValueOnForm?: boolean; + /** + * Use this prop to pass down dynamic data **asynchronously** to your validators. + * Your validator accesses the dynamic data by resolving the provider() Promise. + * The Promise will resolve **when a new value is sent** to the validationData$ Observable. + * + * ```typescript + * validator: ({ customData }) => { + * // Wait until a value is sent to the "validationData$" Observable + * const dynamicData = await customData.provider(); + * } + * ``` + */ + validationData$?: Observable; + /** + * Use this prop to pass down dynamic data to your validators. The validation data + * is then accessible in your validator inside the `customData.value` property. + * + * ```typescript + * validator: ({ customData: { value: dynamicData } }) => { + * // Validate with the dynamic data + * if (dynamicData) { .. } + * } + * ``` + */ + validationData?: unknown; onChange?: (value: I) => void; onError?: (errors: string[] | null) => void; children?: (field: FieldHook) => JSX.Element | null; @@ -36,6 +62,8 @@ function UseFieldComp(props: Props(props: Props(form, path, fieldConfig, onChange, onError); + const field = useField(form, path, fieldConfig, onChange, onError, { + customValidationData$, + customValidationData, + }); // Children prevails over anything else provided. if (children) { diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/index.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/index.ts index 3afb5bf6a20c2..8438e5de871bd 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/index.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/index.ts @@ -10,3 +10,4 @@ export { useField, InternalFieldConfig } from './use_field'; export { useForm } from './use_form'; export { useFormData } from './use_form_data'; export { useFormIsModified } from './use_form_is_modified'; +export { useAsyncValidationData } from './use_async_validation_data'; diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_async_validation_data.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_async_validation_data.ts new file mode 100644 index 0000000000000..21d5e101536ae --- /dev/null +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_async_validation_data.ts @@ -0,0 +1,36 @@ +/* + * 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 { useCallback, useRef, useMemo, useEffect } from 'react'; +import { Subject, Observable } from 'rxjs'; + +export const useAsyncValidationData = (state?: T) => { + const validationData$ = useRef>(); + + const getValidationData$ = useCallback(() => { + if (validationData$.current === undefined) { + validationData$.current = new Subject(); + } + return validationData$.current; + }, []); + + const hook: [Observable, (value?: T) => void] = useMemo(() => { + const subject = getValidationData$(); + + const observable = subject.asObservable(); + const next = subject.next.bind(subject); + + return [observable, next]; + }, [getValidationData$]); + + // Whenever the state changes we update the observable + useEffect(() => { + getValidationData$().next(state); + }, [state, getValidationData$]); + + return hook; +}; diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.ts index 806c60a66aa1d..ececf724db45d 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.ts @@ -7,6 +7,8 @@ */ import { useMemo, useState, useEffect, useRef, useCallback } from 'react'; +import { Observable } from 'rxjs'; +import { first } from 'rxjs/operators'; import { FormHook, @@ -29,7 +31,11 @@ export const useField = ( path: string, config: FieldConfig & InternalFieldConfig = {}, valueChangeListener?: (value: I) => void, - errorChangeListener?: (errors: string[] | null) => void + errorChangeListener?: (errors: string[] | null) => void, + { + customValidationData$, + customValidationData = null, + }: { customValidationData$?: Observable; customValidationData?: unknown } = {} ) => { const { type = FIELD_TYPES.TEXT, @@ -81,6 +87,12 @@ export const useField = ( const hasBeenReset = useRef(false); const inflightValidation = useRef<(Promise & { cancel?(): void }) | null>(null); const debounceTimeout = useRef(null); + // Keep a ref of the last state (value and errors) notified to the consumer so he does + // not get tons of updates whenever he does not wrap the "onChange()" and "onError()" handlers with a useCallback + const lastNotifiedState = useRef<{ value?: I; errors: string[] | null }>({ + value: undefined, + errors: null, + }); // ---------------------------------- // -- HELPERS @@ -131,11 +143,6 @@ export const useField = ( setPristine(false); setIsChangingValue(true); - // Notify listener - if (valueChangeListener) { - valueChangeListener(value); - } - // Update the form data observable __updateFormDataAt(path, value); @@ -171,7 +178,6 @@ export const useField = ( }, [ path, value, - valueChangeListener, valueChangeDebounceTime, fieldsToValidateOnChange, __updateFormDataAt, @@ -232,6 +238,12 @@ export const useField = ( return false; }; + let dataProvider: () => Promise = () => Promise.resolve(null); + + if (customValidationData$) { + dataProvider = () => customValidationData$.pipe(first()).toPromise(); + } + const runAsync = async () => { const validationErrors: ValidationError[] = []; @@ -254,6 +266,7 @@ export const useField = ( form: { getFormData, getFields }, formData, path, + customData: { provider: dataProvider, value: customValidationData }, }) as Promise; const validationResult = await inflightValidation.current; @@ -297,6 +310,7 @@ export const useField = ( form: { getFormData, getFields }, formData, path, + customData: { provider: dataProvider, value: customValidationData }, }); if (!validationResult) { @@ -334,7 +348,15 @@ export const useField = ( // We first try to run the validations synchronously return runSync(); }, - [cancelInflightValidation, validations, getFormData, getFields, path] + [ + cancelInflightValidation, + validations, + getFormData, + getFields, + path, + customValidationData, + customValidationData$, + ] ); // ---------------------------------- @@ -376,7 +398,7 @@ export const useField = ( const validateIteration = ++validateCounter.current; const onValidationResult = (_validationErrors: ValidationError[]): FieldValidateResponse => { - if (validateIteration === validateCounter.current) { + if (validateIteration === validateCounter.current && isMounted.current) { // This is the most recent invocation setValidating(false); // Update the errors array @@ -566,6 +588,18 @@ export const useField = ( }; }, [path, __removeField]); + // Notify listener whenever the value changes + useEffect(() => { + if (!isMounted.current) { + return; + } + + if (valueChangeListener && value !== lastNotifiedState.current.value) { + valueChangeListener(value); + lastNotifiedState.current.value = value; + } + }, [value, valueChangeListener]); + useEffect(() => { // If the field value has been reset, we don't want to call the "onValueChange()" // as it will set the "isPristine" state to true or validate the field, which we don't want @@ -602,8 +636,12 @@ export const useField = ( if (!isMounted.current) { return; } - if (errorChangeListener) { - errorChangeListener(errors.length ? errors.map((error) => error.message) : null); + + const errorMessages = errors.length ? errors.map((error) => error.message) : null; + + if (errorChangeListener && lastNotifiedState.current.errors !== errorMessages) { + errorChangeListener(errorMessages); + lastNotifiedState.current.errors = errorMessages; } }, [errors, errorChangeListener]); diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form.ts index b42b3211871ba..864579a8c71f3 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form.ts @@ -166,7 +166,7 @@ export function useForm( return { areFieldsValid: true, isFormValid: true }; } - const areFieldsValid = validationResult.every(Boolean); + const areFieldsValid = validationResult.every((res) => res.isValid); const validationResultByPath = fieldsToValidate.reduce((acc, field, i) => { acc[field.path] = validationResult[i].isValid; diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form_data.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form_data.ts index af3da45868b5a..7ad98bc2483bb 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form_data.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form_data.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { useState, useEffect, useRef, useCallback } from 'react'; +import { useState, useEffect, useRef, useCallback, useMemo } from 'react'; import { FormData, FormHook } from '../types'; import { unflattenObject } from '../lib'; @@ -24,6 +24,9 @@ export const useFormData = ( ): HookReturn => { const { watch, form } = options; const ctx = useFormDataContext(); + const watchToArray: string[] = watch === undefined ? [] : Array.isArray(watch) ? watch : [watch]; + // We will use "stringifiedWatch" to compare if the array has changed in the useMemo() below + const stringifiedWatch = watchToArray.join('.'); let getFormData: Context['getFormData']; let getFormData$: Context['getFormData$']; @@ -54,16 +57,14 @@ export const useFormData = ( // eslint-disable-next-line react-hooks/exhaustive-deps }, [getFormData, formData]); - useEffect(() => { - const subscription = getFormData$().subscribe((raw) => { + const subscription = useMemo(() => { + return getFormData$().subscribe((raw) => { if (!isMounted.current && Object.keys(raw).length === 0) { return; } - if (watch) { - const pathsToWatchArray: string[] = Array.isArray(watch) ? watch : [watch]; - - if (pathsToWatchArray.some((path) => previousRawData.current[path] !== raw[path])) { + if (watchToArray.length > 0) { + if (watchToArray.some((path) => previousRawData.current[path] !== raw[path])) { previousRawData.current = raw; // Only update the state if one of the field we watch has changed. setFormData(unflattenObject(raw)); @@ -72,8 +73,13 @@ export const useFormData = ( setFormData(unflattenObject(raw)); } }); + // To compare we use the stringified version of the "watchToArray" array + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [stringifiedWatch, getFormData$]); + + useEffect(() => { return subscription.unsubscribe; - }, [getFormData$, watch]); + }, [subscription]); useEffect(() => { isMounted.current = true; diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/index.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/index.ts index 19121bb6753a0..b5c7f5b4214e0 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/index.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/index.ts @@ -8,7 +8,7 @@ // We don't export the "useField" hook as it is for internal use. // The consumer of the library must use the component to create a field -export { useForm, useFormData, useFormIsModified } from './hooks'; +export { useForm, useFormData, useFormIsModified, useAsyncValidationData } from './hooks'; export { getFieldValidityAndErrorMessage } from './helpers'; export * from './form_context'; diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/types.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/types.ts index 151adea30c4f1..cfb211b702ed6 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/types.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/types.ts @@ -193,6 +193,11 @@ export interface ValidationFuncArg { }; formData: I; errors: readonly ValidationError[]; + customData: { + /** Async handler that will resolve whenever a value is sent to the `validationData$` Observable */ + provider: () => Promise; + value: unknown; + }; } export type ValidationFunc< diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/schema.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/schema.test.tsx index 3266d6f61eeed..0513f3754d3d5 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/schema.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/schema.test.tsx @@ -83,6 +83,7 @@ describe('stepRuleActions schema', () => { form: {} as FormHook, formData: jest.fn(), errors: [], + customData: { value: null, provider: () => Promise.resolve(null) }, }); expect(result).toEqual(undefined); @@ -105,6 +106,7 @@ describe('stepRuleActions schema', () => { form: {} as FormHook, formData: jest.fn(), errors: [], + customData: { value: null, provider: () => Promise.resolve(null) }, }); expect(result).toEqual({ @@ -147,6 +149,7 @@ describe('stepRuleActions schema', () => { form: {} as FormHook, formData: jest.fn(), errors: [], + customData: { value: null, provider: () => Promise.resolve(null) }, }); expect(result).toEqual({ From d36287a1e5cc357ab9651b81e2b26c1da6784e6e Mon Sep 17 00:00:00 2001 From: Orhan Toy Date: Tue, 24 Aug 2021 15:05:37 +0200 Subject: [PATCH 4/8] [App Search] Fix typo in content verification fallback message (#109743) --- .../crawler/components/add_domain/add_domain_logic.test.ts | 4 ++-- .../components/crawler/components/add_domain/utils.ts | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/add_domain/add_domain_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/add_domain/add_domain_logic.test.ts index 04bb253165b41..addee72ae4bd2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/add_domain/add_domain_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/add_domain/add_domain_logic.test.ts @@ -479,7 +479,7 @@ describe('AddDomainLogic', () => { }, contentVerification: { state: 'invalid', - message: 'Unable to verify content because the "Network Connectivity" check failed.', + message: 'Unable to verify content because the "Indexing Restrictions" check failed.', }, }); }); @@ -574,7 +574,7 @@ describe('AddDomainLogic', () => { }, contentVerification: { state: 'invalid', - message: 'Unable to verify content because the "Network Connectivity" check failed.', + message: 'Unable to verify content because the "Indexing Restrictions" check failed.', }, }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/add_domain/utils.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/add_domain/utils.ts index 15fbac64b47d3..fb72c1da0a6b1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/add_domain/utils.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/add_domain/utils.ts @@ -99,7 +99,8 @@ const allFailureResultChanges: CrawlerDomainValidationResultChange = { message: i18n.translate( 'xpack.enterpriseSearch.appSearch.crawler.addDomainForm.contentVerificationFalureMessage', { - defaultMessage: 'Unable to verify content because the "Network Connectivity" check failed.', + defaultMessage: + 'Unable to verify content because the "Indexing Restrictions" check failed.', } ), }, From 796a1cfbe697d8465b52a2de9b483dc834847b9c Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Tue, 24 Aug 2021 15:33:40 +0200 Subject: [PATCH 5/8] [Security Solutions] Adds missing exceptionable field for behavior protections (#109782) --- .../security_solution/common/endpoint/generate_data.ts | 4 ++++ .../components/exceptions/exceptionable_endpoint_fields.json | 1 + 2 files changed, 5 insertions(+) diff --git a/x-pack/plugins/security_solution/common/endpoint/generate_data.ts b/x-pack/plugins/security_solution/common/endpoint/generate_data.ts index 94fc6be366beb..8df0dfc6b58a4 100644 --- a/x-pack/plugins/security_solution/common/endpoint/generate_data.ts +++ b/x-pack/plugins/security_solution/common/endpoint/generate_data.ts @@ -871,6 +871,10 @@ export class EndpointDocGenerator extends BaseDataGenerator { name: processName, entity_id: entityID, executable: `C:/fake_behavior/${processName}`, + code_signature: { + status: 'trusted', + subject_name: 'Microsoft Windows', + }, parent: parentEntityID ? { entity_id: parentEntityID, diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/exceptionable_endpoint_fields.json b/x-pack/plugins/security_solution/public/common/components/exceptions/exceptionable_endpoint_fields.json index 12ee0273f078a..d46b39b90fe5a 100644 --- a/x-pack/plugins/security_solution/public/common/components/exceptions/exceptionable_endpoint_fields.json +++ b/x-pack/plugins/security_solution/public/common/components/exceptions/exceptionable_endpoint_fields.json @@ -78,6 +78,7 @@ "host.os.version", "host.type", "process.command_line", + "process.code_signature.subject_name", "process.Ext.services", "process.Ext.user", "process.Ext.code_signature", From 9857cac494d9a9b8c5f32388272036b5261e5765 Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Tue, 24 Aug 2021 07:39:29 -0600 Subject: [PATCH 6/8] [Metrics UI] Unskip Inventory View Saved View Tests (#109697) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/test/functional/apps/infra/home_page.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/test/functional/apps/infra/home_page.ts b/x-pack/test/functional/apps/infra/home_page.ts index 255f2c49e5621..ccab92918ee42 100644 --- a/x-pack/test/functional/apps/infra/home_page.ts +++ b/x-pack/test/functional/apps/infra/home_page.ts @@ -87,12 +87,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); - // FLAKY: https://github.com/elastic/kibana/issues/106650 - describe.skip('Saved Views', () => { + describe('Saved Views', () => { before(() => esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs')); after(() => esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs')); it('should have save and load controls', async () => { await pageObjects.common.navigateToApp('infraOps'); + await pageObjects.infraHome.waitForLoading(); await pageObjects.infraHome.goToTime(DATE_WITH_DATA); await pageObjects.infraSavedViews.getSavedViewsButton(); await pageObjects.infraSavedViews.ensureViewIsLoaded('Default view'); From 52ee65b8d5a7721bb3b03b1a55b5b656af3bd8d0 Mon Sep 17 00:00:00 2001 From: Stacey Gammon Date: Tue, 24 Aug 2021 10:02:32 -0400 Subject: [PATCH 7/8] Make owner attribute required on kibana.json (#108231) * make owner attribute required * Add owner properties in more places * add test for owner attribute * add error check too in the test * Fix tests * fix tests and update docs * wip * More test fixes * Fix All The Errorz * Adding more owner attributes * Update x-pack/test/saved_object_api_integration/common/fixtures/saved_object_test_plugin/kibana.json Co-authored-by: Larry Gregory * Update x-pack/test/ui_capabilities/common/fixtures/plugins/foo_plugin/kibana.json Co-authored-by: Larry Gregory * commeeeooonnnn * Update docs * soooo many kibanajsons * adjust plugin generator to add an owner * Add owner to the plugin generator scripts * update snapshot * Fix snapshot * review updates Co-authored-by: Larry Gregory Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- dev_docs/key_concepts/anatomy_of_a_plugin.mdx | 2 +- ...ibana-plugin-core-server.pluginmanifest.md | 2 +- ...plugin-core-server.pluginmanifest.owner.md | 4 +- .../plugins/parse_kibana_platform_plugin.ts | 9 +- .../src/api_docs/mdx/write_plugin_mdx_docs.ts | 4 +- .../__fixtures__/src/plugin_a/kibana.json | 12 +- .../__fixtures__/src/plugin_b/kibana.json | 1 + .../tests/kibana_platform_plugin_mock.ts | 3 + .../mock_repo/plugins/bar/kibana.json | 5 +- .../mock_repo/plugins/foo/kibana.json | 3 + .../mock_repo/plugins/nested/baz/kibana.json | 3 + .../test_plugins/test_baz/kibana.json | 3 + .../mock_repo/x-pack/baz/kibana.json | 1 + .../kbn-plugin-generator/src/ask_questions.ts | 26 ++++ .../src/render_template.ts | 4 + .../template/kibana.json.ejs | 5 + .../src/integration_tests/build.test.ts | 5 + src/core/public/plugins/plugin.test.ts | 3 + .../public/plugins/plugins_service.test.ts | 4 + .../discovery/plugin_manifest_parser.test.ts | 114 +++++++++++++++--- .../discovery/plugin_manifest_parser.ts | 11 +- .../discovery/plugins_discovery.test.ts | 90 +++++++++++--- .../integration_tests/plugins_service.test.ts | 3 + src/core/server/plugins/plugin.test.ts | 1 + .../server/plugins/plugin_context.test.ts | 4 + .../server/plugins/plugins_service.test.ts | 4 + .../server/plugins/plugins_system.test.ts | 1 + src/core/server/plugins/types.ts | 5 +- src/core/server/server.api.md | 11 +- .../fixtures/test_plugin/kibana.json | 4 + .../fixtures/plugins/coverage/kibana.json | 4 +- .../fixtures/plugins/newsfeed/kibana.json | 4 + .../plugins/kbn_tp_run_pipeline/kibana.json | 15 +-- .../plugins/app_link_test/kibana.json | 4 + .../plugins/core_app_status/kibana.json | 4 + .../plugins/core_history_block/kibana.json | 4 + .../plugins/core_http/kibana.json | 4 + .../plugins/core_plugin_a/kibana.json | 4 + .../plugins/core_plugin_appleave/kibana.json | 4 + .../plugins/core_plugin_b/kibana.json | 4 + .../core_plugin_chromeless/kibana.json | 4 + .../core_plugin_deep_links/kibana.json | 4 + .../core_plugin_deprecations/kibana.json | 4 + .../core_plugin_execution_context/kibana.json | 4 + .../plugins/core_plugin_helpmenu/kibana.json | 4 + .../core_plugin_route_timeouts/kibana.json | 4 + .../core_plugin_static_assets/kibana.json | 4 + .../plugins/core_provider_plugin/kibana.json | 12 +- .../plugins/data_search/kibana.json | 4 + .../elasticsearch_client_plugin/kibana.json | 4 + .../kbn_sample_panel_action/kibana.json | 4 + .../plugins/kbn_top_nav/kibana.json | 4 + .../kbn_tp_custom_visualizations/kibana.json | 9 +- .../management_test_plugin/kibana.json | 4 + .../plugins/rendering_plugin/kibana.json | 4 + .../kibana.json | 4 + .../saved_object_import_warnings/kibana.json | 4 + .../saved_objects_hidden_type/kibana.json | 4 + .../plugins/session_notifications/kibana.json | 4 + .../plugins/telemetry/kibana.json | 4 + .../plugins/ui_settings_plugin/kibana.json | 4 + .../plugins/usage_collection/kibana.json | 4 + .../plugins/status_plugin_a/kibana.json | 1 + .../plugins/status_plugin_b/kibana.json | 1 + x-pack/plugins/dashboard_enhanced/kibana.json | 24 ++-- x-pack/plugins/monitoring/kibana.json | 2 +- x-pack/plugins/rule_registry/kibana.json | 4 + .../common/fixtures/plugins/aad/kibana.json | 4 + .../plugins/actions_simulators/kibana.json | 4 + .../fixtures/plugins/alerts/kibana.json | 6 +- .../plugins/alerts_restricted/kibana.json | 4 + .../plugins/task_manager_fixture/kibana.json | 4 + .../plugins/cases_client_user/kibana.json | 6 +- .../plugins/observability/kibana.json | 6 +- .../plugins/security_solution/kibana.json | 6 +- .../fixtures/saml/saml_provider/kibana.json | 1 + .../fixtures/api_consumer_plugin/kibana.json | 1 + .../plugins/kibana_cors_test/kibana.json | 1 + .../plugins/iframe_embedded/kibana.json | 1 + .../fixtures/plugins/alerts/kibana.json | 1 + .../plugins/test_feature_usage/kibana.json | 1 + .../plugins/elasticsearch_client/kibana.json | 1 + .../plugins/event_log/kibana.json | 4 + .../plugins/feature_usage_test/kibana.json | 4 + .../plugins/sample_task_plugin/kibana.json | 4 + .../task_manager_performance/kibana.json | 1 + .../plugins/global_search_test/kibana.json | 1 + .../plugins/resolver_test/kibana.json | 12 +- .../plugins/timelines_test/kibana.json | 1 + .../saved_object_test_plugin/kibana.json | 1 + .../fixtures/audit/audit_log/kibana.json | 1 + .../fixtures/oidc/oidc_provider/kibana.json | 1 + .../fixtures/saml/saml_provider/kibana.json | 1 + .../common/test_endpoints/kibana.json | 1 + .../fixtures/spaces_test_plugin/kibana.json | 1 + .../fixtures/plugins/foo_plugin/kibana.json | 1 + .../application_usage_test/kibana.json | 1 + .../stack_management_usage_test/kibana.json | 1 + 98 files changed, 506 insertions(+), 108 deletions(-) diff --git a/dev_docs/key_concepts/anatomy_of_a_plugin.mdx b/dev_docs/key_concepts/anatomy_of_a_plugin.mdx index fa0aae2299bb0..b22bc6f101998 100644 --- a/dev_docs/key_concepts/anatomy_of_a_plugin.mdx +++ b/dev_docs/key_concepts/anatomy_of_a_plugin.mdx @@ -75,7 +75,7 @@ plugins/ - preboot plugins are bootstrapped to prepare the environment before Kibana starts. - standard plugins define Kibana functionality while Kibana is running. -`owner` - [Required] Help users of your plugin know who manages this plugin and how to get in touch. This is required for internal plugins. `Owner.name` should be the name of the team that manages this plugin. This should match the team that owns this code in the [CODEOWNERS](https://github.com/elastic/kibana/blob/master/.github/CODEOWNERS) file (however, this is not currently enforced). Internal teams should also use a [GitHub team alias](https://github.com/orgs/elastic/teams) for `owner.githubTeam`. While many teams can contribute to a plugin, only a single team should be the primary owner. +`owner` - [Required] Help users of your plugin know who manages this plugin and how to get in touch. For internal developers, `Owner.name` should be the name of the team that manages this plugin. This should match the team that owns this code in the [CODEOWNERS](https://github.com/elastic/kibana/blob/master/.github/CODEOWNERS) file (however, this is not currently enforced). Internal teams should also use a [GitHub team alias](https://github.com/orgs/elastic/teams) for `owner.githubTeam`. This value is used to create a link to `https://github.com/orgs/elastic/teams/${githubTeam}`, so leave the `elastic/` prefix should be left out. While many teams can contribute to a plugin, only a single team should be the primary owner. `description` - [Required] Give your plugin a description to help other developers understand what it does. This is required for internal plugins. diff --git a/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md index f8d4c3f1b9d15..e82599c11f51a 100644 --- a/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md +++ b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md @@ -26,7 +26,7 @@ Should never be used in code outside of Core but is exported for documentation p | [id](./kibana-plugin-core-server.pluginmanifest.id.md) | PluginName | Identifier of the plugin. Must be a string in camelCase. Part of a plugin public contract. Other plugins leverage it to access plugin API, navigate to the plugin, etc. | | [kibanaVersion](./kibana-plugin-core-server.pluginmanifest.kibanaversion.md) | string | The version of Kibana the plugin is compatible with, defaults to "version". | | [optionalPlugins](./kibana-plugin-core-server.pluginmanifest.optionalplugins.md) | readonly PluginName[] | An optional list of the other plugins that if installed and enabled \*\*may be\*\* leveraged by this plugin for some additional functionality but otherwise are not required for this plugin to work properly. | -| [owner](./kibana-plugin-core-server.pluginmanifest.owner.md) | {
readonly name: string;
readonly githubTeam?: string;
} | TODO: make required once all internal plugins have this specified. | +| [owner](./kibana-plugin-core-server.pluginmanifest.owner.md) | {
readonly name: string;
readonly githubTeam?: string;
} | | | [requiredBundles](./kibana-plugin-core-server.pluginmanifest.requiredbundles.md) | readonly string[] | List of plugin ids that this plugin's UI code imports modules from that are not in requiredPlugins. | | [requiredPlugins](./kibana-plugin-core-server.pluginmanifest.requiredplugins.md) | readonly PluginName[] | An optional list of the other plugins that \*\*must be\*\* installed and enabled for this plugin to function properly. | | [server](./kibana-plugin-core-server.pluginmanifest.server.md) | boolean | Specifies whether plugin includes some server-side specific functionality. | diff --git a/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.owner.md b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.owner.md index a90af81aa186a..06b97a0313de5 100644 --- a/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.owner.md +++ b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.owner.md @@ -4,12 +4,10 @@ ## PluginManifest.owner property -TODO: make required once all internal plugins have this specified. - Signature: ```typescript -readonly owner?: { +readonly owner: { readonly name: string; readonly githubTeam?: string; }; diff --git a/packages/kbn-dev-utils/src/plugins/parse_kibana_platform_plugin.ts b/packages/kbn-dev-utils/src/plugins/parse_kibana_platform_plugin.ts index 62231f8221a95..c34192a8396e8 100644 --- a/packages/kbn-dev-utils/src/plugins/parse_kibana_platform_plugin.ts +++ b/packages/kbn-dev-utils/src/plugins/parse_kibana_platform_plugin.ts @@ -29,8 +29,7 @@ interface Manifest { server: boolean; kibanaVersion: string; version: string; - // TODO: make this required. - owner?: { + owner: { // Internally, this should be a team name. name: string; // All internally owned plugins should have a github team specified that can be pinged in issues, or used to look up @@ -64,6 +63,12 @@ export function parseKibanaPlatformPlugin(manifestPath: string): KibanaPlatformP throw new TypeError('expected new platform plugin manifest to have a string version'); } + if (!manifest.owner || typeof manifest.owner.name !== 'string') { + throw new TypeError( + `Expected plugin ${manifest.id} manifest to have an owner with name specified (${manifestPath})` + ); + } + return { directory: Path.dirname(manifestPath), manifestPath, diff --git a/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_mdx_docs.ts b/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_mdx_docs.ts index 557277331b099..1eb24e99e7dd8 100644 --- a/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_mdx_docs.ts +++ b/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_mdx_docs.ts @@ -86,8 +86,8 @@ import ${json} from './${fileName}.json'; ${plugin.manifest.description ?? ''} ${ - plugin.manifest.owner?.githubTeam && name - ? `Contact [${name}](https://github.com/orgs/elastic/teams/${plugin.manifest.owner?.githubTeam}) for questions regarding this plugin.` + plugin.manifest.owner.githubTeam && name + ? `Contact [${name}](https://github.com/orgs/elastic/teams/${plugin.manifest.owner.githubTeam}) for questions regarding this plugin.` : name ? `Contact ${name} for questions regarding this plugin.` : '' diff --git a/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/kibana.json b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/kibana.json index 84b46caa70802..585898d38dc32 100644 --- a/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/kibana.json +++ b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/kibana.json @@ -1,7 +1,7 @@ { - "id": "pluginA", - "summary": "This an example plugin for testing the api documentation system", - "version": "kibana", - "serviceFolders": ["foo"] - } - \ No newline at end of file + "id": "pluginA", + "owner": { "name": "Kibana Tech Leads" }, + "summary": "This an example plugin for testing the api documentation system", + "version": "kibana", + "serviceFolders": ["foo"] +} diff --git a/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_b/kibana.json b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_b/kibana.json index b526ffab90f7f..09413569c6571 100644 --- a/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_b/kibana.json +++ b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_b/kibana.json @@ -1,5 +1,6 @@ { "id": "pluginB", + "owner": { "name": "Kibana Tech Leads" }, "summary": "This an example plugin for testing the api documentation system", "version": "kibana" } diff --git a/packages/kbn-docs-utils/src/api_docs/tests/kibana_platform_plugin_mock.ts b/packages/kbn-docs-utils/src/api_docs/tests/kibana_platform_plugin_mock.ts index 9debca91b7ca8..08ddfb1ffd421 100644 --- a/packages/kbn-docs-utils/src/api_docs/tests/kibana_platform_plugin_mock.ts +++ b/packages/kbn-docs-utils/src/api_docs/tests/kibana_platform_plugin_mock.ts @@ -18,6 +18,9 @@ export function getKibanaPlatformPlugin(id: string, dir?: string): KibanaPlatfor server: true, kibanaVersion: '1', version: '1', + owner: { + name: 'Kibana Core', + }, serviceFolders: [], requiredPlugins: [], requiredBundles: [], diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/kibana.json b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/kibana.json index a5e9f34a22aa6..0aadeb1644fe8 100644 --- a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/kibana.json +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/kibana.json @@ -2,5 +2,8 @@ "id": "bar", "ui": true, "requiredBundles": ["foo"], - "version": "8.0.0" + "version": "8.0.0", + "owner": { + "name": "Operations" + } } diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/kibana.json b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/kibana.json index 27730df199887..ceea6483ab47a 100644 --- a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/kibana.json +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/kibana.json @@ -1,5 +1,8 @@ { "id": "foo", + "owner": { + "name": "Operations" + }, "ui": true, "version": "8.0.0" } diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/nested/baz/kibana.json b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/nested/baz/kibana.json index a8f991ee11465..f8b1bf6bcc39a 100644 --- a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/nested/baz/kibana.json +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/nested/baz/kibana.json @@ -1,4 +1,7 @@ { "id": "baz", + "owner": { + "name": "Operations" + }, "version": "8.0.0" } diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz/kibana.json b/packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz/kibana.json index d8a8b2e548e4a..e784007bce6d8 100644 --- a/packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz/kibana.json +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz/kibana.json @@ -1,4 +1,7 @@ { "id": "test_baz", + "owner": { + "name": "Operations" + }, "version": "8.0.0" } diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/x-pack/baz/kibana.json b/packages/kbn-optimizer/src/__fixtures__/mock_repo/x-pack/baz/kibana.json index 64ec7ff5ccf3e..d94123ae7ef02 100644 --- a/packages/kbn-optimizer/src/__fixtures__/mock_repo/x-pack/baz/kibana.json +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/x-pack/baz/kibana.json @@ -1,5 +1,6 @@ { "id": "baz", + "owner": { "name": "Operations", "githubTeam": "kibana-operations" }, "ui": true, "version": "8.0.0" } diff --git a/packages/kbn-plugin-generator/src/ask_questions.ts b/packages/kbn-plugin-generator/src/ask_questions.ts index ed41130c5c154..aeee8dfdbdad1 100644 --- a/packages/kbn-plugin-generator/src/ask_questions.ts +++ b/packages/kbn-plugin-generator/src/ask_questions.ts @@ -17,6 +17,9 @@ export interface Answers { internalLocation: string; ui: boolean; server: boolean; + githubTeam?: string; + ownerName: string; + description?: string; } export const INTERNAL_PLUGIN_LOCATIONS: Array<{ name: string; value: string }> = [ @@ -49,6 +52,11 @@ export const QUESTIONS = [ default: undefined, validate: (name: string) => (!name ? 'name is required' : true), }, + { + name: 'description', + message: 'Provide a description for your plugin.', + default: undefined, + }, { name: 'internal', type: 'confirm', @@ -63,6 +71,24 @@ export const QUESTIONS = [ default: INTERNAL_PLUGIN_LOCATIONS[0].value, when: ({ internal }: Answers) => internal, }, + { + name: 'ownerName', + message: 'Who is developing and maintaining this plugin?', + default: undefined, + when: ({ internal }: Answers) => !internal, + }, + { + name: 'ownerName', + message: 'What team will maintain this plugin?', + default: undefined, + when: ({ internal }: Answers) => internal, + }, + { + name: 'githubTeam', + message: 'What is your gitHub team alias?', + default: undefined, + when: ({ internal }: Answers) => internal, + }, { name: 'ui', type: 'confirm', diff --git a/packages/kbn-plugin-generator/src/render_template.ts b/packages/kbn-plugin-generator/src/render_template.ts index 1a9716f1f1ba5..ec09781b9a553 100644 --- a/packages/kbn-plugin-generator/src/render_template.ts +++ b/packages/kbn-plugin-generator/src/render_template.ts @@ -64,6 +64,10 @@ export async function renderTemplates({ hasServer: !!answers.server, hasUi: !!answers.ui, + ownerName: answers.ownerName, + githubTeam: answers.githubTeam, + description: answers.description, + camelCase, snakeCase, upperCamelCase, diff --git a/packages/kbn-plugin-generator/template/kibana.json.ejs b/packages/kbn-plugin-generator/template/kibana.json.ejs index 698a394e0d0b5..601a5e2cbeccd 100644 --- a/packages/kbn-plugin-generator/template/kibana.json.ejs +++ b/packages/kbn-plugin-generator/template/kibana.json.ejs @@ -2,6 +2,11 @@ "id": "<%= camelCase(name) %>", "version": "1.0.0", "kibanaVersion": "kibana", + "owner": { + "name": "<%= ownerName %>", + "githubTeam": "<%= githubTeam %>" + }, + "description": "<%= description %>", "server": <%= hasServer %>, "ui": <%= hasUi %>, "requiredPlugins": ["navigation"], diff --git a/packages/kbn-plugin-helpers/src/integration_tests/build.test.ts b/packages/kbn-plugin-helpers/src/integration_tests/build.test.ts index 9723c0107cf8e..65cbdaf88034c 100644 --- a/packages/kbn-plugin-helpers/src/integration_tests/build.test.ts +++ b/packages/kbn-plugin-helpers/src/integration_tests/build.test.ts @@ -101,9 +101,14 @@ it('builds a generated plugin into a viable archive', async () => { expect(loadJsonFile.sync(Path.resolve(TMP_DIR, 'kibana', 'fooTestPlugin', 'kibana.json'))) .toMatchInlineSnapshot(` Object { + "description": "", "id": "fooTestPlugin", "kibanaVersion": "7.5.0", "optionalPlugins": Array [], + "owner": Object { + "githubTeam": "", + "name": "", + }, "requiredPlugins": Array [ "navigation", ], diff --git a/src/core/public/plugins/plugin.test.ts b/src/core/public/plugins/plugin.test.ts index 94c88f732f4e1..8deef6ac9f727 100644 --- a/src/core/public/plugins/plugin.test.ts +++ b/src/core/public/plugins/plugin.test.ts @@ -24,6 +24,9 @@ function createManifest( requiredPlugins: required, optionalPlugins: optional, requiredBundles: [], + owner: { + name: 'foo', + }, } as DiscoveredPlugin; } diff --git a/src/core/public/plugins/plugins_service.test.ts b/src/core/public/plugins/plugins_service.test.ts index 06c72823c7752..d85f8538e3a69 100644 --- a/src/core/public/plugins/plugins_service.test.ts +++ b/src/core/public/plugins/plugins_service.test.ts @@ -64,6 +64,10 @@ function createManifest( requiredPlugins: required, optionalPlugins: optional, requiredBundles: [], + owner: { + name: 'Core', + githubTeam: 'kibana-core', + }, }; } diff --git a/src/core/server/plugins/discovery/plugin_manifest_parser.test.ts b/src/core/server/plugins/discovery/plugin_manifest_parser.test.ts index 3e410e4b19c0e..400b83dc0403f 100644 --- a/src/core/server/plugins/discovery/plugin_manifest_parser.test.ts +++ b/src/core/server/plugins/discovery/plugin_manifest_parser.test.ts @@ -65,7 +65,7 @@ test('return error when manifest content is not a valid JSON', async () => { test('return error when plugin id is missing', async () => { mockReadFile.mockImplementation((path, cb) => { - cb(null, Buffer.from(JSON.stringify({ version: 'some-version' }))); + cb(null, Buffer.from(JSON.stringify({ version: 'some-version', owner: { name: 'foo' } }))); }); await expect(parseManifest(pluginPath, packageInfo)).rejects.toMatchObject({ @@ -77,7 +77,12 @@ test('return error when plugin id is missing', async () => { test('return error when plugin id includes `.` characters', async () => { mockReadFile.mockImplementation((path, cb) => { - cb(null, Buffer.from(JSON.stringify({ id: 'some.name', version: 'some-version' }))); + cb( + null, + Buffer.from( + JSON.stringify({ id: 'some.name', version: 'some-version', owner: { name: 'foo' } }) + ) + ); }); await expect(parseManifest(pluginPath, packageInfo)).rejects.toMatchObject({ @@ -90,7 +95,12 @@ test('return error when plugin id includes `.` characters', async () => { test('return error when pluginId is not in camelCase format', async () => { expect.assertions(1); mockReadFile.mockImplementation((path, cb) => { - cb(null, Buffer.from(JSON.stringify({ id: 'some_name', version: 'kibana', server: true }))); + cb( + null, + Buffer.from( + JSON.stringify({ id: 'some_name', version: 'kibana', server: true, owner: { name: 'foo' } }) + ) + ); }); await expect(parseManifest(pluginPath, packageInfo)).rejects.toMatchObject({ @@ -102,7 +112,7 @@ test('return error when pluginId is not in camelCase format', async () => { test('return error when plugin version is missing', async () => { mockReadFile.mockImplementation((path, cb) => { - cb(null, Buffer.from(JSON.stringify({ id: 'someId' }))); + cb(null, Buffer.from(JSON.stringify({ id: 'someId', owner: { name: 'foo' } }))); }); await expect(parseManifest(pluginPath, packageInfo)).rejects.toMatchObject({ @@ -114,7 +124,10 @@ test('return error when plugin version is missing', async () => { test('return error when plugin expected Kibana version is lower than actual version', async () => { mockReadFile.mockImplementation((path, cb) => { - cb(null, Buffer.from(JSON.stringify({ id: 'someId', version: '6.4.2' }))); + cb( + null, + Buffer.from(JSON.stringify({ id: 'someId', version: '6.4.2', owner: { name: 'foo' } })) + ); }); await expect(parseManifest(pluginPath, packageInfo)).rejects.toMatchObject({ @@ -128,7 +141,14 @@ test('return error when plugin expected Kibana version cannot be interpreted as mockReadFile.mockImplementation((path, cb) => { cb( null, - Buffer.from(JSON.stringify({ id: 'someId', version: '1.0.0', kibanaVersion: 'non-sem-ver' })) + Buffer.from( + JSON.stringify({ + id: 'someId', + version: '1.0.0', + kibanaVersion: 'non-sem-ver', + owner: { name: 'foo' }, + }) + ) ); }); @@ -141,7 +161,12 @@ test('return error when plugin expected Kibana version cannot be interpreted as test('return error when plugin config path is not a string', async () => { mockReadFile.mockImplementation((path, cb) => { - cb(null, Buffer.from(JSON.stringify({ id: 'someId', version: '7.0.0', configPath: 2 }))); + cb( + null, + Buffer.from( + JSON.stringify({ id: 'someId', version: '7.0.0', configPath: 2, owner: { name: 'foo' } }) + ) + ); }); await expect(parseManifest(pluginPath, packageInfo)).rejects.toMatchObject({ @@ -155,7 +180,14 @@ test('return error when plugin config path is an array that contains non-string mockReadFile.mockImplementation((path, cb) => { cb( null, - Buffer.from(JSON.stringify({ id: 'someId', version: '7.0.0', configPath: ['config', 2] })) + Buffer.from( + JSON.stringify({ + id: 'someId', + version: '7.0.0', + configPath: ['config', 2], + owner: { name: 'foo' }, + }) + ) ); }); @@ -168,7 +200,10 @@ test('return error when plugin config path is an array that contains non-string test('return error when plugin expected Kibana version is higher than actual version', async () => { mockReadFile.mockImplementation((path, cb) => { - cb(null, Buffer.from(JSON.stringify({ id: 'someId', version: '7.0.1' }))); + cb( + null, + Buffer.from(JSON.stringify({ id: 'someId', version: '7.0.1', owner: { name: 'foo' } })) + ); }); await expect(parseManifest(pluginPath, packageInfo)).rejects.toMatchObject({ @@ -180,7 +215,10 @@ test('return error when plugin expected Kibana version is higher than actual ver test('return error when both `server` and `ui` are set to `false` or missing', async () => { mockReadFile.mockImplementation((path, cb) => { - cb(null, Buffer.from(JSON.stringify({ id: 'someId', version: '7.0.0' }))); + cb( + null, + Buffer.from(JSON.stringify({ id: 'someId', version: '7.0.0', owner: { name: 'foo' } })) + ); }); await expect(parseManifest(pluginPath, packageInfo)).rejects.toMatchObject({ @@ -192,7 +230,15 @@ test('return error when both `server` and `ui` are set to `false` or missing', a mockReadFile.mockImplementation((path, cb) => { cb( null, - Buffer.from(JSON.stringify({ id: 'someId', version: '7.0.0', server: false, ui: false })) + Buffer.from( + JSON.stringify({ + id: 'someId', + version: '7.0.0', + server: false, + ui: false, + owner: { name: 'foo' }, + }) + ) ); }); @@ -214,6 +260,7 @@ test('return error when manifest contains unrecognized properties', async () => server: true, unknownOne: 'one', unknownTwo: true, + owner: { name: 'foo' }, }) ) ); @@ -237,6 +284,7 @@ test('returns error when manifest contains unrecognized `type`', async () => { kibanaVersion: '7.0.0', type: 'unknown', server: true, + owner: { name: 'foo' }, }) ) ); @@ -252,7 +300,12 @@ test('returns error when manifest contains unrecognized `type`', async () => { describe('configPath', () => { test('falls back to plugin id if not specified', async () => { mockReadFile.mockImplementation((path, cb) => { - cb(null, Buffer.from(JSON.stringify({ id: 'plugin', version: '7.0.0', server: true }))); + cb( + null, + Buffer.from( + JSON.stringify({ id: 'plugin', version: '7.0.0', server: true, owner: { name: 'foo' } }) + ) + ); }); const manifest = await parseManifest(pluginPath, packageInfo); @@ -261,7 +314,12 @@ describe('configPath', () => { test('falls back to plugin id in snakeCase format', async () => { mockReadFile.mockImplementation((path, cb) => { - cb(null, Buffer.from(JSON.stringify({ id: 'someId', version: '7.0.0', server: true }))); + cb( + null, + Buffer.from( + JSON.stringify({ id: 'someId', version: '7.0.0', server: true, owner: { name: 'foo' } }) + ) + ); }); const manifest = await parseManifest(pluginPath, packageInfo); @@ -273,7 +331,13 @@ describe('configPath', () => { cb( null, Buffer.from( - JSON.stringify({ id: 'someId', configPath: 'somePath', version: '7.0.0', server: true }) + JSON.stringify({ + id: 'someId', + configPath: 'somePath', + version: '7.0.0', + server: true, + owner: { name: 'foo' }, + }) ) ); }); @@ -287,7 +351,13 @@ describe('configPath', () => { cb( null, Buffer.from( - JSON.stringify({ id: 'someId', configPath: ['somePath'], version: '7.0.0', server: true }) + JSON.stringify({ + id: 'someId', + configPath: ['somePath'], + version: '7.0.0', + server: true, + owner: { name: 'foo' }, + }) ) ); }); @@ -299,7 +369,12 @@ describe('configPath', () => { test('set defaults for all missing optional fields', async () => { mockReadFile.mockImplementation((path, cb) => { - cb(null, Buffer.from(JSON.stringify({ id: 'someId', version: '7.0.0', server: true }))); + cb( + null, + Buffer.from( + JSON.stringify({ id: 'someId', version: '7.0.0', server: true, owner: { name: 'foo' } }) + ) + ); }); await expect(parseManifest(pluginPath, packageInfo)).resolves.toEqual({ @@ -313,6 +388,7 @@ test('set defaults for all missing optional fields', async () => { requiredBundles: [], server: true, ui: false, + owner: { name: 'foo' }, }); }); @@ -330,6 +406,7 @@ test('return all set optional fields as they are in manifest', async () => { requiredPlugins: ['some-required-plugin', 'some-required-plugin-2'], optionalPlugins: ['some-optional-plugin'], ui: true, + owner: { name: 'foo' }, }) ) ); @@ -346,6 +423,7 @@ test('return all set optional fields as they are in manifest', async () => { requiredPlugins: ['some-required-plugin', 'some-required-plugin-2'], server: false, ui: true, + owner: { name: 'foo' }, }); }); @@ -361,6 +439,7 @@ test('return manifest when plugin expected Kibana version matches actual version kibanaVersion: '7.0.0-alpha2', requiredPlugins: ['some-required-plugin'], server: true, + owner: { name: 'foo' }, }) ) ); @@ -377,6 +456,7 @@ test('return manifest when plugin expected Kibana version matches actual version requiredBundles: [], server: true, ui: false, + owner: { name: 'foo' }, }); }); @@ -392,6 +472,7 @@ test('return manifest when plugin expected Kibana version is `kibana`', async () requiredPlugins: ['some-required-plugin'], server: true, ui: true, + owner: { name: 'foo' }, }) ) ); @@ -408,5 +489,6 @@ test('return manifest when plugin expected Kibana version is `kibana`', async () requiredBundles: [], server: true, ui: true, + owner: { name: 'foo' }, }); }); diff --git a/src/core/server/plugins/discovery/plugin_manifest_parser.ts b/src/core/server/plugins/discovery/plugin_manifest_parser.ts index 57640ec6acc0a..d5f96980eac23 100644 --- a/src/core/server/plugins/discovery/plugin_manifest_parser.ts +++ b/src/core/server/plugins/discovery/plugin_manifest_parser.ts @@ -121,6 +121,15 @@ export async function parseManifest( ); } + if (!manifest.owner || !manifest.owner.name || typeof manifest.owner.name !== 'string') { + throw PluginDiscoveryError.invalidManifest( + manifestPath, + new Error( + `Plugin manifest for "${manifest.id}" must contain an "owner" property, which includes a nested "name" property.` + ) + ); + } + if (manifest.configPath !== undefined && !isConfigPath(manifest.configPath)) { throw PluginDiscoveryError.invalidManifest( manifestPath, @@ -201,7 +210,7 @@ export async function parseManifest( ui: includesUiPlugin, server: includesServerPlugin, extraPublicDirs: manifest.extraPublicDirs, - owner: manifest.owner, + owner: manifest.owner!, description: manifest.description, }; } diff --git a/src/core/server/plugins/discovery/plugins_discovery.test.ts b/src/core/server/plugins/discovery/plugins_discovery.test.ts index 28f2ab799e092..15e53b0a34f7b 100644 --- a/src/core/server/plugins/discovery/plugins_discovery.test.ts +++ b/src/core/server/plugins/discovery/plugins_discovery.test.ts @@ -30,10 +30,23 @@ const Plugins = { 'kibana.json': 'not-json', }), incomplete: () => ({ - 'kibana.json': JSON.stringify({ version: '1' }), + 'kibana.json': JSON.stringify({ + version: '1', + owner: { + name: 'foo', + githubTeam: 'foo', + }, + }), }), incompatible: () => ({ - 'kibana.json': JSON.stringify({ id: 'plugin', version: '1' }), + 'kibana.json': JSON.stringify({ + id: 'plugin', + version: '1', + owner: { + name: 'foo', + githubTeam: 'foo', + }, + }), }), incompatibleType: (id: string) => ({ 'kibana.json': JSON.stringify({ @@ -42,6 +55,10 @@ const Plugins = { kibanaVersion: '1.2.3', type: 'evenEarlierThanPreboot', server: true, + owner: { + name: 'foo', + githubTeam: 'foo', + }, }), }), missingManifest: () => ({}), @@ -51,6 +68,17 @@ const Plugins = { content: JSON.stringify({ id: 'plugin', version: '1' }), }), }), + missingOwnerAttribute: () => ({ + 'kibana.json': JSON.stringify({ + id: 'foo', + configPath: ['plugins', 'foo'], + version: '1', + kibanaVersion: '1.2.3', + requiredPlugins: [], + optionalPlugins: [], + server: true, + }), + }), valid: (id: string) => ({ 'kibana.json': JSON.stringify({ id, @@ -60,6 +88,10 @@ const Plugins = { requiredPlugins: [], optionalPlugins: [], server: true, + owner: { + name: 'foo', + githubTeam: 'foo', + }, }), }), validPreboot: (id: string) => ({ @@ -72,6 +104,10 @@ const Plugins = { requiredPlugins: [], optionalPlugins: [], server: true, + owner: { + name: 'foo', + githubTeam: 'foo', + }, }), }), }; @@ -182,6 +218,7 @@ describe('plugins discovery system', () => { [`${KIBANA_ROOT}/src/plugins/plugin_c`]: Plugins.incompatible(), [`${KIBANA_ROOT}/src/plugins/plugin_d`]: Plugins.incompatibleType('pluginD'), [`${KIBANA_ROOT}/src/plugins/plugin_ad`]: Plugins.missingManifest(), + [`${KIBANA_ROOT}/src/plugins/plugin_e`]: Plugins.missingOwnerAttribute(), }, { createCwd: false } ); @@ -196,21 +233,40 @@ describe('plugins discovery system', () => { ) .toPromise(); - expect(errors).toEqual( - expect.arrayContaining([ - `Error: Unexpected token o in JSON at position 1 (invalid-manifest, ${manifestPath( - 'plugin_a' - )})`, - `Error: Plugin manifest must contain an "id" property. (invalid-manifest, ${manifestPath( - 'plugin_b' - )})`, - `Error: Plugin "plugin" is only compatible with Kibana version "1", but used Kibana version is "1.2.3". (incompatible-version, ${manifestPath( - 'plugin_c' - )})`, - `Error: The "type" in manifest for plugin "pluginD" is set to "evenEarlierThanPreboot", but it should either be "standard" or "preboot". (invalid-manifest, ${manifestPath( - 'plugin_d' - )})`, - ]) + expect(errors).toContain( + `Error: Unexpected token o in JSON at position 1 (invalid-manifest, ${manifestPath( + 'plugin_a' + )})` + ); + + expect(errors).toContain( + `Error: Plugin manifest must contain an "id" property. (invalid-manifest, ${manifestPath( + 'plugin_b' + )})` + ); + + expect(errors).toContain( + `Error: Plugin "plugin" is only compatible with Kibana version "1", but used Kibana version is "1.2.3". (incompatible-version, ${manifestPath( + 'plugin_c' + )})` + ); + + expect(errors).toContain( + `Error: The "type" in manifest for plugin "pluginD" is set to "evenEarlierThanPreboot", but it should either be "standard" or "preboot". (invalid-manifest, ${manifestPath( + 'plugin_d' + )})` + ); + + expect(errors).toContain( + `Error: The "type" in manifest for plugin "pluginD" is set to "evenEarlierThanPreboot", but it should either be "standard" or "preboot". (invalid-manifest, ${manifestPath( + 'plugin_d' + )})` + ); + + expect(errors).toContain( + `Error: Plugin manifest for "foo" must contain an "owner" property, which includes a nested "name" property. (invalid-manifest, ${manifestPath( + 'plugin_e' + )})` ); }); diff --git a/src/core/server/plugins/integration_tests/plugins_service.test.ts b/src/core/server/plugins/integration_tests/plugins_service.test.ts index 1b0caf7bf6255..4170d9422f277 100644 --- a/src/core/server/plugins/integration_tests/plugins_service.test.ts +++ b/src/core/server/plugins/integration_tests/plugins_service.test.ts @@ -42,6 +42,7 @@ describe('PluginsService', () => { configPath = [path], server = true, ui = true, + owner = { name: 'foo' }, }: { path?: string; disabled?: boolean; @@ -54,6 +55,7 @@ describe('PluginsService', () => { configPath?: ConfigPath; server?: boolean; ui?: boolean; + owner?: { name: string }; } ): PluginWrapper => { return new PluginWrapper({ @@ -69,6 +71,7 @@ describe('PluginsService', () => { optionalPlugins, server, ui, + owner, }, opaqueId: Symbol(id), initializerContext: { logger } as any, diff --git a/src/core/server/plugins/plugin.test.ts b/src/core/server/plugins/plugin.test.ts index 31706e01e4b84..513e893992005 100644 --- a/src/core/server/plugins/plugin.test.ts +++ b/src/core/server/plugins/plugin.test.ts @@ -56,6 +56,7 @@ function createPluginManifest(manifestProps: Partial = {}): Plug requiredBundles: [], server: true, ui: true, + owner: { name: 'Core' }, ...manifestProps, }; } diff --git a/src/core/server/plugins/plugin_context.test.ts b/src/core/server/plugins/plugin_context.test.ts index 7913bad3cad17..00da0fa43c40f 100644 --- a/src/core/server/plugins/plugin_context.test.ts +++ b/src/core/server/plugins/plugin_context.test.ts @@ -38,6 +38,10 @@ function createPluginManifest(manifestProps: Partial = {}): Plug optionalPlugins: ['some-optional-dep'], server: true, ui: true, + owner: { + name: 'Core', + githubTeam: 'kibana-core', + }, ...manifestProps, }; } diff --git a/src/core/server/plugins/plugins_service.test.ts b/src/core/server/plugins/plugins_service.test.ts index a9827dc60fb78..d45e7f9bf0bd0 100644 --- a/src/core/server/plugins/plugins_service.test.ts +++ b/src/core/server/plugins/plugins_service.test.ts @@ -101,6 +101,10 @@ const createPlugin = ( requiredBundles, optionalPlugins, server, + owner: { + name: 'Core', + githubTeam: 'kibana-core', + }, ui, }, opaqueId: Symbol(id), diff --git a/src/core/server/plugins/plugins_system.test.ts b/src/core/server/plugins/plugins_system.test.ts index e61c9c2002a12..4cd8e4c551bea 100644 --- a/src/core/server/plugins/plugins_system.test.ts +++ b/src/core/server/plugins/plugins_system.test.ts @@ -55,6 +55,7 @@ function createPlugin( requiredBundles: [], server, ui, + owner: { name: 'foo' }, }, opaqueId: Symbol(id), initializerContext: { logger } as any, diff --git a/src/core/server/plugins/types.ts b/src/core/server/plugins/types.ts index b0edcbdfd8677..a2e460a3e3c67 100644 --- a/src/core/server/plugins/types.ts +++ b/src/core/server/plugins/types.ts @@ -226,10 +226,7 @@ export interface PluginManifest { */ readonly serviceFolders?: readonly string[]; - /** - * TODO: make required once all internal plugins have this specified. - */ - readonly owner?: { + readonly owner: { /** * The name of the team that currently owns this plugin. */ diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index 67b08f4c0d9b7..b4f07bc393e25 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -1530,7 +1530,8 @@ export interface PluginManifest { readonly id: PluginName; readonly kibanaVersion: string; readonly optionalPlugins: readonly PluginName[]; - readonly owner?: { + // (undocumented) + readonly owner: { readonly name: string; readonly githubTeam?: string; }; @@ -2918,9 +2919,9 @@ export const validBodyOutput: readonly ["data", "stream"]; // // src/core/server/elasticsearch/client/types.ts:94:7 - (ae-forgotten-export) The symbol "Explanation" needs to be exported by the entry point index.d.ts // src/core/server/http/router/response.ts:301:3 - (ae-forgotten-export) The symbol "KibanaResponse" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:380:3 - (ae-forgotten-export) The symbol "KibanaConfigType" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:380:3 - (ae-forgotten-export) The symbol "SharedGlobalConfigKeys" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:383:3 - (ae-forgotten-export) The symbol "SavedObjectsConfigType" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:489:5 - (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "create" +// src/core/server/plugins/types.ts:377:3 - (ae-forgotten-export) The symbol "KibanaConfigType" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:377:3 - (ae-forgotten-export) The symbol "SharedGlobalConfigKeys" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:380:3 - (ae-forgotten-export) The symbol "SavedObjectsConfigType" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:486:5 - (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "create" ``` diff --git a/src/dev/code_coverage/ingest_coverage/integration_tests/fixtures/test_plugin/kibana.json b/src/dev/code_coverage/ingest_coverage/integration_tests/fixtures/test_plugin/kibana.json index cbb214b575701..1d94c5e22d29a 100644 --- a/src/dev/code_coverage/ingest_coverage/integration_tests/fixtures/test_plugin/kibana.json +++ b/src/dev/code_coverage/ingest_coverage/integration_tests/fixtures/test_plugin/kibana.json @@ -1,5 +1,9 @@ { "id": "codeCoverageTestPlugin", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "kibana", "server": true, "ui": false diff --git a/test/common/fixtures/plugins/coverage/kibana.json b/test/common/fixtures/plugins/coverage/kibana.json index d849db8d0583d..80afd40ba805f 100644 --- a/test/common/fixtures/plugins/coverage/kibana.json +++ b/test/common/fixtures/plugins/coverage/kibana.json @@ -1,6 +1,8 @@ { "id": "coverageFixtures", + "owner": { "name": "Kibana Operations", "githubTeam": "kibana-operations" }, "version": "kibana", "server": false, "ui": true -} \ No newline at end of file +} + diff --git a/test/common/fixtures/plugins/newsfeed/kibana.json b/test/common/fixtures/plugins/newsfeed/kibana.json index 0fbd24f45b684..b624f4b064995 100644 --- a/test/common/fixtures/plugins/newsfeed/kibana.json +++ b/test/common/fixtures/plugins/newsfeed/kibana.json @@ -1,5 +1,9 @@ { "id": "newsfeedFixtures", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "kibana", "server": true, "ui": false diff --git a/test/interpreter_functional/plugins/kbn_tp_run_pipeline/kibana.json b/test/interpreter_functional/plugins/kbn_tp_run_pipeline/kibana.json index 2fd2a9e5144d4..67316b1d0d7eb 100644 --- a/test/interpreter_functional/plugins/kbn_tp_run_pipeline/kibana.json +++ b/test/interpreter_functional/plugins/kbn_tp_run_pipeline/kibana.json @@ -1,16 +1,13 @@ { "id": "kbnTpRunPipeline", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", - "requiredPlugins": [ - "data", - "savedObjects", - "kibanaUtils", - "expressions" - ], + "requiredPlugins": ["data", "savedObjects", "kibanaUtils", "expressions"], "server": true, "ui": true, - "requiredBundles": [ - "inspector" - ] + "requiredBundles": ["inspector"] } diff --git a/test/plugin_functional/plugins/app_link_test/kibana.json b/test/plugin_functional/plugins/app_link_test/kibana.json index c37eae274460c..3e6d8c120a10b 100644 --- a/test/plugin_functional/plugins/app_link_test/kibana.json +++ b/test/plugin_functional/plugins/app_link_test/kibana.json @@ -1,5 +1,9 @@ { "id": "appLinkTest", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "server": false, diff --git a/test/plugin_functional/plugins/core_app_status/kibana.json b/test/plugin_functional/plugins/core_app_status/kibana.json index eb825cf9990c9..0c81e8169348a 100644 --- a/test/plugin_functional/plugins/core_app_status/kibana.json +++ b/test/plugin_functional/plugins/core_app_status/kibana.json @@ -1,5 +1,9 @@ { "id": "coreAppStatus", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["core_app_status"], diff --git a/test/plugin_functional/plugins/core_history_block/kibana.json b/test/plugin_functional/plugins/core_history_block/kibana.json index 6d2dda2b13225..189c79b1a76a0 100644 --- a/test/plugin_functional/plugins/core_history_block/kibana.json +++ b/test/plugin_functional/plugins/core_history_block/kibana.json @@ -1,5 +1,9 @@ { "id": "coreHistoryBlock", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "server": false, diff --git a/test/plugin_functional/plugins/core_http/kibana.json b/test/plugin_functional/plugins/core_http/kibana.json index 69855f59d64b7..6d0042d33f5ab 100644 --- a/test/plugin_functional/plugins/core_http/kibana.json +++ b/test/plugin_functional/plugins/core_http/kibana.json @@ -1,6 +1,10 @@ { "id": "coreHttp", "version": "0.0.1", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "kibanaVersion": "kibana", "configPath": ["core_http"], "server": true, diff --git a/test/plugin_functional/plugins/core_plugin_a/kibana.json b/test/plugin_functional/plugins/core_plugin_a/kibana.json index 9a153011bdc70..7914f0cc616cc 100644 --- a/test/plugin_functional/plugins/core_plugin_a/kibana.json +++ b/test/plugin_functional/plugins/core_plugin_a/kibana.json @@ -2,6 +2,10 @@ "id": "corePluginA", "version": "0.0.1", "kibanaVersion": "kibana", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "configPath": ["core_plugin_a"], "server": true, "ui": true diff --git a/test/plugin_functional/plugins/core_plugin_appleave/kibana.json b/test/plugin_functional/plugins/core_plugin_appleave/kibana.json index f9337fcc226f2..f51343e87ae33 100644 --- a/test/plugin_functional/plugins/core_plugin_appleave/kibana.json +++ b/test/plugin_functional/plugins/core_plugin_appleave/kibana.json @@ -1,6 +1,10 @@ { "id": "corePluginAppleave", "version": "0.0.1", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "kibanaVersion": "kibana", "configPath": ["core_plugin_appleave"], "server": false, diff --git a/test/plugin_functional/plugins/core_plugin_b/kibana.json b/test/plugin_functional/plugins/core_plugin_b/kibana.json index d132e714ea31d..bdcbb2660ed37 100644 --- a/test/plugin_functional/plugins/core_plugin_b/kibana.json +++ b/test/plugin_functional/plugins/core_plugin_b/kibana.json @@ -2,6 +2,10 @@ "id": "corePluginB", "version": "0.0.1", "kibanaVersion": "kibana", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "configPath": ["core_plugin_b"], "server": true, "ui": true, diff --git a/test/plugin_functional/plugins/core_plugin_chromeless/kibana.json b/test/plugin_functional/plugins/core_plugin_chromeless/kibana.json index 61863781b8f32..9c538a2a4bf27 100644 --- a/test/plugin_functional/plugins/core_plugin_chromeless/kibana.json +++ b/test/plugin_functional/plugins/core_plugin_chromeless/kibana.json @@ -1,5 +1,9 @@ { "id": "corePluginChromeless", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["core_plugin_chromeless"], diff --git a/test/plugin_functional/plugins/core_plugin_deep_links/kibana.json b/test/plugin_functional/plugins/core_plugin_deep_links/kibana.json index 539550974c563..8d7e15710d7f1 100644 --- a/test/plugin_functional/plugins/core_plugin_deep_links/kibana.json +++ b/test/plugin_functional/plugins/core_plugin_deep_links/kibana.json @@ -1,5 +1,9 @@ { "id": "corePluginDeepLinks", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["core_plugin_deep_links"], diff --git a/test/plugin_functional/plugins/core_plugin_deprecations/kibana.json b/test/plugin_functional/plugins/core_plugin_deprecations/kibana.json index bc251f97bea58..ace107cdc6a84 100644 --- a/test/plugin_functional/plugins/core_plugin_deprecations/kibana.json +++ b/test/plugin_functional/plugins/core_plugin_deprecations/kibana.json @@ -1,6 +1,10 @@ { "id": "corePluginDeprecations", "version": "0.0.1", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "kibanaVersion": "kibana", "configPath": ["corePluginDeprecations"], "server": true, diff --git a/test/plugin_functional/plugins/core_plugin_execution_context/kibana.json b/test/plugin_functional/plugins/core_plugin_execution_context/kibana.json index 625745202e39b..e6d7ed04d25b3 100644 --- a/test/plugin_functional/plugins/core_plugin_execution_context/kibana.json +++ b/test/plugin_functional/plugins/core_plugin_execution_context/kibana.json @@ -1,5 +1,9 @@ { "id": "corePluginExecutionContext", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["core_plugin_execution_context"], diff --git a/test/plugin_functional/plugins/core_plugin_helpmenu/kibana.json b/test/plugin_functional/plugins/core_plugin_helpmenu/kibana.json index 1b0f477ef34ae..84378c0b16a1b 100644 --- a/test/plugin_functional/plugins/core_plugin_helpmenu/kibana.json +++ b/test/plugin_functional/plugins/core_plugin_helpmenu/kibana.json @@ -1,5 +1,9 @@ { "id": "corePluginHelpmenu", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["core_plugin_helpmenu"], diff --git a/test/plugin_functional/plugins/core_plugin_route_timeouts/kibana.json b/test/plugin_functional/plugins/core_plugin_route_timeouts/kibana.json index 000f8e38a1035..935db895e4934 100644 --- a/test/plugin_functional/plugins/core_plugin_route_timeouts/kibana.json +++ b/test/plugin_functional/plugins/core_plugin_route_timeouts/kibana.json @@ -1,5 +1,9 @@ { "id": "corePluginRouteTimeouts", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["core_plugin_route_timeouts"], diff --git a/test/plugin_functional/plugins/core_plugin_static_assets/kibana.json b/test/plugin_functional/plugins/core_plugin_static_assets/kibana.json index 6f9fb94e9b49c..0aeefda84030b 100644 --- a/test/plugin_functional/plugins/core_plugin_static_assets/kibana.json +++ b/test/plugin_functional/plugins/core_plugin_static_assets/kibana.json @@ -1,5 +1,9 @@ { "id": "corePluginStaticAssets", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "server": false, diff --git a/test/plugin_functional/plugins/core_provider_plugin/kibana.json b/test/plugin_functional/plugins/core_provider_plugin/kibana.json index b3009b07de0a0..c5bfdfb6e1deb 100644 --- a/test/plugin_functional/plugins/core_provider_plugin/kibana.json +++ b/test/plugin_functional/plugins/core_provider_plugin/kibana.json @@ -1,14 +1,12 @@ { "id": "coreProviderPlugin", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", - "optionalPlugins": [ - "corePluginA", - "corePluginB", - "coreHttp", - "licensing", - "globalSearchTest" - ], + "optionalPlugins": ["corePluginA", "corePluginB", "coreHttp", "licensing", "globalSearchTest"], "server": false, "ui": true } diff --git a/test/plugin_functional/plugins/data_search/kibana.json b/test/plugin_functional/plugins/data_search/kibana.json index 28f7eb9996fc5..eadc4b71f3203 100644 --- a/test/plugin_functional/plugins/data_search/kibana.json +++ b/test/plugin_functional/plugins/data_search/kibana.json @@ -1,5 +1,9 @@ { "id": "dataSearchPlugin", + "owner": { + "name": "App Services", + "githubTeam": "kibana-app-services" + }, "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["data_search_test_plugin"], diff --git a/test/plugin_functional/plugins/elasticsearch_client_plugin/kibana.json b/test/plugin_functional/plugins/elasticsearch_client_plugin/kibana.json index 3d934414adc2f..cecc84a848ecc 100644 --- a/test/plugin_functional/plugins/elasticsearch_client_plugin/kibana.json +++ b/test/plugin_functional/plugins/elasticsearch_client_plugin/kibana.json @@ -1,5 +1,9 @@ { "id": "elasticsearchClientPlugin", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "server": true, diff --git a/test/plugin_functional/plugins/kbn_sample_panel_action/kibana.json b/test/plugin_functional/plugins/kbn_sample_panel_action/kibana.json index 51a254016b650..2cd9105764d50 100644 --- a/test/plugin_functional/plugins/kbn_sample_panel_action/kibana.json +++ b/test/plugin_functional/plugins/kbn_sample_panel_action/kibana.json @@ -1,5 +1,9 @@ { "id": "kbnSamplePanelAction", + "owner": { + "name": "App Services", + "githubTeam": "kibana-app-services" + }, "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["kbn_sample_panel_action"], diff --git a/test/plugin_functional/plugins/kbn_top_nav/kibana.json b/test/plugin_functional/plugins/kbn_top_nav/kibana.json index a656eae476b87..f7cf378d1fce3 100644 --- a/test/plugin_functional/plugins/kbn_top_nav/kibana.json +++ b/test/plugin_functional/plugins/kbn_top_nav/kibana.json @@ -1,5 +1,9 @@ { "id": "kbnTopNav", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["kbn_top_nav"], diff --git a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/kibana.json b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/kibana.json index 3e2d1c9e98fee..2bc636371fb0b 100644 --- a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/kibana.json +++ b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/kibana.json @@ -1,11 +1,12 @@ { "id": "kbnTpCustomVisualizations", + "owner": { + "name": "Kibana App", + "githubTeam": "kibana-app" + }, "version": "0.0.1", "kibanaVersion": "kibana", - "requiredPlugins": [ - "expressions", - "visualizations" - ], + "requiredPlugins": ["expressions", "visualizations"], "server": false, "ui": true } diff --git a/test/plugin_functional/plugins/management_test_plugin/kibana.json b/test/plugin_functional/plugins/management_test_plugin/kibana.json index f07c2ae997221..61cc1bae2fce7 100644 --- a/test/plugin_functional/plugins/management_test_plugin/kibana.json +++ b/test/plugin_functional/plugins/management_test_plugin/kibana.json @@ -1,5 +1,9 @@ { "id": "managementTestPlugin", + "owner": { + "name": "App Services", + "githubTeam": "kibana-app-services" + }, "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["management_test_plugin"], diff --git a/test/plugin_functional/plugins/rendering_plugin/kibana.json b/test/plugin_functional/plugins/rendering_plugin/kibana.json index f5f218db3c184..f3f5989cf530d 100644 --- a/test/plugin_functional/plugins/rendering_plugin/kibana.json +++ b/test/plugin_functional/plugins/rendering_plugin/kibana.json @@ -1,5 +1,9 @@ { "id": "renderingPlugin", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["rendering_plugin"], diff --git a/test/plugin_functional/plugins/saved_object_export_transforms/kibana.json b/test/plugin_functional/plugins/saved_object_export_transforms/kibana.json index 40b4c12f58e69..b4a6594f8736f 100644 --- a/test/plugin_functional/plugins/saved_object_export_transforms/kibana.json +++ b/test/plugin_functional/plugins/saved_object_export_transforms/kibana.json @@ -1,5 +1,9 @@ { "id": "savedObjectExportTransforms", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["saved_object_export_transforms"], diff --git a/test/plugin_functional/plugins/saved_object_import_warnings/kibana.json b/test/plugin_functional/plugins/saved_object_import_warnings/kibana.json index 947f840560eba..1449c8437b57b 100644 --- a/test/plugin_functional/plugins/saved_object_import_warnings/kibana.json +++ b/test/plugin_functional/plugins/saved_object_import_warnings/kibana.json @@ -1,5 +1,9 @@ { "id": "savedObjectImportWarnings", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["saved_object_import_warnings"], diff --git a/test/plugin_functional/plugins/saved_objects_hidden_type/kibana.json b/test/plugin_functional/plugins/saved_objects_hidden_type/kibana.json index baef662c695d4..9efabf2f54fcb 100644 --- a/test/plugin_functional/plugins/saved_objects_hidden_type/kibana.json +++ b/test/plugin_functional/plugins/saved_objects_hidden_type/kibana.json @@ -1,5 +1,9 @@ { "id": "savedObjectsHiddenType", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["saved_objects_hidden_type"], diff --git a/test/plugin_functional/plugins/session_notifications/kibana.json b/test/plugin_functional/plugins/session_notifications/kibana.json index 939a96e3f21d6..cab17564957dd 100644 --- a/test/plugin_functional/plugins/session_notifications/kibana.json +++ b/test/plugin_functional/plugins/session_notifications/kibana.json @@ -1,5 +1,9 @@ { "id": "sessionNotifications", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["session_notifications"], diff --git a/test/plugin_functional/plugins/telemetry/kibana.json b/test/plugin_functional/plugins/telemetry/kibana.json index 40a7d59d7dc2d..90d802a272e2a 100644 --- a/test/plugin_functional/plugins/telemetry/kibana.json +++ b/test/plugin_functional/plugins/telemetry/kibana.json @@ -1,5 +1,9 @@ { "id": "telemetryTestPlugin", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["telemetryTestPlugin"], diff --git a/test/plugin_functional/plugins/ui_settings_plugin/kibana.json b/test/plugin_functional/plugins/ui_settings_plugin/kibana.json index 459d995333eca..92eff06eaaf36 100644 --- a/test/plugin_functional/plugins/ui_settings_plugin/kibana.json +++ b/test/plugin_functional/plugins/ui_settings_plugin/kibana.json @@ -1,5 +1,9 @@ { "id": "uiSettingsPlugin", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["ui_settings_plugin"], diff --git a/test/plugin_functional/plugins/usage_collection/kibana.json b/test/plugin_functional/plugins/usage_collection/kibana.json index c98e3b95d389c..34e6ba9afb177 100644 --- a/test/plugin_functional/plugins/usage_collection/kibana.json +++ b/test/plugin_functional/plugins/usage_collection/kibana.json @@ -1,5 +1,9 @@ { "id": "usageCollectionTestPlugin", + "owner": { + "name": "Core", + "githubTeam": "kibana-core" + }, "version": "0.0.1", "kibanaVersion": "kibana", "configPath": ["usageCollectionTestPlugin"], diff --git a/test/server_integration/__fixtures__/plugins/status_plugin_a/kibana.json b/test/server_integration/__fixtures__/plugins/status_plugin_a/kibana.json index 36981d446c9f9..181ca0d8dc5e5 100644 --- a/test/server_integration/__fixtures__/plugins/status_plugin_a/kibana.json +++ b/test/server_integration/__fixtures__/plugins/status_plugin_a/kibana.json @@ -1,5 +1,6 @@ { "id": "statusPluginA", + "owner": { "name": "Core", "githubTeam": "kibana-core" }, "version": "0.0.1", "kibanaVersion": "kibana", "server": true, diff --git a/test/server_integration/__fixtures__/plugins/status_plugin_b/kibana.json b/test/server_integration/__fixtures__/plugins/status_plugin_b/kibana.json index fa02f42d500af..30b9060f9212e 100644 --- a/test/server_integration/__fixtures__/plugins/status_plugin_b/kibana.json +++ b/test/server_integration/__fixtures__/plugins/status_plugin_b/kibana.json @@ -1,5 +1,6 @@ { "id": "statusPluginB", + "owner": { "name": "Core", "githubTeam": "kibana-core" }, "version": "0.0.1", "kibanaVersion": "kibana", "server": true, diff --git a/x-pack/plugins/dashboard_enhanced/kibana.json b/x-pack/plugins/dashboard_enhanced/kibana.json index 0f2e790ff91ad..35f8e535eb336 100644 --- a/x-pack/plugins/dashboard_enhanced/kibana.json +++ b/x-pack/plugins/dashboard_enhanced/kibana.json @@ -1,23 +1,13 @@ { "id": "dashboardEnhanced", + "owner": { + "name": "App Services", + "githubTeam": "kibana-app-services" + }, "version": "kibana", "server": true, "ui": true, - "configPath": [ - "xpack", - "dashboardEnhanced" - ], - "requiredPlugins": [ - "dashboard", - "data", - "embeddable", - "share", - "uiActionsEnhanced" - ], - "requiredBundles": [ - "embeddable", - "embeddableEnhanced", - "kibanaReact", - "kibanaUtils" - ] + "configPath": ["xpack", "dashboardEnhanced"], + "requiredPlugins": ["dashboard", "data", "embeddable", "share", "uiActionsEnhanced"], + "requiredBundles": ["embeddable", "embeddableEnhanced", "kibanaReact", "kibanaUtils"] } diff --git a/x-pack/plugins/monitoring/kibana.json b/x-pack/plugins/monitoring/kibana.json index 0e02812af28fb..bf5e0ff2e16e3 100644 --- a/x-pack/plugins/monitoring/kibana.json +++ b/x-pack/plugins/monitoring/kibana.json @@ -3,7 +3,7 @@ "version": "8.0.0", "kibanaVersion": "kibana", "owner": { - "owner": "Stack Monitoring", + "name": "Stack Monitoring", "githubTeam": "stack-monitoring-ui" }, "configPath": ["monitoring"], diff --git a/x-pack/plugins/rule_registry/kibana.json b/x-pack/plugins/rule_registry/kibana.json index a750c4a91072a..75e0c2c8c0bac 100644 --- a/x-pack/plugins/rule_registry/kibana.json +++ b/x-pack/plugins/rule_registry/kibana.json @@ -1,5 +1,9 @@ { "id": "ruleRegistry", + "owner": { + "name": "RAC", + "githubTeam": "rac" + }, "version": "8.0.0", "kibanaVersion": "kibana", "configPath": ["xpack", "ruleRegistry"], diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/kibana.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/kibana.json index 6a43c7c74ad8c..016ba8eee281c 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/kibana.json +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/kibana.json @@ -1,5 +1,9 @@ { "id": "aadFixtures", + "owner": { + "name": "Alerting Services", + "githubTeam": "kibana-alerting-services" + }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["xpack"], diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/kibana.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/kibana.json index f63d6ef0d45ac..db7372d66b793 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/kibana.json +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/kibana.json @@ -1,5 +1,9 @@ { "id": "actionsSimulators", + "owner": { + "name": "Alerting Services", + "githubTeam": "kibana-alerting-services" + }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["xpack"], diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/kibana.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/kibana.json index bab4517850e91..63777d0c26629 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/kibana.json +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/kibana.json @@ -1,10 +1,14 @@ { "id": "alertsFixtures", + "owner": { + "name": "Alerting Services", + "githubTeam": "kibana-alerting-services" + }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["xpack"], "requiredPlugins": ["taskManager", "features", "actions", "alerting", "encryptedSavedObjects"], - "optionalPlugins": ["security", "spaces"], + "optionalPlugins": ["security", "spaces"], "server": true, "ui": false } diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts_restricted/kibana.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts_restricted/kibana.json index b61ec79541665..f12f8c3c205aa 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts_restricted/kibana.json +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts_restricted/kibana.json @@ -1,5 +1,9 @@ { "id": "alertsRestrictedFixtures", + "owner": { + "name": "Alerting Services", + "githubTeam": "kibana-alerting-services" + }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["xpack"], diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/kibana.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/kibana.json index 2f8117163471d..6d21226db4994 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/kibana.json +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager_fixture/kibana.json @@ -1,5 +1,9 @@ { "id": "taskManagerFixture", + "owner": { + "name": "Alerting Services", + "githubTeam": "kibana-alerting-services" + }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["xpack"], diff --git a/x-pack/test/case_api_integration/common/fixtures/plugins/cases_client_user/kibana.json b/x-pack/test/case_api_integration/common/fixtures/plugins/cases_client_user/kibana.json index 21dd9a58ffaad..22312e27bb1d3 100644 --- a/x-pack/test/case_api_integration/common/fixtures/plugins/cases_client_user/kibana.json +++ b/x-pack/test/case_api_integration/common/fixtures/plugins/cases_client_user/kibana.json @@ -1,10 +1,14 @@ { "id": "casesClientUserFixture", + "owner": { + "githubTeam": "security-threat-hunting", + "name": "Security Solution Threat Hunting" + }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["xpack"], "requiredPlugins": ["features", "cases"], - "optionalPlugins": ["security", "spaces"], + "optionalPlugins": ["security", "spaces"], "server": true, "ui": false } diff --git a/x-pack/test/case_api_integration/common/fixtures/plugins/observability/kibana.json b/x-pack/test/case_api_integration/common/fixtures/plugins/observability/kibana.json index 5115f4e3a0d3b..afc0cd39734e3 100644 --- a/x-pack/test/case_api_integration/common/fixtures/plugins/observability/kibana.json +++ b/x-pack/test/case_api_integration/common/fixtures/plugins/observability/kibana.json @@ -1,10 +1,14 @@ { "id": "observabilityFixtures", + "owner": { + "githubTeam": "security-threat-hunting", + "name": "Security Solution Threat Hunting" + }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["xpack"], "requiredPlugins": ["features", "cases"], - "optionalPlugins": ["security", "spaces"], + "optionalPlugins": ["security", "spaces"], "server": true, "ui": false } diff --git a/x-pack/test/case_api_integration/common/fixtures/plugins/security_solution/kibana.json b/x-pack/test/case_api_integration/common/fixtures/plugins/security_solution/kibana.json index cdef22263b01e..8368ed83efaa1 100644 --- a/x-pack/test/case_api_integration/common/fixtures/plugins/security_solution/kibana.json +++ b/x-pack/test/case_api_integration/common/fixtures/plugins/security_solution/kibana.json @@ -1,10 +1,14 @@ { "id": "securitySolutionFixtures", + "owner": { + "githubTeam": "security-threat-hunting", + "name": "Security Solution Threat Hunting" + }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["xpack"], "requiredPlugins": ["features", "cases"], - "optionalPlugins": ["security", "spaces"], + "optionalPlugins": ["security", "spaces"], "server": true, "ui": false } diff --git a/x-pack/test/cloud_integration/fixtures/saml/saml_provider/kibana.json b/x-pack/test/cloud_integration/fixtures/saml/saml_provider/kibana.json index 81ec23fc3d2f3..e753a315a5a70 100644 --- a/x-pack/test/cloud_integration/fixtures/saml/saml_provider/kibana.json +++ b/x-pack/test/cloud_integration/fixtures/saml/saml_provider/kibana.json @@ -1,5 +1,6 @@ { "id": "samlProviderPlugin", + "owner": { "name": "Core", "githubTeam": "kibana-core" }, "version": "8.0.0", "kibanaVersion": "kibana", "server": true, diff --git a/x-pack/test/encrypted_saved_objects_api_integration/fixtures/api_consumer_plugin/kibana.json b/x-pack/test/encrypted_saved_objects_api_integration/fixtures/api_consumer_plugin/kibana.json index 92449d0136ce5..1de42cf70cb23 100644 --- a/x-pack/test/encrypted_saved_objects_api_integration/fixtures/api_consumer_plugin/kibana.json +++ b/x-pack/test/encrypted_saved_objects_api_integration/fixtures/api_consumer_plugin/kibana.json @@ -1,5 +1,6 @@ { "id": "eso", + "owner": { "name": "Platform Security", "githubTeam": "kibana-security" }, "version": "8.0.0", "kibanaVersion": "kibana", "requiredPlugins": ["encryptedSavedObjects", "spaces"], diff --git a/x-pack/test/functional_cors/plugins/kibana_cors_test/kibana.json b/x-pack/test/functional_cors/plugins/kibana_cors_test/kibana.json index a0ebde9bff4b7..fa35253b9a46e 100644 --- a/x-pack/test/functional_cors/plugins/kibana_cors_test/kibana.json +++ b/x-pack/test/functional_cors/plugins/kibana_cors_test/kibana.json @@ -1,5 +1,6 @@ { "id": "kibanaCorsTest", + "owner": { "name": "Platform Security", "githubTeam": "kibana-security" }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["test", "cors"], diff --git a/x-pack/test/functional_embedded/plugins/iframe_embedded/kibana.json b/x-pack/test/functional_embedded/plugins/iframe_embedded/kibana.json index 919b7f69d28b9..4e31ecac3974a 100644 --- a/x-pack/test/functional_embedded/plugins/iframe_embedded/kibana.json +++ b/x-pack/test/functional_embedded/plugins/iframe_embedded/kibana.json @@ -1,5 +1,6 @@ { "id": "iframeEmbedded", + "owner": { "name": "Core", "githubTeam": "kibana-core" }, "version": "1.0.0", "kibanaVersion": "kibana", "server": true, diff --git a/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/kibana.json b/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/kibana.json index 4e2cae8d8ebff..717fe9966be39 100644 --- a/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/kibana.json +++ b/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/kibana.json @@ -1,5 +1,6 @@ { "id": "alertingFixture", + "owner": { "name": "Alerting Services", "githubTeam": "kibana-alerting-services" }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["xpack"], diff --git a/x-pack/test/licensing_plugin/plugins/test_feature_usage/kibana.json b/x-pack/test/licensing_plugin/plugins/test_feature_usage/kibana.json index aedbf95539736..55823ffb2da97 100644 --- a/x-pack/test/licensing_plugin/plugins/test_feature_usage/kibana.json +++ b/x-pack/test/licensing_plugin/plugins/test_feature_usage/kibana.json @@ -1,5 +1,6 @@ { "id": "testFeatureUsage", + "owner": { "name": "Platform Security", "githubTeam": "kibana-security" }, "version": "kibana", "server": false, "ui": true, diff --git a/x-pack/test/plugin_api_integration/plugins/elasticsearch_client/kibana.json b/x-pack/test/plugin_api_integration/plugins/elasticsearch_client/kibana.json index 5f4cb3f7f7eb2..0ca249c2931b4 100644 --- a/x-pack/test/plugin_api_integration/plugins/elasticsearch_client/kibana.json +++ b/x-pack/test/plugin_api_integration/plugins/elasticsearch_client/kibana.json @@ -1,5 +1,6 @@ { "id": "elasticsearchClientXpack", + "owner": { "name": "Core", "githubTeam": "kibana-core" }, "version": "1.0.0", "kibanaVersion": "kibana", "server": true, diff --git a/x-pack/test/plugin_api_integration/plugins/event_log/kibana.json b/x-pack/test/plugin_api_integration/plugins/event_log/kibana.json index 4c940ffec1463..7ba0617010112 100644 --- a/x-pack/test/plugin_api_integration/plugins/event_log/kibana.json +++ b/x-pack/test/plugin_api_integration/plugins/event_log/kibana.json @@ -1,5 +1,9 @@ { "id": "eventLogFixture", + "owner": { + "name": "Kibana Alerting", + "githubTeam": "kibana-alerting-services" + }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["xpack"], diff --git a/x-pack/test/plugin_api_integration/plugins/feature_usage_test/kibana.json b/x-pack/test/plugin_api_integration/plugins/feature_usage_test/kibana.json index b81f96362e9f5..71e62b4ed44d5 100644 --- a/x-pack/test/plugin_api_integration/plugins/feature_usage_test/kibana.json +++ b/x-pack/test/plugin_api_integration/plugins/feature_usage_test/kibana.json @@ -1,5 +1,9 @@ { "id": "featureUsageTest", + "owner": { + "name": "Platform Security", + "githubTeam": "kibana-security" + }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["xpack", "feature_usage_test"], diff --git a/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/kibana.json b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/kibana.json index 6a8a2221b48d3..7a9fd345739a0 100644 --- a/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/kibana.json +++ b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/kibana.json @@ -1,5 +1,9 @@ { "id": "sampleTaskPlugin", + "owner": { + "name": "Alerting Services", + "githubTeam": "kibana-alerting-services" + }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["xpack"], diff --git a/x-pack/test/plugin_api_perf/plugins/task_manager_performance/kibana.json b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/kibana.json index 387f392c8db98..1cc106fd95b36 100644 --- a/x-pack/test/plugin_api_perf/plugins/task_manager_performance/kibana.json +++ b/x-pack/test/plugin_api_perf/plugins/task_manager_performance/kibana.json @@ -1,5 +1,6 @@ { "id": "taskManagerPerformance", + "owner": { "name": "Alerting Services", "githubTeam": "kibana-alerting-services" }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["xpack"], diff --git a/x-pack/test/plugin_functional/plugins/global_search_test/kibana.json b/x-pack/test/plugin_functional/plugins/global_search_test/kibana.json index e081b47760b99..863ac116ae250 100644 --- a/x-pack/test/plugin_functional/plugins/global_search_test/kibana.json +++ b/x-pack/test/plugin_functional/plugins/global_search_test/kibana.json @@ -1,5 +1,6 @@ { "id": "globalSearchTest", + "owner": { "name": "Core", "githubTeam": "kibana-core" }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["xpack", "global_search_test"], diff --git a/x-pack/test/plugin_functional/plugins/resolver_test/kibana.json b/x-pack/test/plugin_functional/plugins/resolver_test/kibana.json index a203705e13ed6..7874e49b6d02b 100644 --- a/x-pack/test/plugin_functional/plugins/resolver_test/kibana.json +++ b/x-pack/test/plugin_functional/plugins/resolver_test/kibana.json @@ -1,14 +1,14 @@ { "id": "resolverTest", + "owner": { + "githubTeam": "security-threat-hunting", + "name": "Security Solution Threat Hunting" + }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["xpack", "resolverTest"], - "requiredPlugins": [ - "securitySolution" - ], - "requiredBundles": [ - "kibanaReact" - ], + "requiredPlugins": ["securitySolution"], + "requiredBundles": ["kibanaReact"], "server": false, "ui": true } diff --git a/x-pack/test/plugin_functional/plugins/timelines_test/kibana.json b/x-pack/test/plugin_functional/plugins/timelines_test/kibana.json index e6465142d4b5d..f96e8b2bbcc23 100644 --- a/x-pack/test/plugin_functional/plugins/timelines_test/kibana.json +++ b/x-pack/test/plugin_functional/plugins/timelines_test/kibana.json @@ -1,5 +1,6 @@ { "id": "timelinesTest", + "owner": { "name": "Security solution", "githubTeam": "security-solution" }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["xpack", "timelinesTest"], diff --git a/x-pack/test/saved_object_api_integration/common/fixtures/saved_object_test_plugin/kibana.json b/x-pack/test/saved_object_api_integration/common/fixtures/saved_object_test_plugin/kibana.json index 55cd29686fdef..fea1c591889b8 100644 --- a/x-pack/test/saved_object_api_integration/common/fixtures/saved_object_test_plugin/kibana.json +++ b/x-pack/test/saved_object_api_integration/common/fixtures/saved_object_test_plugin/kibana.json @@ -1,5 +1,6 @@ { "id": "savedObjectTestPlugin", + "owner": { "name": "Platform Security", "githubTeam": "kibana-security" }, "version": "kibana", "server": true, "ui": false diff --git a/x-pack/test/security_api_integration/fixtures/audit/audit_log/kibana.json b/x-pack/test/security_api_integration/fixtures/audit/audit_log/kibana.json index fbec5108ee484..d308e349543b6 100644 --- a/x-pack/test/security_api_integration/fixtures/audit/audit_log/kibana.json +++ b/x-pack/test/security_api_integration/fixtures/audit/audit_log/kibana.json @@ -1,5 +1,6 @@ { "id": "auditLog", + "owner": { "name": "Platform Security", "githubTeam": "kibana-security" }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": [], diff --git a/x-pack/test/security_api_integration/fixtures/oidc/oidc_provider/kibana.json b/x-pack/test/security_api_integration/fixtures/oidc/oidc_provider/kibana.json index aa7cd499a173a..9979b626768fa 100644 --- a/x-pack/test/security_api_integration/fixtures/oidc/oidc_provider/kibana.json +++ b/x-pack/test/security_api_integration/fixtures/oidc/oidc_provider/kibana.json @@ -1,5 +1,6 @@ { "id": "oidcProviderPlugin", + "owner": { "name": "Platform Security", "githubTeam": "kibana-security" }, "version": "8.0.0", "kibanaVersion": "kibana", "server": true, diff --git a/x-pack/test/security_api_integration/fixtures/saml/saml_provider/kibana.json b/x-pack/test/security_api_integration/fixtures/saml/saml_provider/kibana.json index 81ec23fc3d2f3..e753a315a5a70 100644 --- a/x-pack/test/security_api_integration/fixtures/saml/saml_provider/kibana.json +++ b/x-pack/test/security_api_integration/fixtures/saml/saml_provider/kibana.json @@ -1,5 +1,6 @@ { "id": "samlProviderPlugin", + "owner": { "name": "Core", "githubTeam": "kibana-core" }, "version": "8.0.0", "kibanaVersion": "kibana", "server": true, diff --git a/x-pack/test/security_functional/fixtures/common/test_endpoints/kibana.json b/x-pack/test/security_functional/fixtures/common/test_endpoints/kibana.json index 89b7725fe2b4e..71af8e99d3940 100644 --- a/x-pack/test/security_functional/fixtures/common/test_endpoints/kibana.json +++ b/x-pack/test/security_functional/fixtures/common/test_endpoints/kibana.json @@ -1,5 +1,6 @@ { "id": "securityTestEndpoints", + "owner": { "name": "Platform Security", "githubTeam": "kibana-security" }, "version": "8.0.0", "kibanaVersion": "kibana", "server": true, diff --git a/x-pack/test/spaces_api_integration/common/fixtures/spaces_test_plugin/kibana.json b/x-pack/test/spaces_api_integration/common/fixtures/spaces_test_plugin/kibana.json index a567e52031854..3bd95416184a6 100644 --- a/x-pack/test/spaces_api_integration/common/fixtures/spaces_test_plugin/kibana.json +++ b/x-pack/test/spaces_api_integration/common/fixtures/spaces_test_plugin/kibana.json @@ -1,5 +1,6 @@ { "id": "spacesTestPlugin", + "owner": { "name": "Platform Security", "githubTeam": "kibana-security" }, "version": "kibana", "server": true, "ui": false diff --git a/x-pack/test/ui_capabilities/common/fixtures/plugins/foo_plugin/kibana.json b/x-pack/test/ui_capabilities/common/fixtures/plugins/foo_plugin/kibana.json index 912cf5d70e16b..e2b5fffbe5108 100644 --- a/x-pack/test/ui_capabilities/common/fixtures/plugins/foo_plugin/kibana.json +++ b/x-pack/test/ui_capabilities/common/fixtures/plugins/foo_plugin/kibana.json @@ -1,5 +1,6 @@ { "id": "fooPlugin", + "owner": { "name": "Platform Security", "githubTeam": "kibana-security" }, "version": "1.0.0", "kibanaVersion": "kibana", "requiredPlugins": ["features"], diff --git a/x-pack/test/usage_collection/plugins/application_usage_test/kibana.json b/x-pack/test/usage_collection/plugins/application_usage_test/kibana.json index 1bff6cb64be1c..ab5dabeb0e5f6 100644 --- a/x-pack/test/usage_collection/plugins/application_usage_test/kibana.json +++ b/x-pack/test/usage_collection/plugins/application_usage_test/kibana.json @@ -1,5 +1,6 @@ { "id": "applicationUsageTest", + "owner": { "name": "Core", "githubTeam": "kibana-core" }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["xpack", "applicationUsageTest"], diff --git a/x-pack/test/usage_collection/plugins/stack_management_usage_test/kibana.json b/x-pack/test/usage_collection/plugins/stack_management_usage_test/kibana.json index c41fe744ca946..0b91b8dccde0f 100644 --- a/x-pack/test/usage_collection/plugins/stack_management_usage_test/kibana.json +++ b/x-pack/test/usage_collection/plugins/stack_management_usage_test/kibana.json @@ -1,5 +1,6 @@ { "id": "stackManagementUsageTest", + "owner": { "name": "Kibana Stack Management", "githubTeam": "kibana-stack-management" }, "version": "1.0.0", "kibanaVersion": "kibana", "configPath": ["xpack", "stackManagementUsageTest"], From ca86f769d73920a811c375004e699c027a11c141 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 24 Aug 2021 17:21:36 +0200 Subject: [PATCH 8/8] [ML] Fix tooltip text. --- .../app/correlations/failed_transactions_correlations.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/correlations/failed_transactions_correlations.tsx b/x-pack/plugins/apm/public/components/app/correlations/failed_transactions_correlations.tsx index 307dfc556672f..1e75bd2273848 100644 --- a/x-pack/plugins/apm/public/components/app/correlations/failed_transactions_correlations.tsx +++ b/x-pack/plugins/apm/public/components/app/correlations/failed_transactions_correlations.tsx @@ -146,7 +146,7 @@ export function FailedTransactionsCorrelations({ 'xpack.apm.correlations.failedTransactions.correlationsTable.failurePercentageDescription', { defaultMessage: - 'Percentage of time the term appear in failed transactions.', + 'Percentage of time the term appears in failed transactions.', } )} > @@ -179,7 +179,7 @@ export function FailedTransactionsCorrelations({ 'xpack.apm.correlations.failedTransactions.correlationsTable.successPercentageDescription', { defaultMessage: - 'Percentage of time the term appear in successful transactions.', + 'Percentage of time the term appears in successful transactions.', } )} >