From 5cc480a375cb6645920e5adc332cc7f126b1024b Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 2 Mar 2021 09:54:43 -0500 Subject: [PATCH 01/33] Improve consistency for display of management items (#92694) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../beats_management/public/bootstrap.tsx | 11 +++++++---- .../cross_cluster_replication/public/plugin.ts | 16 ++++++++++------ x-pack/plugins/watcher/public/plugin.ts | 16 ++++++++++++---- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/x-pack/plugins/beats_management/public/bootstrap.tsx b/x-pack/plugins/beats_management/public/bootstrap.tsx index 4a4d3a893286b..b5bdd39fa0817 100644 --- a/x-pack/plugins/beats_management/public/bootstrap.tsx +++ b/x-pack/plugins/beats_management/public/bootstrap.tsx @@ -18,10 +18,13 @@ import { BeatsManagementConfigType } from '../common'; import { MANAGEMENT_SECTION } from '../common/constants'; async function startApp(libs: FrontendLibs, core: CoreSetup) { - const [startServices] = await Promise.all([ - core.getStartServices(), - libs.framework.waitUntilFrameworkReady(), - ]); + const startServices = await core.getStartServices(); + + if (startServices[0].http.anonymousPaths.isAnonymous(window.location.pathname)) { + return; + } + // Can't run until the `start` lifecycle, so we wait for start services to resolve above before calling this. + await libs.framework.waitUntilFrameworkReady(); const capabilities = startServices[0].application.capabilities; const hasBeatsCapability = capabilities.management.ingest?.[MANAGEMENT_SECTION] ?? false; diff --git a/x-pack/plugins/cross_cluster_replication/public/plugin.ts b/x-pack/plugins/cross_cluster_replication/public/plugin.ts index 24c9d8dae379d..7998cdbdf750b 100644 --- a/x-pack/plugins/cross_cluster_replication/public/plugin.ts +++ b/x-pack/plugins/cross_cluster_replication/public/plugin.ts @@ -73,18 +73,21 @@ export class CrossClusterReplicationPlugin implements Plugin { // NOTE: We enable the plugin by default instead of disabling it by default because this // creates a race condition that causes functional tests to fail on CI (see #66781). - licensing.license$ - .pipe(first()) - .toPromise() - .then((license) => { + Promise.all([licensing.license$.pipe(first()).toPromise(), getStartServices()]).then( + ([license, startServices]) => { const licenseStatus = license.check(PLUGIN.ID, PLUGIN.minimumLicenseType); const isLicenseOk = licenseStatus.state === 'valid'; const config = this.initializerContext.config.get(); + const capabilities = startServices[0].application.capabilities; + // remoteClusters.isUiEnabled is driven by the xpack.remote_clusters.ui.enabled setting. // The CCR UI depends upon the Remote Clusters UI (e.g. by cross-linking to it), so if // the Remote Clusters UI is disabled we can't show the CCR UI. - const isCcrUiEnabled = config.ui.enabled && remoteClusters.isUiEnabled; + const isCcrUiEnabled = + capabilities.management.data?.[MANAGEMENT_ID] && + config.ui.enabled && + remoteClusters.isUiEnabled; if (isLicenseOk && isCcrUiEnabled) { if (indexManagement) { @@ -106,7 +109,8 @@ export class CrossClusterReplicationPlugin implements Plugin { } else { ccrApp.disable(); } - }); + } + ); } public start() {} diff --git a/x-pack/plugins/watcher/public/plugin.ts b/x-pack/plugins/watcher/public/plugin.ts index 9cc0b1bbe99a8..6c6d6f1169658 100644 --- a/x-pack/plugins/watcher/public/plugin.ts +++ b/x-pack/plugins/watcher/public/plugin.ts @@ -6,9 +6,10 @@ */ import { i18n } from '@kbn/i18n'; -import { CoreSetup, Plugin, CoreStart } from 'kibana/public'; +import { CoreSetup, Plugin, CoreStart, Capabilities } from 'kibana/public'; import { first, map, skip } from 'rxjs/operators'; +import { Subject, combineLatest } from 'rxjs'; import { FeatureCatalogueCategory } from '../../../../src/plugins/home/public'; import { LicenseStatus } from '../common/types/license_status'; @@ -26,6 +27,8 @@ const licenseToLicenseStatus = (license: ILicense): LicenseStatus => { }; export class WatcherUIPlugin implements Plugin { + private capabilities$: Subject = new Subject(); + setup( { notifications, http, uiSettings, getStartServices }: CoreSetup, { licensing, management, data, home, charts }: Dependencies @@ -99,13 +102,16 @@ export class WatcherUIPlugin implements Plugin { home.featureCatalogue.register(watcherHome); - licensing.license$.pipe(first(), map(licenseToLicenseStatus)).subscribe(({ valid }) => { + combineLatest([ + licensing.license$.pipe(first(), map(licenseToLicenseStatus)), + this.capabilities$, + ]).subscribe(([{ valid }, capabilities]) => { // NOTE: We enable the plugin by default instead of disabling it by default because this // creates a race condition that can cause the app nav item to not render in the side nav. // The race condition still exists, but it will result in the item rendering when it shouldn't // (e.g. on a license it's not available for), instead of *not* rendering when it *should*, // which is a less frustrating UX. - if (valid) { + if (valid && capabilities.management.insightsAndAlerting?.watcher === true) { watcherESApp.enable(); } else { watcherESApp.disable(); @@ -113,7 +119,9 @@ export class WatcherUIPlugin implements Plugin { }); } - start(core: CoreStart) {} + start(core: CoreStart) { + this.capabilities$.next(core.application.capabilities); + } stop() {} } From cce6861b893935f9005bc57d3fe7cd4f03aaa700 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Tue, 2 Mar 2021 16:00:11 +0100 Subject: [PATCH 02/33] [ILM] Allow multiple searchable snapshot actions (#92789) * remove logic that disables SS action in cold if no rollover and always show replicas field * update test coverage to be consistent with new form behaviour and expand hot phase without rollover test * only licensing can disable searchable snapshot field * clean up i18n * remove ss field callout * update error reporting logic to include causes chain, also update UI to show causes * updated searchable snapshot field in hot phase callout Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../errors/es_error_parser.ts | 6 ++--- .../errors/handle_es_error.ts | 11 +++++++- .../searchable_snapshot_field.tsx | 27 ++++--------------- .../public/application/services/api_errors.ts | 5 +++- .../translations/translations/ja-JP.json | 2 -- .../translations/translations/zh-CN.json | 2 -- 6 files changed, 22 insertions(+), 31 deletions(-) diff --git a/src/plugins/es_ui_shared/__packages_do_not_import__/errors/es_error_parser.ts b/src/plugins/es_ui_shared/__packages_do_not_import__/errors/es_error_parser.ts index 61a8882317f9f..fc400e4a87b3a 100644 --- a/src/plugins/es_ui_shared/__packages_do_not_import__/errors/es_error_parser.ts +++ b/src/plugins/es_ui_shared/__packages_do_not_import__/errors/es_error_parser.ts @@ -11,14 +11,14 @@ interface ParsedError { cause: string[]; } -const getCause = (obj: any = {}, causes: string[] = []): string[] => { +export const getEsCause = (obj: any = {}, causes: string[] = []): string[] => { const updated = [...causes]; if (obj.caused_by) { updated.push(obj.caused_by.reason); // Recursively find all the "caused by" reasons - return getCause(obj.caused_by, updated); + return getEsCause(obj.caused_by, updated); } return updated.filter(Boolean); @@ -27,7 +27,7 @@ const getCause = (obj: any = {}, causes: string[] = []): string[] => { export const parseEsError = (err: string): ParsedError => { try { const { error } = JSON.parse(err); - const cause = getCause(error); + const cause = getEsCause(error); return { message: error.reason, cause, diff --git a/src/plugins/es_ui_shared/__packages_do_not_import__/errors/handle_es_error.ts b/src/plugins/es_ui_shared/__packages_do_not_import__/errors/handle_es_error.ts index 4a45cff0b9604..a98a74375638d 100644 --- a/src/plugins/es_ui_shared/__packages_do_not_import__/errors/handle_es_error.ts +++ b/src/plugins/es_ui_shared/__packages_do_not_import__/errors/handle_es_error.ts @@ -9,6 +9,7 @@ import { ApiError } from '@elastic/elasticsearch'; import { ResponseError } from '@elastic/elasticsearch/lib/errors'; import { IKibanaResponse, KibanaResponseFactory } from 'kibana/server'; +import { getEsCause } from './es_error_parser'; interface EsErrorHandlerParams { error: ApiError; @@ -34,7 +35,15 @@ export const handleEsError = ({ const { statusCode, body } = error as ResponseError; return response.customError({ statusCode, - body: { message: body.error?.reason }, + body: { + message: body.error?.reason, + attributes: { + // The full original ES error object + error: body.error, + // We assume that this is an ES error object with a nested caused by chain if we can see the "caused_by" field at the top-level + causes: body.error?.caused_by ? getEsCause(body.error) : undefined, + }, + }, }); } // Case: default diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/searchable_snapshot_field/searchable_snapshot_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/searchable_snapshot_field/searchable_snapshot_field.tsx index 1a78149521e63..3fc7064575555 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/searchable_snapshot_field/searchable_snapshot_field.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/searchable_snapshot_field/searchable_snapshot_field.tsx @@ -61,9 +61,6 @@ export const SearchableSnapshotField: FunctionComponent = ({ phase }) => const isColdPhase = phase === 'cold'; const isDisabledDueToLicense = !license.canUseSearchableSnapshot(); - const isDisabledInColdDueToHotPhase = isColdPhase && isUsingSearchableSnapshotInHotPhase; - - const isDisabled = isDisabledDueToLicense || isDisabledInColdDueToHotPhase; const [isFieldToggleChecked, setIsFieldToggleChecked] = useState(() => Boolean( @@ -74,10 +71,10 @@ export const SearchableSnapshotField: FunctionComponent = ({ phase }) => ); useEffect(() => { - if (isDisabled) { + if (isDisabledDueToLicense) { setIsFieldToggleChecked(false); } - }, [isDisabled]); + }, [isDisabledDueToLicense]); const renderField = () => ( @@ -254,7 +251,7 @@ export const SearchableSnapshotField: FunctionComponent = ({ phase }) => 'xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotCalloutBody', { defaultMessage: - 'Force merge, shrink, freeze and cold phase searchable snapshots are not allowed when searchable snapshots are enabled in the hot phase.', + 'Force merge, shrink and freeze actions are not allowed when searchable snapshots are enabled in this phase.', } )} data-test-subj="searchableSnapshotFieldsDisabledCallout" @@ -278,20 +275,6 @@ export const SearchableSnapshotField: FunctionComponent = ({ phase }) => )} ); - } else if (isDisabledInColdDueToHotPhase) { - infoCallout = ( - - ); } return infoCallout ? ( @@ -308,7 +291,7 @@ export const SearchableSnapshotField: FunctionComponent = ({ phase }) => data-test-subj={`searchableSnapshotField-${phase}`} switchProps={{ checked: isFieldToggleChecked, - disabled: isDisabled, + disabled: isDisabledDueToLicense, onChange: setIsFieldToggleChecked, 'data-test-subj': 'searchableSnapshotToggle', label: i18n.translate( @@ -339,7 +322,7 @@ export const SearchableSnapshotField: FunctionComponent = ({ phase }) => fieldNotices={renderInfoCallout()} fullWidth > - {isDisabled ?
: renderField} + {isDisabledDueToLicense ?
: renderField} ); }; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/services/api_errors.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/api_errors.ts index 54ef91457b1f9..fc37b62e30eb2 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/services/api_errors.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/services/api_errors.ts @@ -11,7 +11,10 @@ import { fatalErrors, toasts } from './notification'; function createToastConfig(error: IHttpFetchError, errorTitle: string) { if (error && error.body) { // Error body shape is defined by the API. - const { error: errorString, statusCode, message } = error.body; + const { error: errorString, statusCode, message: errorMessage, attributes } = error.body; + const message = attributes?.causes?.length + ? attributes.causes[attributes.causes.length - 1] + : errorMessage; return { title: errorTitle, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 0fc467645bec8..dd628134c521e 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -9449,8 +9449,6 @@ "xpack.indexLifecycleMgmt.editPolicy.saveAsNewPolicyMessage": "新規ポリシーとして保存します", "xpack.indexLifecycleMgmt.editPolicy.saveButton": "ポリシーを保存", "xpack.indexLifecycleMgmt.editPolicy.saveErrorMessage": "ライフサイクルポリシー {lifecycleName} の保存中にエラーが発生しました", - "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotCalloutBody": "検索可能なスナップショットがホットフェーズで有効な場合には、強制、マージ、縮小、凍結、コールドフェーズの検索可能なスナップショットは許可されません。", - "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotDisabledCalloutBody": "ホットフェーズで構成されているときには、コールドフェーズで検索可能なスナップショットを作成できません。", "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotFieldDescription": "選択したリポジトリで管理されたインデックスのスナップショットを作成し、検索可能なスナップショットとしてマウントします。{learnMoreLink}。", "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotFieldLabel": "検索可能なスナップショットリポジドリ", "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotFieldTitle": "検索可能スナップショット", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index f6f58e06264e6..c733f214be554 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -9473,8 +9473,6 @@ "xpack.indexLifecycleMgmt.editPolicy.saveAsNewPolicyMessage": "另存为新策略", "xpack.indexLifecycleMgmt.editPolicy.saveButton": "保存策略", "xpack.indexLifecycleMgmt.editPolicy.saveErrorMessage": "保存生命周期策略 {lifecycleName} 时出错", - "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotCalloutBody": "在热阶段启用可搜索快照时,不允许强制合并、缩小、冻结可搜索快照以及将其置入冷阶段。", - "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotDisabledCalloutBody": "无法在冷阶段创建在热阶段配置的可搜索快照。", "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotFieldDescription": "在所选存储库中拍取受管索引的快照,并将其安装为可搜索快照。{learnMoreLink}。", "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotFieldLabel": "可搜索快照存储库", "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotFieldTitle": "可搜索快照", From 41b81a1011ee260d312e4ccaa55fc86b41444851 Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Tue, 2 Mar 2021 11:03:27 -0500 Subject: [PATCH 03/33] [Time to Visualize] Disable Visualize URL Tracker When Linked to OriginatingApp (#92917) * changed url tracker for visualize to not save when linked to originating app --- src/plugins/visualize/public/plugin.ts | 5 +---- .../dashboard/create_and_add_embeddables.ts | 4 ++-- .../apps/dashboard/edit_visualizations.js | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/plugins/visualize/public/plugin.ts b/src/plugins/visualize/public/plugin.ts index 300afd69c84cc..4b369e8be86ee 100644 --- a/src/plugins/visualize/public/plugin.ts +++ b/src/plugins/visualize/public/plugin.ts @@ -116,10 +116,7 @@ export class VisualizePlugin ], getHistory: () => this.currentHistory!, onBeforeNavLinkSaved: (urlToSave: string) => { - if ( - !urlToSave.includes(`${VisualizeConstants.EDIT_PATH}/`) && - this.isLinkedToOriginatingApp?.() - ) { + if (this.isLinkedToOriginatingApp?.()) { return core.http.basePath.prepend(VisualizeConstants.VISUALIZE_BASE_PATH); } return urlToSave; diff --git a/test/functional/apps/dashboard/create_and_add_embeddables.ts b/test/functional/apps/dashboard/create_and_add_embeddables.ts index c26b375a37b8f..f4ee4e9904768 100644 --- a/test/functional/apps/dashboard/create_and_add_embeddables.ts +++ b/test/functional/apps/dashboard/create_and_add_embeddables.ts @@ -69,10 +69,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.dashboard.waitForRenderComplete(); }); - it('saves the saved visualization url to the app link', async () => { + it('saves the listing page instead of the visualization to the app link', async () => { await PageObjects.header.clickVisualize(true); const currentUrl = await browser.getCurrentUrl(); - expect(currentUrl).to.contain(VisualizeConstants.EDIT_PATH); + expect(currentUrl).not.to.contain(VisualizeConstants.EDIT_PATH); }); after(async () => { diff --git a/test/functional/apps/dashboard/edit_visualizations.js b/test/functional/apps/dashboard/edit_visualizations.js index a918c017bd88f..d5df97881a1d3 100644 --- a/test/functional/apps/dashboard/edit_visualizations.js +++ b/test/functional/apps/dashboard/edit_visualizations.js @@ -109,6 +109,24 @@ export default function ({ getService, getPageObjects }) { expect(await testSubjects.exists('visualizationLandingPage')).to.be(true); }); + it('visualize app menu navigates to the visualize listing page if the last opened visualization was linked to dashboard', async () => { + await PageObjects.common.navigateToApp('dashboard'); + await PageObjects.dashboard.gotoDashboardLandingPage(); + await PageObjects.dashboard.clickNewDashboard(); + + // Create markdown by reference. + await createMarkdownVis('by reference'); + + // Edit then save and return + await editMarkdownVis(); + await PageObjects.visualize.saveVisualizationAndReturn(); + + await PageObjects.header.waitUntilLoadingHasFinished(); + await appsMenu.clickLink('Visualize Library'); + await PageObjects.common.clickConfirmOnModal(); + expect(await testSubjects.exists('visualizationLandingPage')).to.be(true); + }); + describe('by value', () => { it('save and return button returns to dashboard after editing visualization with changes saved', async () => { await PageObjects.common.navigateToApp('dashboard'); From 3d065739ea71f6fcaf4e142e5883f2b903f2daa5 Mon Sep 17 00:00:00 2001 From: Byron Hulcher Date: Tue, 2 Mar 2021 11:20:27 -0500 Subject: [PATCH 04/33] [App Search] Migrate Create Meta Engine View (#92127) * New empty MetaEngineCreation component * Added MetaEngineCreation to AppSearchConfigured router * Empty MetaEngineCreationLogic * Add rawName value and setRawName action to MetaEngineCreationLogic * Add indexedEngineNames value and setIndexedEngineNames action to MEtaEngineCreationLogic * Add selectedIndexedEngineNames value and setIndexedEngineNames action to MetaEngineCreationLogic * Add description to MetaEngineCreation * Add name selector to MetaEngineCreationLogic * Added MetaEngineCreationNameInput to MetaEngineCreation * Add fetchIndexedEngineNames listener to MetaEngineCreationLogic * Call fetchIndexedEngineNames when MetaEngineCreation first renders * Add EuiComboBox for selectedEngineNames to MetaEngineCreation * WIP Add meta engine source engine limit warning to MetaEngineCreation * Add submitEngine listener to MetaEngineCreationLogic * Add onEngineCreationSuccess to MetaEngineCreationLogic * Fixing tests for MetaEngineCreationLogic * Fix tests for MetaEngineCreation * Add Create a meta engine button to EnginesOverview * Use DEFAULT_META for fetching indexed engine names in MetaEngineCreationLogic * Copy fixes * Updating POST /api/engines tests * Add noItemsMessage prop to EnginesTable * Add empty prompt to Meta Engines table in EnginesOverview * Apply suggestions from code review Co-authored-by: Constance * Better form functionality in MetaEngineCreation * Fix errors from github * More MetaEngineCreation coverage * Meta MetaEngineCreationLogic coverage * Update x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation_logic.ts Co-authored-by: Constance * Update x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation_logic.ts Co-authored-by: Constance * Update x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts Co-authored-by: Constance Co-authored-by: Constance --- .../components/engines/constants.ts | 22 +++ .../engines/engines_overview.test.tsx | 46 ++++- .../components/engines/engines_overview.tsx | 53 ++++- .../components/engines/engines_table.test.tsx | 7 + .../components/engines/engines_table.tsx | 5 +- .../meta_engine_creation/constants.tsx | 119 +++++++++++ .../components/meta_engine_creation/index.ts | 8 + .../meta_engine_creation.test.tsx | 187 ++++++++++++++++++ .../meta_engine_creation.tsx | 170 ++++++++++++++++ .../meta_engine_creation_logic.test.ts | 175 ++++++++++++++++ .../meta_engine_creation_logic.ts | 127 ++++++++++++ .../applications/app_search/index.test.tsx | 17 ++ .../public/applications/app_search/index.tsx | 9 +- .../public/applications/app_search/routes.ts | 1 + .../server/routes/app_search/engines.test.ts | 63 ++++-- .../server/routes/app_search/engines.ts | 2 + 16 files changed, 981 insertions(+), 30 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/constants.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/index.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation_logic.test.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation_logic.ts diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts index 401d4ccd6d117..e0e36afa8e0c4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts @@ -22,3 +22,25 @@ export const CREATE_AN_ENGINE_BUTTON_LABEL = i18n.translate( defaultMessage: 'Create an engine', } ); + +export const CREATE_A_META_ENGINE_BUTTON_LABEL = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engines.createAMetaEngineButton.ButtonLabel', + { + defaultMessage: 'Create a meta engine', + } +); + +export const META_ENGINE_EMPTY_PROMPT_TITLE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engines.metaEngines.emptyPrompTitle', + { + defaultMessage: 'No meta engines yet', + } +); + +export const META_ENGINE_EMPTY_PROMPT_DESCRIPTION = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engines.metaEngines.emptyPromptDescription', + { + defaultMessage: + 'Meta engines allow you to combine multiple engines into one searchable engine.', + } +); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx index c25f27c81ff48..5a3f730940760 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx @@ -12,6 +12,8 @@ import React from 'react'; import { shallow, ShallowWrapper } from 'enzyme'; +import { EuiEmptyPrompt } from '@elastic/eui'; + import { LoadingState, EmptyState } from './components'; import { EnginesTable } from './engines_table'; @@ -19,7 +21,6 @@ import { EnginesOverview } from './'; describe('EnginesOverview', () => { const values = { - hasPlatinumLicense: false, dataLoading: false, engines: [], enginesMeta: { @@ -39,6 +40,7 @@ describe('EnginesOverview', () => { }, }, metaEnginesLoading: false, + hasPlatinumLicense: false, }; const actions = { loadEngines: jest.fn(), @@ -73,7 +75,7 @@ describe('EnginesOverview', () => { const valuesWithEngines = { ...values, dataLoading: false, - engines: ['dummy-engine'], + engines: ['test-engine'], enginesMeta: { page: { current: 1, @@ -84,6 +86,7 @@ describe('EnginesOverview', () => { }; beforeEach(() => { + jest.clearAllMocks(); setMockValues(valuesWithEngines); }); @@ -102,18 +105,47 @@ describe('EnginesOverview', () => { ).toEqual('/engine_creation'); }); - describe('when on a platinum license', () => { - it('renders a 2nd meta engines table & makes a 2nd meta engines API call', async () => { + describe('when user has a platinum license', () => { + let wrapper: ShallowWrapper; + + beforeEach(() => { setMockValues({ ...valuesWithEngines, hasPlatinumLicense: true, - metaEngines: ['dummy-meta-engine'], }); - const wrapper = shallow(); + wrapper = shallow(); + }); + it('renders a 2nd meta engines table ', async () => { expect(wrapper.find(EnginesTable)).toHaveLength(2); + }); + + it('makes a 2nd meta engines call', () => { expect(actions.loadMetaEngines).toHaveBeenCalled(); }); + + it('renders a create engine button which takes users to the create meta engine page', () => { + expect( + wrapper.find('[data-test-subj="appSearchEnginesMetaEngineCreationButton"]').prop('to') + ).toEqual('/meta_engine_creation'); + }); + + it('contains an EuiEmptyPrompt that takes users to the create meta when metaEngines is empty', () => { + setMockValues({ + ...valuesWithEngines, + hasPlatinumLicense: true, + metaEngines: [], + }); + wrapper = shallow(); + const metaEnginesTable = wrapper.find(EnginesTable).last().dive(); + const emptyPrompt = metaEnginesTable.dive().find(EuiEmptyPrompt).dive(); + + expect( + emptyPrompt + .find('[data-test-subj="appSearchMetaEnginesEmptyStateCreationButton"]') + .prop('to') + ).toEqual('/meta_engine_creation'); + }); }); describe('pagination', () => { @@ -150,7 +182,7 @@ describe('EnginesOverview', () => { setMockValues({ ...valuesWithEngines, hasPlatinumLicense: true, - metaEngines: ['dummy-meta-engine'], + metaEngines: ['test-meta-engine'], }); const wrapper = shallow(); const pageEvent = { page: { index: 0 } }; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx index a26fe87365536..4cfa5d9078162 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx @@ -16,6 +16,7 @@ import { EuiPageContentBody, EuiTitle, EuiSpacer, + EuiEmptyPrompt, } from '@elastic/eui'; import { FlashMessages } from '../../../shared/flash_messages'; @@ -24,12 +25,19 @@ import { LicensingLogic } from '../../../shared/licensing'; import { EuiButtonTo } from '../../../shared/react_router_helpers'; import { convertMetaToPagination, handlePageChange } from '../../../shared/table_pagination'; import { SendAppSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; -import { ENGINE_CREATION_PATH } from '../../routes'; +import { ENGINE_CREATION_PATH, META_ENGINE_CREATION_PATH } from '../../routes'; import { EngineIcon } from './assets/engine_icon'; import { MetaEngineIcon } from './assets/meta_engine_icon'; import { EnginesOverviewHeader, LoadingState, EmptyState } from './components'; -import { CREATE_AN_ENGINE_BUTTON_LABEL, ENGINES_TITLE, META_ENGINES_TITLE } from './constants'; +import { + CREATE_AN_ENGINE_BUTTON_LABEL, + CREATE_A_META_ENGINE_BUTTON_LABEL, + ENGINES_TITLE, + META_ENGINE_EMPTY_PROMPT_DESCRIPTION, + META_ENGINE_EMPTY_PROMPT_TITLE, + META_ENGINES_TITLE, +} from './constants'; import { EnginesLogic } from './engines_logic'; import { EnginesTable } from './engines_table'; @@ -37,6 +45,7 @@ import './engines_overview.scss'; export const EnginesOverview: React.FC = () => { const { hasPlatinumLicense } = useValues(LicensingLogic); + const { dataLoading, engines, @@ -46,6 +55,7 @@ export const EnginesOverview: React.FC = () => { metaEnginesMeta, metaEnginesLoading, } = useValues(EnginesLogic); + const { loadEngines, loadMetaEngines, onEnginesPagination, onMetaEnginesPagination } = useActions( EnginesLogic ); @@ -100,15 +110,27 @@ export const EnginesOverview: React.FC = () => { /> - {metaEngines.length > 0 && ( + {hasPlatinumLicense && ( <> - -

- {META_ENGINES_TITLE} -

-
+ + +

+ {META_ENGINES_TITLE} +

+
+
+ + + {CREATE_A_META_ENGINE_BUTTON_LABEL} + +
{ ...convertMetaToPagination(metaEnginesMeta), hidePerPageOptions: true, }} + noItemsMessage={ + {META_ENGINE_EMPTY_PROMPT_TITLE}} + body={

{META_ENGINE_EMPTY_PROMPT_DESCRIPTION}

} + actions={ + + {CREATE_A_META_ENGINE_BUTTON_LABEL} + + } + /> + } onChange={handlePageChange(onMetaEnginesPagination)} />
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.test.tsx index f8ad9bc6b2bc3..51c65e1478d13 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.test.tsx @@ -88,6 +88,13 @@ describe('EnginesTable', () => { }); }); + describe('noItemsMessage', () => { + it('passes the noItemsMessage prop', () => { + const wrapper = mountWithIntl(); + expect(wrapper.find(EuiBasicTable).prop('noItemsMessage')).toEqual('No items.'); + }); + }); + describe('language field', () => { it('renders language when available', () => { const wrapper = mountWithIntl( diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx index fe61ba8cbcc43..f542d12318244 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { ReactNode } from 'react'; import { useActions } from 'kea'; @@ -24,6 +24,7 @@ import { EngineDetails } from '../engine/types'; interface EnginesTableProps { items: EngineDetails[]; loading: boolean; + noItemsMessage?: ReactNode; pagination: { pageIndex: number; pageSize: number; @@ -36,6 +37,7 @@ interface EnginesTableProps { export const EnginesTable: React.FC = ({ items, loading, + noItemsMessage, pagination, onChange, }) => { @@ -148,6 +150,7 @@ export const EnginesTable: React.FC = ({ loading={loading} pagination={pagination} onChange={onChange} + noItemsMessage={noItemsMessage} /> ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/constants.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/constants.tsx new file mode 100644 index 0000000000000..aff5942d497a8 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/constants.tsx @@ -0,0 +1,119 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { EuiLink } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { DOCS_PREFIX } from '../../routes'; + +export const DEFAULT_LANGUAGE = 'Universal'; + +export const META_ENGINE_CREATION_TITLE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.title', + { + defaultMessage: 'Create a meta engine', + } +); + +export const META_ENGINE_CREATION_FORM_TITLE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.title', + { + defaultMessage: 'Name your meta engine', + } +); + +export const META_ENGINE_CREATION_FORM_SUBMIT_BUTTON_LABEL = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.submitButton.buttonLabel', + { + defaultMessage: 'Create meta engine', + } +); + +export const META_ENGINE_CREATION_FORM_META_ENGINE_DESCRIPTION = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.metaEngineDescription', + { + defaultMessage: + 'Meta engines allow you to combine multiple engines into one searchable engine.', + } +); + +export const META_ENGINE_CREATION_FORM_DOCUMENTATION_LINK = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.documentationLink', + { + defaultMessage: 'Read the documentation', + } +); + +export const META_ENGINE_CREATION_FORM_DOCUMENTATION_DESCRIPTION = ( + + {META_ENGINE_CREATION_FORM_DOCUMENTATION_LINK} + + ), + }} + /> +); + +export const META_ENGINE_CREATION_FORM_ENGINE_NAME_LABEL = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.engineName.label', + { + defaultMessage: 'Meta engine name', + } +); + +export const ALLOWED_CHARS_NOTE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.engineName.allowedCharactersHelpText', + { + defaultMessage: 'Meta engine names can only contain lowercase letters, numbers, and hyphens', + } +); + +export const SANITIZED_NAME_NOTE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.engineName.sanitizedNameHelpText', + { + defaultMessage: 'Your meta engine will be named', + } +); + +export const META_ENGINE_CREATION_FORM_ENGINE_NAME_PLACEHOLDER = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.engineName.placeholder', + { + defaultMessage: 'i.e., my-meta-engine', + } +); + +export const META_ENGINE_CREATION_FORM_ENGINE_SOURCE_ENGINES_LABEL = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.sourceEngines.label', + { + defaultMessage: 'Add source engines to this meta engine', + } +); + +export const META_ENGINE_CREATION_FORM_MAX_SOURCE_ENGINES_WARNING_TITLE = ( + maxEnginesPerMetaEngine: number +) => + i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.sourceEngines.maxSourceEnginesWarningTitle', + { + defaultMessage: 'Meta engines have a limit of {maxEnginesPerMetaEngine} source engines', + values: { maxEnginesPerMetaEngine }, + } + ); + +export const META_ENGINE_CREATION_SUCCESS_MESSAGE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.successMessage', + { + defaultMessage: 'Successfully created meta engine.', + } +); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/index.ts new file mode 100644 index 0000000000000..2d33322a84fc6 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { MetaEngineCreation } from './meta_engine_creation'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.test.tsx new file mode 100644 index 0000000000000..51ccc7b83b1fc --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.test.tsx @@ -0,0 +1,187 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import '../../../__mocks__/shallow_useeffect.mock'; +import { setMockActions, setMockValues } from '../../../__mocks__'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiCallOut } from '@elastic/eui'; + +import { MetaEngineCreation } from './'; + +const DEFAULT_VALUES = { + // MetaEngineLogic + name: 'test-meta-engine', + rawName: 'test-meta-engine', + indexedEngineNames: [], + selectedIndexedEngineNames: ['one'], + // AppLogic + configuredLimits: { engine: { maxEnginesPerMetaEngine: 10 } }, +}; + +const MOCK_ACTIONS = { + setRawName: jest.fn(), + setSelectedIndexedEngineNames: jest.fn(), + fetchIndexedEngineNames: jest.fn(), + submitEngine: jest.fn(), +}; + +describe('MetaEngineCreation', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(DEFAULT_VALUES); + setMockActions(MOCK_ACTIONS); + }); + + it('renders and calls fetchIndexedEngineNames', () => { + const wrapper = shallow(); + expect(wrapper.find('[data-test-subj="MetaEngineCreation"]')).toHaveLength(1); + expect(MOCK_ACTIONS.fetchIndexedEngineNames).toHaveBeenCalledTimes(1); + }); + + describe('MetaEngineCreationNameInput', () => { + it('uses rawName as its value', () => { + const wrapper = shallow(); + expect( + wrapper + .find('[data-test-subj="MetaEngineCreationNameInput"]') + .render() + .find('input') // as far as I can tell I can't include this input in the .find() two lines above + .attr('value') + ).toEqual('test-meta-engine'); + }); + + it('EngineCreationForm calls submitEngine on form submit', () => { + const wrapper = shallow(); + const simulatedEvent = { + preventDefault: jest.fn(), + }; + wrapper.find('[data-test-subj="MetaEngineCreationForm"]').simulate('submit', simulatedEvent); + + expect(MOCK_ACTIONS.submitEngine).toHaveBeenCalledTimes(1); + }); + + it('MetaEngineCreationNameInput calls setRawName on change', () => { + const wrapper = shallow(); + const simulatedEvent = { + currentTarget: { value: 'new-raw-name' }, + }; + wrapper + .find('[data-test-subj="MetaEngineCreationNameInput"]') + .simulate('change', simulatedEvent); + expect(MOCK_ACTIONS.setRawName).toHaveBeenCalledWith('new-raw-name'); + }); + }); + + describe('EngineCreationNameFormRow', () => { + it('renders sanitized name helptext when the raw name is being sanitized', () => { + setMockValues({ + ...DEFAULT_VALUES, + name: 'name-with-special-characters', + rawName: 'Name__With#$&*%Special--Characters', + }); + + const wrapper = shallow(); + const formRow = wrapper.find('[data-test-subj="MetaEngineCreationNameFormRow"]').dive(); + + expect(formRow.contains('Your meta engine will be named')).toBeTruthy(); + }); + + it('renders allowed character helptext when rawName and sanitizedName match', () => { + setMockValues({ + ...DEFAULT_VALUES, + name: 'name-without-special-characters', + rawName: 'name-without-special-characters', + }); + + const wrapper = shallow(); + const formRow = wrapper.find('[data-test-subj="MetaEngineCreationNameFormRow"]').dive(); + + expect( + formRow.contains( + 'Meta engine names can only contain lowercase letters, numbers, and hyphens' + ) + ).toBeTruthy(); + }); + }); + + it('MetaEngineCreationSourceEnginesInput calls calls setSelectedIndexedEngines on change', () => { + const wrapper = shallow(); + + wrapper + .find('[data-test-subj="MetaEngineCreationSourceEnginesInput"]') + .simulate('change', [{ label: 'foo', value: 'foo' }]); + + expect(MOCK_ACTIONS.setSelectedIndexedEngineNames).toHaveBeenCalledWith(['foo']); + }); + + it('renders a warning callout when user has selected too many engines', () => { + setMockValues({ + ...DEFAULT_VALUES, + ...{ + selectedIndexedEngineNames: ['one', 'two', 'three'], + configuredLimits: { engine: { maxEnginesPerMetaEngine: 2 } }, + }, + }); + const wrapper = shallow(); + + expect(wrapper.find(EuiCallOut).prop('title')).toContain('Meta engines have a limit of'); + }); + + describe('NewMetaEngineSubmitButton', () => { + it('is enabled for a valid submission', () => { + const wrapper = shallow(); + const submitButton = wrapper.find('[data-test-subj="NewMetaEngineSubmitButton"]'); + + expect(submitButton.prop('disabled')).toEqual(false); + }); + + it('is disabled when name is empty', () => { + setMockValues({ + ...DEFAULT_VALUES, + ...{ + name: '', + rawName: '', + }, + }); + const wrapper = shallow(); + const submitButton = wrapper.find('[data-test-subj="NewMetaEngineSubmitButton"]'); + + expect(submitButton.prop('disabled')).toEqual(true); + }); + + it('is disabled when user has selected no engines', () => { + setMockValues({ + ...DEFAULT_VALUES, + ...{ + selectedIndexedEngineNames: [], + }, + }); + const wrapper = shallow(); + const submitButton = wrapper.find('[data-test-subj="NewMetaEngineSubmitButton"]'); + + expect(submitButton.prop('disabled')).toEqual(true); + }); + + it('is disabled when user has selected too many engines', () => { + setMockValues({ + ...DEFAULT_VALUES, + ...{ + selectedIndexedEngineNames: ['one', 'two', 'three'], + configuredLimits: { engine: { maxEnginesPerMetaEngine: 2 } }, + }, + }); + const wrapper = shallow(); + const submitButton = wrapper.find('[data-test-subj="NewMetaEngineSubmitButton"]'); + + expect(submitButton.prop('disabled')).toEqual(true); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.tsx new file mode 100644 index 0000000000000..3757bbb533e57 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.tsx @@ -0,0 +1,170 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useEffect } from 'react'; + +import { useActions, useValues } from 'kea'; + +import { + EuiCallOut, + EuiComboBox, + EuiComboBoxOptionOption, + EuiForm, + EuiFlexGroup, + EuiFormRow, + EuiFlexItem, + EuiFieldText, + EuiPageContent, + EuiPageHeader, + EuiPageHeaderSection, + EuiSpacer, + EuiText, + EuiTitle, + EuiButton, +} from '@elastic/eui'; + +import { FlashMessages } from '../../../shared/flash_messages'; +import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; +import { AppLogic } from '../../app_logic'; + +import { + ALLOWED_CHARS_NOTE, + META_ENGINE_CREATION_FORM_DOCUMENTATION_DESCRIPTION, + META_ENGINE_CREATION_FORM_ENGINE_NAME_LABEL, + META_ENGINE_CREATION_FORM_ENGINE_NAME_PLACEHOLDER, + META_ENGINE_CREATION_FORM_ENGINE_SOURCE_ENGINES_LABEL, + META_ENGINE_CREATION_FORM_MAX_SOURCE_ENGINES_WARNING_TITLE, + META_ENGINE_CREATION_FORM_META_ENGINE_DESCRIPTION, + META_ENGINE_CREATION_FORM_SUBMIT_BUTTON_LABEL, + META_ENGINE_CREATION_FORM_TITLE, + META_ENGINE_CREATION_TITLE, + SANITIZED_NAME_NOTE, +} from './constants'; +import { MetaEngineCreationLogic } from './meta_engine_creation_logic'; + +const engineNameToComboBoxOption = (engineName: string): EuiComboBoxOptionOption => ({ + label: engineName, +}); + +const comboBoxOptionToEngineName = (option: EuiComboBoxOptionOption): string => + option.label; + +export const MetaEngineCreation: React.FC = () => { + const { + configuredLimits: { + engine: { maxEnginesPerMetaEngine } = { maxEnginesPerMetaEngine: Infinity }, + }, + } = useValues(AppLogic); + + const { + fetchIndexedEngineNames, + setRawName, + setSelectedIndexedEngineNames, + submitEngine, + } = useActions(MetaEngineCreationLogic); + + const { rawName, name, indexedEngineNames, selectedIndexedEngineNames } = useValues( + MetaEngineCreationLogic + ); + + useEffect(() => { + fetchIndexedEngineNames(); + }, []); + + return ( +
+ + + + +

{META_ENGINE_CREATION_TITLE}

+
+ {META_ENGINE_CREATION_FORM_META_ENGINE_DESCRIPTION} + {META_ENGINE_CREATION_FORM_DOCUMENTATION_DESCRIPTION} +
+
+ + + { + e.preventDefault(); + submitEngine(); + }} + > + + {META_ENGINE_CREATION_FORM_TITLE} + + + + + 0 && rawName !== name ? ( + <> + {SANITIZED_NAME_NOTE} {name} + + ) : ( + ALLOWED_CHARS_NOTE + ) + } + fullWidth + > + setRawName(event.currentTarget.value)} + fullWidth + data-test-subj="MetaEngineCreationNameInput" + placeholder={META_ENGINE_CREATION_FORM_ENGINE_NAME_PLACEHOLDER} + autoFocus + /> + + + + + + { + setSelectedIndexedEngineNames(options.map(comboBoxOptionToEngineName)); + }} + /> + + + {selectedIndexedEngineNames.length > maxEnginesPerMetaEngine && ( + + )} + + maxEnginesPerMetaEngine + } + type="submit" + data-test-subj="NewMetaEngineSubmitButton" + fill + color="secondary" + > + {META_ENGINE_CREATION_FORM_SUBMIT_BUTTON_LABEL} + + + +
+ ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation_logic.test.ts new file mode 100644 index 0000000000000..6ffe7034584a1 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation_logic.test.ts @@ -0,0 +1,175 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + LogicMounter, + mockHttpValues, + mockFlashMessageHelpers, + mockKibanaValues, +} from '../../../__mocks__'; + +import { nextTick } from '@kbn/test/jest'; + +import { MetaEngineCreationLogic } from './meta_engine_creation_logic'; + +describe('MetaEngineCreationLogic', () => { + const { mount } = new LogicMounter(MetaEngineCreationLogic); + const { http } = mockHttpValues; + const { navigateToUrl } = mockKibanaValues; + const { setQueuedSuccessMessage, flashAPIErrors } = mockFlashMessageHelpers; + + const DEFAULT_VALUES = { + indexedEngineNames: [], + name: '', + rawName: '', + selectedIndexedEngineNames: [], + }; + + it('has expected default values', () => { + mount(); + expect(MetaEngineCreationLogic.values).toEqual(DEFAULT_VALUES); + }); + + describe('actions', () => { + describe('setRawName', () => { + beforeAll(() => { + jest.clearAllMocks(); + mount(); + MetaEngineCreationLogic.actions.setRawName('Name__With#$&*%Special--Characters'); + }); + + it('should set rawName to provided value', () => { + expect(MetaEngineCreationLogic.values.rawName).toEqual( + 'Name__With#$&*%Special--Characters' + ); + }); + + it('should set name to a sanitized value', () => { + expect(MetaEngineCreationLogic.values.name).toEqual('name-with-special-characters'); + }); + }); + + describe('setIndexedEngineNames', () => { + it('should set indexedEngineNames to provided value', () => { + mount(); + MetaEngineCreationLogic.actions.setIndexedEngineNames(['first', 'middle', 'last']); + expect(MetaEngineCreationLogic.values.indexedEngineNames).toEqual([ + 'first', + 'middle', + 'last', + ]); + }); + }); + + describe('setSelectedIndexedEngineNames', () => { + it('should set selectedIndexedEngineNames to provided value', () => { + mount(); + MetaEngineCreationLogic.actions.setSelectedIndexedEngineNames(['one', 'two', 'three']); + expect(MetaEngineCreationLogic.values.selectedIndexedEngineNames).toEqual([ + 'one', + 'two', + 'three', + ]); + }); + }); + }); + + describe('listeners', () => { + describe('fetchIndexedEngineNames', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('calls flashAPIErrors on API Error', async () => { + http.get.mockReturnValueOnce(Promise.reject()); + MetaEngineCreationLogic.actions.fetchIndexedEngineNames(); + await nextTick(); + expect(flashAPIErrors).toHaveBeenCalledTimes(1); + }); + + it('calls onEngineCreationSuccess on valid submission', async () => { + jest.spyOn(MetaEngineCreationLogic.actions, 'setIndexedEngineNames'); + http.get.mockReturnValueOnce( + Promise.resolve({ results: [{ name: 'foo' }], meta: { page: { total_pages: 1 } } }) + ); + MetaEngineCreationLogic.actions.fetchIndexedEngineNames(); + await nextTick(); + expect(MetaEngineCreationLogic.actions.setIndexedEngineNames).toHaveBeenCalledWith(['foo']); + }); + + it('if there are remaining pages it should call fetchIndexedEngineNames recursively with an incremented page', async () => { + jest.spyOn(MetaEngineCreationLogic.actions, 'fetchIndexedEngineNames'); + http.get.mockReturnValueOnce( + Promise.resolve({ results: [{ name: 'foo' }], meta: { page: { total_pages: 2 } } }) + ); + MetaEngineCreationLogic.actions.fetchIndexedEngineNames(); + await nextTick(); + expect(MetaEngineCreationLogic.actions.fetchIndexedEngineNames).toHaveBeenCalledWith(2); + }); + + it('if there are no remaining pages it should end without calling recursively', async () => { + jest.spyOn(MetaEngineCreationLogic.actions, 'fetchIndexedEngineNames'); + http.get.mockReturnValueOnce( + Promise.resolve({ results: [{ name: 'foo' }], meta: { page: { total_pages: 1 } } }) + ); + MetaEngineCreationLogic.actions.fetchIndexedEngineNames(); + await nextTick(); + expect(MetaEngineCreationLogic.actions.fetchIndexedEngineNames).toHaveBeenCalledTimes(1); // it's one time cause we called it two lines above + }); + }); + + describe('onEngineCreationSuccess', () => { + beforeAll(() => { + jest.clearAllMocks(); + mount({ language: 'English', rawName: 'test' }); + MetaEngineCreationLogic.actions.onEngineCreationSuccess(); + }); + + it('should set a success message', () => { + expect(setQueuedSuccessMessage).toHaveBeenCalledWith('Successfully created meta engine.'); + }); + + it('should navigate the user to the engine page', () => { + expect(navigateToUrl).toHaveBeenCalledWith('/engines/test'); + }); + }); + + describe('submitEngine', () => { + beforeAll(() => { + jest.clearAllMocks(); + mount({ rawName: 'test', selectedIndexedEngineNames: ['foo'] }); + }); + + it('POSTS to /api/app_search/engines', () => { + const body = JSON.stringify({ + name: 'test', + type: 'meta', + source_engines: ['foo'], + }); + MetaEngineCreationLogic.actions.submitEngine(); + expect(http.post).toHaveBeenCalledWith('/api/app_search/engines', { body }); + }); + + it('calls onEngineCreationSuccess on valid submission', async () => { + jest.spyOn(MetaEngineCreationLogic.actions, 'onEngineCreationSuccess'); + http.post.mockReturnValueOnce(Promise.resolve({})); + MetaEngineCreationLogic.actions.submitEngine(); + await nextTick(); + expect(MetaEngineCreationLogic.actions.onEngineCreationSuccess).toHaveBeenCalledTimes(1); + }); + + it('calls flashAPIErrors on API Error', async () => { + jest.spyOn(MetaEngineCreationLogic.actions, 'setIndexedEngineNames'); + http.post.mockReturnValueOnce(Promise.reject()); + MetaEngineCreationLogic.actions.submitEngine(); + await nextTick(); + expect(flashAPIErrors).toHaveBeenCalledTimes(1); + expect(MetaEngineCreationLogic.actions.setIndexedEngineNames).not.toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation_logic.ts new file mode 100644 index 0000000000000..d94eb82a49c0e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation_logic.ts @@ -0,0 +1,127 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { generatePath } from 'react-router-dom'; + +import { kea, MakeLogicType } from 'kea'; + +import { Meta } from '../../../../../common/types'; +import { DEFAULT_META } from '../../../shared/constants'; +import { flashAPIErrors, setQueuedSuccessMessage } from '../../../shared/flash_messages'; +import { HttpLogic } from '../../../shared/http'; +import { KibanaLogic } from '../../../shared/kibana'; +import { ENGINE_PATH } from '../../routes'; +import { formatApiName } from '../../utils/format_api_name'; +import { EngineDetails } from '../engine/types'; + +import { META_ENGINE_CREATION_SUCCESS_MESSAGE } from './constants'; + +interface MetaEngineCreationValues { + indexedEngineNames: string[]; + name: string; + rawName: string; + selectedIndexedEngineNames: string[]; +} + +interface MetaEngineCreationActions { + fetchIndexedEngineNames(page?: number): { page: number }; + onEngineCreationSuccess(): void; + setIndexedEngineNames( + indexedEngineNames: MetaEngineCreationValues['indexedEngineNames'] + ): { indexedEngineNames: MetaEngineCreationValues['indexedEngineNames'] }; + setRawName(rawName: string): { rawName: string }; + setSelectedIndexedEngineNames( + selectedIndexedEngineNames: MetaEngineCreationValues['selectedIndexedEngineNames'] + ): { selectedIndexedEngineNames: MetaEngineCreationValues['selectedIndexedEngineNames'] }; + submitEngine(): void; +} + +export const MetaEngineCreationLogic = kea< + MakeLogicType +>({ + path: ['enterprise_search', 'app_search', 'meta_engine_creation_logic'], + actions: { + fetchIndexedEngineNames: (page = DEFAULT_META.page.current) => ({ page }), + onEngineCreationSuccess: true, + setIndexedEngineNames: (indexedEngineNames) => ({ indexedEngineNames }), + setRawName: (rawName) => ({ rawName }), + setSelectedIndexedEngineNames: (selectedIndexedEngineNames) => ({ selectedIndexedEngineNames }), + submitEngine: () => null, + }, + reducers: { + indexedEngineNames: [ + [], + { + setIndexedEngineNames: (_, { indexedEngineNames }) => indexedEngineNames, + }, + ], + rawName: [ + '', + { + setRawName: (_, { rawName }) => rawName, + }, + ], + selectedIndexedEngineNames: [ + [], + { + setSelectedIndexedEngineNames: (_, { selectedIndexedEngineNames }) => + selectedIndexedEngineNames, + }, + ], + }, + selectors: ({ selectors }) => ({ + name: [() => [selectors.rawName], (rawName: string) => formatApiName(rawName)], + }), + listeners: ({ values, actions }) => ({ + fetchIndexedEngineNames: async ({ page }) => { + const { http } = HttpLogic.values; + let response: { results: EngineDetails[]; meta: Meta } | undefined; + + try { + response = await http.get('/api/app_search/engines', { + query: { type: 'indexed', 'page[current]': page, 'page[size]': DEFAULT_META.page.size }, + }); + } catch (e) { + flashAPIErrors(e); + } + + if (response) { + const engineNames = response.results.map((result) => result.name); + actions.setIndexedEngineNames([...values.indexedEngineNames, ...engineNames]); + + if (page < response.meta.page.total_pages) { + actions.fetchIndexedEngineNames(page + 1); + } + } + }, + onEngineCreationSuccess: () => { + const { name } = values; + const { navigateToUrl } = KibanaLogic.values; + const enginePath = generatePath(ENGINE_PATH, { engineName: name }); + + setQueuedSuccessMessage(META_ENGINE_CREATION_SUCCESS_MESSAGE); + navigateToUrl(enginePath); + }, + submitEngine: async () => { + const { http } = HttpLogic.values; + const { name, selectedIndexedEngineNames } = values; + + const body = JSON.stringify({ + name, + type: 'meta', + source_engines: selectedIndexedEngineNames, + }); + + try { + await http.post('/api/app_search/engines', { body }); + actions.onEngineCreationSuccess(); + } catch (e) { + flashAPIErrors(e); + } + }, + }), +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx index 5150a4996eb84..a1c845a10a47c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx @@ -21,6 +21,7 @@ import { EngineRouter } from './components/engine'; import { EngineCreation } from './components/engine_creation'; import { EnginesOverview } from './components/engines'; import { ErrorConnecting } from './components/error_connecting'; +import { MetaEngineCreation } from './components/meta_engine_creation'; import { SetupGuide } from './components/setup_guide'; import { AppSearch, AppSearchUnconfigured, AppSearchConfigured, AppSearchNav } from './'; @@ -117,6 +118,22 @@ describe('AppSearchConfigured', () => { expect(wrapper.find(EngineCreation)).toHaveLength(0); }); }); + + describe('canManageMetaEngines', () => { + it('renders MetaEngineCreation when user canManageMetaEngines is true', () => { + setMockValues({ myRole: { canManageMetaEngines: true } }); + const wrapper = shallow(); + + expect(wrapper.find(MetaEngineCreation)).toHaveLength(1); + }); + + it('does not render MetaEngineCreation when user canManageMetaEngines is false', () => { + setMockValues({ myRole: { canManageMetaEngines: false } }); + const wrapper = shallow(); + + expect(wrapper.find(MetaEngineCreation)).toHaveLength(0); + }); + }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx index 40dfc1426e402..ec64cb2f10eb0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx @@ -25,6 +25,7 @@ import { EngineCreation } from './components/engine_creation'; import { EnginesOverview, ENGINES_TITLE } from './components/engines'; import { ErrorConnecting } from './components/error_connecting'; import { Library } from './components/library'; +import { MetaEngineCreation } from './components/meta_engine_creation'; import { ROLE_MAPPINGS_TITLE } from './components/role_mappings'; import { Settings, SETTINGS_TITLE } from './components/settings'; import { SetupGuide } from './components/setup_guide'; @@ -38,6 +39,7 @@ import { ENGINES_PATH, ENGINE_PATH, LIBRARY_PATH, + META_ENGINE_CREATION_PATH, } from './routes'; export const AppSearch: React.FC = (props) => { @@ -60,7 +62,7 @@ export const AppSearchConfigured: React.FC = (props) => { const { initializeAppData } = useActions(AppLogic); const { hasInitialized, - myRole: { canManageEngines }, + myRole: { canManageEngines, canManageMetaEngines }, } = useValues(AppLogic); const { errorConnecting, readOnlyMode } = useValues(HttpLogic); @@ -106,6 +108,11 @@ export const AppSearchConfigured: React.FC = (props) => { )} + {canManageMetaEngines && ( + + + + )} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/routes.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/routes.ts index 6fe9be083405e..907a27c8660d2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/routes.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/routes.ts @@ -40,6 +40,7 @@ export const ENGINE_REINDEX_JOB_PATH = `${ENGINE_PATH}/reindex-job/:activeReinde export const ENGINE_CRAWLER_PATH = `${ENGINE_PATH}/crawler`; // TODO: Crawler sub-pages +export const META_ENGINE_CREATION_PATH = '/meta_engine_creation'; export const META_ENGINE_SOURCE_ENGINES_PATH = `${ENGINE_PATH}/engines`; export const ENGINE_RELEVANCE_TUNING_PATH = `${ENGINE_PATH}/relevance_tuning`; diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/engines.test.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/engines.test.ts index 779c51131b472..6b78f29a6b731 100644 --- a/x-pack/plugins/enterprise_search/server/routes/app_search/engines.test.ts +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/engines.test.ts @@ -122,19 +122,56 @@ describe('engine routes', () => { }); describe('validates', () => { - it('correctly', () => { - const request = { body: { name: 'some-engine', language: 'en' } }; - mockRouter.shouldValidate(request); - }); - - it('missing name', () => { - const request = { body: { language: 'en' } }; - mockRouter.shouldThrow(request); - }); - - it('optional language', () => { - const request = { body: { name: 'some-engine' } }; - mockRouter.shouldValidate(request); + describe('indexed engines', () => { + it('correctly', () => { + const request = { body: { name: 'some-engine', language: 'en' } }; + mockRouter.shouldValidate(request); + }); + + it('missing name', () => { + const request = { body: { language: 'en' } }; + mockRouter.shouldThrow(request); + }); + + it('optional language', () => { + const request = { body: { name: 'some-engine' } }; + mockRouter.shouldValidate(request); + }); + }); + + describe('meta engines', () => { + it('all properties', () => { + const request = { + body: { name: 'some-meta-engine', type: 'any', language: 'en', source_engines: [] }, + }; + mockRouter.shouldValidate(request); + }); + + it('missing name', () => { + const request = { + body: { type: 'any', language: 'en', source_engines: [] }, + }; + mockRouter.shouldThrow(request); + }); + + it('optional language', () => { + const request = { + body: { name: 'some-meta-engine', type: 'any', source_engines: [] }, + }; + mockRouter.shouldValidate(request); + }); + + it('optional source_engines', () => { + const request = { + body: { name: 'some-meta-engine', type: 'any', language: 'en' }, + }; + mockRouter.shouldValidate(request); + }); + + it('optional type', () => { + const request = { body: { name: 'some-engine' } }; + mockRouter.shouldValidate(request); + }); }); }); }); diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts index 9bff6cf127dd3..766be196e70e7 100644 --- a/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts @@ -45,6 +45,8 @@ export function registerEnginesRoutes({ body: schema.object({ name: schema.string(), language: schema.maybe(schema.string()), + source_engines: schema.maybe(schema.arrayOf(schema.string())), + type: schema.maybe(schema.string()), }), }, }, From 9fd28b67c5b6c8a519085ea5171a281fc398a881 Mon Sep 17 00:00:00 2001 From: Josh Dover <1813008+joshdover@users.noreply.github.com> Date: Tue, 2 Mar 2021 17:20:50 +0100 Subject: [PATCH 05/33] Remove ms label from CPU load on status page (#92836) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- src/core/public/core_app/status/lib/load_status.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/public/core_app/status/lib/load_status.ts b/src/core/public/core_app/status/lib/load_status.ts index d8d2bd3fec517..3c31da4c5397f 100644 --- a/src/core/public/core_app/status/lib/load_status.ts +++ b/src/core/public/core_app/status/lib/load_status.ts @@ -57,7 +57,7 @@ function formatMetrics({ metrics }: StatusResponse): Metric[] { defaultMessage: 'Load', }), value: [metrics.os.load['1m'], metrics.os.load['5m'], metrics.os.load['15m']], - type: 'time', + type: 'float', }, { name: i18n.translate('core.statusPage.metricsTiles.columns.resTimeAvgHeader', { From 92134cb88e617c7a161450e9dd7b9c0d86beb65d Mon Sep 17 00:00:00 2001 From: Marco Liberati Date: Tue, 2 Mar 2021 17:34:46 +0100 Subject: [PATCH 06/33] [Lens] Set pie chart slices sorted clockwise (#92617) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../plugins/lens/public/pie_visualization/render_function.tsx | 1 - x-pack/test/functional/apps/lens/dashboard.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx index 404ac99db9df7..4d6eac6a87e48 100644 --- a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx @@ -172,7 +172,6 @@ export function PieComponent( fontFamily: chartTheme.barSeriesStyle?.displayValue?.fontFamily, outerSizeRatio: 1, specialFirstInnermostSector: true, - clockwiseSectors: false, minFontSize: 10, maxFontSize: 16, // Labels are added outside the outer ring when the slice is too small diff --git a/x-pack/test/functional/apps/lens/dashboard.ts b/x-pack/test/functional/apps/lens/dashboard.ts index 0d2db53ba73af..a15176d76f953 100644 --- a/x-pack/test/functional/apps/lens/dashboard.ts +++ b/x-pack/test/functional/apps/lens/dashboard.ts @@ -120,7 +120,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { '[data-test-subj="embeddablePanelHeading-lnsPieVis"]', 'lnsPieVis' ); - const hasGeoDestFilter = await filterBar.hasFilter('geo.dest', 'LS'); + const hasGeoDestFilter = await filterBar.hasFilter('geo.dest', 'AL'); expect(hasGeoDestFilter).to.be(true); await filterBar.addFilter('geo.src', 'is', 'US'); await filterBar.toggleFilterPinned('geo.src'); From 1702cf98f018c41ec0a080d829a12403168ac242 Mon Sep 17 00:00:00 2001 From: John Schulz Date: Tue, 2 Mar 2021 12:10:39 -0500 Subject: [PATCH 07/33] [Fleet] Use type-only imports where possible (#92979) ## Summary Use [type-only `import`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export) to differentiate between runtime values and (erasable) TS types. Screen Shot 2021-02-27 at 6 34 46 PM Allows Babel and `tsc` to make some optimizations since it can be sure what can be erased. It can also be helpful in situations like below which highlights that even though `KibanaAssetType` and `KibanaSavedObjectType` are named a certain way and from `common/types`, they are JS values _not_ TS types. They are `enum`s which means they are JS objects at runtime; not eliminated at runtime. https://github.com/elastic/kibana/blob/d92a1a08d89accc2fa303b1355a9e222f9b6d090/x-pack/plugins/fleet/common/types/models/epm.ts#L41-L63 --- .../fleet/common/constants/agent_policy.ts | 3 +- .../plugins/fleet/common/constants/output.ts | 2 +- x-pack/plugins/fleet/common/mocks.ts | 2 +- .../fleet/common/services/agent_status.ts | 2 +- .../full_agent_policy_kibana_config.ts | 2 +- .../services/full_agent_policy_to_yaml.ts | 2 +- .../services/is_agent_upgradeable.test.ts | 2 +- .../common/services/is_agent_upgradeable.ts | 2 +- .../plugins/fleet/common/services/license.ts | 2 +- .../fleet/common/services/limited_package.ts | 2 +- .../package_policies_to_agent_inputs.test.ts | 2 +- .../package_policies_to_agent_inputs.ts | 2 +- .../package_to_package_policy.test.ts | 2 +- .../services/package_to_package_policy.ts | 2 +- .../fleet/common/types/models/agent.ts | 2 +- .../fleet/common/types/models/agent_policy.ts | 6 ++-- .../plugins/fleet/common/types/models/epm.ts | 6 ++-- .../fleet/common/types/models/package_spec.ts | 2 +- .../fleet/common/types/models/settings.ts | 2 +- .../fleet/common/types/rest_spec/agent.ts | 2 +- .../common/types/rest_spec/agent_policy.ts | 4 +-- .../fleet/common/types/rest_spec/common.ts | 2 +- .../common/types/rest_spec/data_stream.ts | 2 +- .../types/rest_spec/enrollment_api_key.ts | 2 +- .../fleet/common/types/rest_spec/epm.ts | 2 +- .../fleet/common/types/rest_spec/output.ts | 2 +- .../common/types/rest_spec/package_policy.ts | 2 +- .../fleet/common/types/rest_spec/settings.ts | 2 +- .../applications/fleet/hooks/use_config.ts | 2 +- .../applications/fleet/hooks/use_core.ts | 2 +- .../applications/fleet/hooks/use_link.ts | 9 ++---- .../fleet/hooks/use_package_icon_type.ts | 2 +- .../fleet/hooks/use_request/agent_policy.ts | 10 ++---- .../fleet/hooks/use_request/agents.ts | 5 +-- .../fleet/hooks/use_request/app.ts | 2 +- .../fleet/hooks/use_request/data_stream.ts | 2 +- .../hooks/use_request/enrollment_api_keys.ts | 11 ++----- .../fleet/hooks/use_request/epm.ts | 4 +-- .../fleet/hooks/use_request/outputs.ts | 2 +- .../fleet/hooks/use_request/package_policy.ts | 4 +-- .../fleet/hooks/use_request/settings.ts | 2 +- .../fleet/hooks/use_request/setup.ts | 2 +- .../fleet/hooks/use_request/use_request.ts | 8 +++-- .../fleet/hooks/use_ui_extension.ts | 2 +- .../fleet/hooks/use_url_pagination.ts | 3 +- .../fleet/mock/plugin_configuration.ts | 2 +- .../fleet/mock/plugin_dependencies.ts | 2 +- .../fleet/mock/plugin_interfaces.ts | 4 +-- .../public/applications/fleet/mock/types.ts | 9 ++++-- .../services/has_invalid_but_required_var.ts | 2 +- .../services/is_advanced_var.ts | 2 +- .../services/validate_package_policy.test.ts | 2 +- .../services/validate_package_policy.ts | 2 +- .../sections/epm/components/release_badge.ts | 2 +- .../use_package_policies_with_agent_policy.ts | 8 ++--- .../fleet/services/ui_extensions.test.ts | 3 +- .../fleet/services/ui_extensions.ts | 2 +- .../fleet/types/intra_app_route_state.ts | 4 +-- .../applications/fleet/types/ui_extensions.ts | 4 +-- x-pack/plugins/fleet/public/index.ts | 2 +- x-pack/plugins/fleet/public/plugin.ts | 27 +++++++++------- .../plugins/fleet/scripts/dev_agent/script.ts | 2 +- .../server/collectors/agent_collectors.ts | 3 +- .../server/collectors/config_collectors.ts | 2 +- .../fleet/server/collectors/helpers.ts | 5 +-- .../server/collectors/package_collectors.ts | 2 +- .../fleet/server/collectors/register.ts | 12 ++++--- .../plugins/fleet/server/errors/handlers.ts | 4 +-- x-pack/plugins/fleet/server/index.ts | 5 +-- x-pack/plugins/fleet/server/mocks.ts | 7 ++--- .../server/routes/agent/acks_handlers.test.ts | 6 ++-- .../server/routes/agent/acks_handlers.ts | 8 ++--- .../routes/agent/actions_handlers.test.ts | 8 ++--- .../server/routes/agent/actions_handlers.ts | 8 ++--- .../fleet/server/routes/agent/handlers.ts | 8 ++--- .../fleet/server/routes/agent/index.ts | 4 +-- .../server/routes/agent/unenroll_handler.ts | 9 ++++-- .../server/routes/agent/upgrade_handler.ts | 6 ++-- .../server/routes/agent_policy/handlers.ts | 11 +++---- .../fleet/server/routes/agent_policy/index.ts | 2 +- .../plugins/fleet/server/routes/app/index.ts | 4 +-- .../server/routes/data_streams/handlers.ts | 7 +++-- .../fleet/server/routes/data_streams/index.ts | 2 +- .../routes/enrollment_api_key/handler.ts | 6 ++-- .../server/routes/enrollment_api_key/index.ts | 2 +- .../fleet/server/routes/epm/handlers.ts | 8 ++--- .../plugins/fleet/server/routes/epm/index.ts | 2 +- .../server/routes/install_script/index.ts | 3 +- .../server/routes/limited_concurrency.test.ts | 2 +- .../server/routes/limited_concurrency.ts | 4 +-- .../fleet/server/routes/output/handler.ts | 6 ++-- .../fleet/server/routes/output/index.ts | 2 +- .../routes/package_policy/handlers.test.ts | 8 ++--- .../server/routes/package_policy/handlers.ts | 7 +++-- .../server/routes/package_policy/index.ts | 2 +- .../plugins/fleet/server/routes/security.ts | 2 +- .../fleet/server/routes/settings/index.ts | 4 +-- .../server/routes/setup/handlers.test.ts | 2 +- .../fleet/server/routes/setup/handlers.ts | 6 ++-- .../fleet/server/routes/setup/index.ts | 5 ++- .../fleet/server/saved_objects/index.ts | 4 +-- .../saved_objects/migrations/to_v7_10_0.ts | 6 ++-- .../fleet/server/services/agent_policy.ts | 10 +++--- .../server/services/agent_policy_update.ts | 3 +- .../fleet/server/services/agents/acks.test.ts | 5 ++- .../fleet/server/services/agents/acks.ts | 6 ++-- .../server/services/agents/actions.test.ts | 4 +-- .../fleet/server/services/agents/actions.ts | 4 +-- .../server/services/agents/authenticate.ts | 5 +-- .../server/services/agents/checkin/index.ts | 5 ++- .../server/services/agents/checkin/state.ts | 4 +-- .../agents/checkin/state_new_actions.test.ts | 4 +-- .../agents/checkin/state_new_actions.ts | 5 +-- .../fleet/server/services/agents/crud.ts | 4 +-- .../services/agents/crud_fleet_server.ts | 15 ++++----- .../fleet/server/services/agents/crud_so.ts | 8 ++--- .../fleet/server/services/agents/events.ts | 4 +-- .../fleet/server/services/agents/helpers.ts | 4 +-- .../server/services/agents/saved_objects.ts | 4 +-- .../fleet/server/services/agents/setup.ts | 2 +- .../server/services/agents/status.test.ts | 4 +-- .../fleet/server/services/agents/status.ts | 8 ++--- .../fleet/server/services/agents/unenroll.ts | 2 +- .../fleet/server/services/agents/update.ts | 2 +- .../fleet/server/services/agents/upgrade.ts | 4 +-- .../services/api_keys/enrollment_api_key.ts | 4 +-- .../enrollment_api_key_fleet_server.ts | 8 ++--- .../api_keys/enrollment_api_key_so.ts | 4 +-- .../fleet/server/services/api_keys/index.ts | 3 +- .../server/services/api_keys/security.ts | 5 +-- .../fleet/server/services/app_context.ts | 15 +++++---- .../plugins/fleet/server/services/config.ts | 2 +- .../fleet/server/services/epm/agent/agent.ts | 2 +- .../server/services/epm/archive/cache.ts | 4 +-- .../server/services/epm/archive/extract.ts | 2 +- .../server/services/epm/archive/index.ts | 4 +-- .../server/services/epm/archive/storage.ts | 9 +++--- .../server/services/epm/archive/validation.ts | 2 +- .../elasticsearch/datastream_ilm/install.ts | 8 ++--- .../elasticsearch/datastream_ilm/remove.ts | 5 +-- .../services/epm/elasticsearch/ilm/install.ts | 3 +- .../services/epm/elasticsearch/index.test.ts | 2 +- .../services/epm/elasticsearch/index.ts | 2 +- .../ingest_pipeline/ingest_pipelines.test.ts | 2 +- .../elasticsearch/ingest_pipeline/install.ts | 11 ++++--- .../elasticsearch/ingest_pipeline/remove.ts | 8 +++-- .../elasticsearch/template/install.test.ts | 5 ++- .../epm/elasticsearch/template/install.ts | 11 ++++--- .../elasticsearch/template/template.test.ts | 5 +-- .../epm/elasticsearch/template/template.ts | 4 +-- .../epm/elasticsearch/transform/install.ts | 12 +++---- .../elasticsearch/transform/remove.test.ts | 4 +-- .../epm/elasticsearch/transform/remove.ts | 5 +-- .../elasticsearch/transform/transform.test.ts | 9 ++++-- .../server/services/epm/fields/field.test.ts | 3 +- .../fleet/server/services/epm/fields/field.ts | 2 +- .../services/epm/kibana/assets/install.ts | 11 ++----- .../epm/kibana/index_pattern/install.test.ts | 4 +-- .../epm/kibana/index_pattern/install.ts | 14 ++++++--- .../kibana/index_pattern/tests/test_data.ts | 2 +- .../epm/packages/_install_package.test.ts | 3 +- .../services/epm/packages/_install_package.ts | 15 +++------ .../services/epm/packages/assets.test.ts | 2 +- .../server/services/epm/packages/assets.ts | 5 +-- .../epm/packages/bulk_install_packages.ts | 7 +++-- .../ensure_installed_default_packages.test.ts | 5 +-- .../server/services/epm/packages/get.test.ts | 5 +-- .../fleet/server/services/epm/packages/get.ts | 14 ++++++--- .../epm/packages/get_install_type.test.ts | 5 +-- .../server/services/epm/packages/index.ts | 13 +++----- .../server/services/epm/packages/install.ts | 31 +++++++++---------- .../server/services/epm/packages/remove.ts | 6 ++-- .../services/epm/registry/index.test.ts | 2 +- .../server/services/epm/registry/index.ts | 4 +-- .../server/services/epm/registry/proxy.ts | 7 ++--- .../server/services/epm/registry/requests.ts | 3 +- .../fleet/server/services/es_index_pattern.ts | 4 +-- .../services/fleet_server/elastic_index.ts | 2 +- .../fleet_server/saved_object_migrations.ts | 7 +++-- x-pack/plugins/fleet/server/services/index.ts | 9 +++--- .../install_script/install_templates/linux.ts | 2 +- .../install_script/install_templates/macos.ts | 2 +- .../plugins/fleet/server/services/output.ts | 4 +-- .../server/services/package_policy.test.ts | 13 +++++--- .../fleet/server/services/package_policy.ts | 21 +++++++------ .../fleet/server/services/saved_object.ts | 4 +-- .../plugins/fleet/server/services/settings.ts | 11 ++----- x-pack/plugins/fleet/server/services/setup.ts | 9 ++---- .../fleet/server/types/rest_spec/common.ts | 3 +- 189 files changed, 483 insertions(+), 469 deletions(-) diff --git a/x-pack/plugins/fleet/common/constants/agent_policy.ts b/x-pack/plugins/fleet/common/constants/agent_policy.ts index bed9b6e8390b8..51cf0382e2dbc 100644 --- a/x-pack/plugins/fleet/common/constants/agent_policy.ts +++ b/x-pack/plugins/fleet/common/constants/agent_policy.ts @@ -6,7 +6,8 @@ */ import { defaultPackages } from './epm'; -import { AgentPolicy } from '../types'; +import type { AgentPolicy } from '../types'; + export const AGENT_POLICY_SAVED_OBJECT_TYPE = 'ingest-agent-policies'; export const AGENT_POLICY_INDEX = '.fleet-policies'; export const agentPolicyStatuses = { diff --git a/x-pack/plugins/fleet/common/constants/output.ts b/x-pack/plugins/fleet/common/constants/output.ts index 9022be1086744..80c7e56dbb52f 100644 --- a/x-pack/plugins/fleet/common/constants/output.ts +++ b/x-pack/plugins/fleet/common/constants/output.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { NewOutput } from '../types'; +import type { NewOutput } from '../types'; export const OUTPUT_SAVED_OBJECT_TYPE = 'ingest-outputs'; diff --git a/x-pack/plugins/fleet/common/mocks.ts b/x-pack/plugins/fleet/common/mocks.ts index 4edc0fa6f81e9..7ea4be0ee35c6 100644 --- a/x-pack/plugins/fleet/common/mocks.ts +++ b/x-pack/plugins/fleet/common/mocks.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { NewPackagePolicy, PackagePolicy } from './types'; +import type { NewPackagePolicy, PackagePolicy } from './types'; export const createNewPackagePolicyMock = (): NewPackagePolicy => { return { diff --git a/x-pack/plugins/fleet/common/services/agent_status.ts b/x-pack/plugins/fleet/common/services/agent_status.ts index 1b49ba0c015e9..6d1d1c6a309d8 100644 --- a/x-pack/plugins/fleet/common/services/agent_status.ts +++ b/x-pack/plugins/fleet/common/services/agent_status.ts @@ -6,7 +6,7 @@ */ import { AGENT_POLLING_THRESHOLD_MS, AGENT_SAVED_OBJECT_TYPE } from '../constants'; -import { Agent, AgentStatus } from '../types'; +import type { Agent, AgentStatus } from '../types'; export function getAgentStatus(agent: Agent, now: number = Date.now()): AgentStatus { const { last_checkin: lastCheckIn } = agent; diff --git a/x-pack/plugins/fleet/common/services/full_agent_policy_kibana_config.ts b/x-pack/plugins/fleet/common/services/full_agent_policy_kibana_config.ts index 46fddd8bf040b..6b2709cc1961d 100644 --- a/x-pack/plugins/fleet/common/services/full_agent_policy_kibana_config.ts +++ b/x-pack/plugins/fleet/common/services/full_agent_policy_kibana_config.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FullAgentPolicyKibanaConfig } from '../types'; +import type { FullAgentPolicyKibanaConfig } from '../types'; export function getFullAgentPolicyKibanaConfig(kibanaUrls: string[]): FullAgentPolicyKibanaConfig { // paths and protocol are validated to be the same for all urls, so use the first to get them diff --git a/x-pack/plugins/fleet/common/services/full_agent_policy_to_yaml.ts b/x-pack/plugins/fleet/common/services/full_agent_policy_to_yaml.ts index 3dafc65a65235..64d297922f570 100644 --- a/x-pack/plugins/fleet/common/services/full_agent_policy_to_yaml.ts +++ b/x-pack/plugins/fleet/common/services/full_agent_policy_to_yaml.ts @@ -6,7 +6,7 @@ */ import { safeDump } from 'js-yaml'; -import { FullAgentPolicy } from '../types'; +import type { FullAgentPolicy } from '../types'; const POLICY_KEYS_ORDER = [ 'id', diff --git a/x-pack/plugins/fleet/common/services/is_agent_upgradeable.test.ts b/x-pack/plugins/fleet/common/services/is_agent_upgradeable.test.ts index ed5e2a22709c4..38ae63933a076 100644 --- a/x-pack/plugins/fleet/common/services/is_agent_upgradeable.test.ts +++ b/x-pack/plugins/fleet/common/services/is_agent_upgradeable.test.ts @@ -6,7 +6,7 @@ */ import { isAgentUpgradeable } from './is_agent_upgradeable'; -import { Agent } from '../types/models/agent'; +import type { Agent } from '../types/models/agent'; const getAgent = ({ version, diff --git a/x-pack/plugins/fleet/common/services/is_agent_upgradeable.ts b/x-pack/plugins/fleet/common/services/is_agent_upgradeable.ts index 12129816581f1..7de4e7c11d09e 100644 --- a/x-pack/plugins/fleet/common/services/is_agent_upgradeable.ts +++ b/x-pack/plugins/fleet/common/services/is_agent_upgradeable.ts @@ -7,7 +7,7 @@ import semverCoerce from 'semver/functions/coerce'; import semverLt from 'semver/functions/lt'; -import { Agent } from '../types'; +import type { Agent } from '../types'; export function isAgentUpgradeable(agent: Agent, kibanaVersion: string) { let agentVersion: string; diff --git a/x-pack/plugins/fleet/common/services/license.ts b/x-pack/plugins/fleet/common/services/license.ts index a480dd56d8b0c..68cbee5786d3b 100644 --- a/x-pack/plugins/fleet/common/services/license.ts +++ b/x-pack/plugins/fleet/common/services/license.ts @@ -6,7 +6,7 @@ */ import { Observable, Subscription } from 'rxjs'; -import { ILicense } from '../../../licensing/common/types'; +import type { ILicense } from '../../../licensing/common/types'; // Generic license service class that works with the license observable // Both server and client plugins instancates a singleton version of this class diff --git a/x-pack/plugins/fleet/common/services/limited_package.ts b/x-pack/plugins/fleet/common/services/limited_package.ts index da4ee176ee443..e247b61869de1 100644 --- a/x-pack/plugins/fleet/common/services/limited_package.ts +++ b/x-pack/plugins/fleet/common/services/limited_package.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PackageInfo, AgentPolicy, PackagePolicy } from '../types'; +import type { PackageInfo, AgentPolicy, PackagePolicy } from '../types'; // Assume packages only ever include 1 config template for now export const isPackageLimited = (packageInfo: PackageInfo): boolean => { diff --git a/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.test.ts b/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.test.ts index ee67263f159be..930a111f66d6b 100644 --- a/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.test.ts +++ b/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PackagePolicy, PackagePolicyInput } from '../types'; +import type { PackagePolicy, PackagePolicyInput } from '../types'; import { storedPackagePoliciesToAgentInputs } from './package_policies_to_agent_inputs'; describe('Fleet - storedPackagePoliciesToAgentInputs', () => { diff --git a/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.ts b/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.ts index f1cd2f60896e7..61d7764a832b1 100644 --- a/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.ts +++ b/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PackagePolicy, FullAgentPolicyInput, FullAgentPolicyInputStream } from '../types'; +import type { PackagePolicy, FullAgentPolicyInput, FullAgentPolicyInputStream } from '../types'; import { DEFAULT_OUTPUT } from '../constants'; export const storedPackagePoliciesToAgentInputs = ( diff --git a/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts b/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts index bb07ff152c085..e8ede61098dc2 100644 --- a/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts +++ b/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PackageInfo } from '../types'; +import type { PackageInfo } from '../types'; import { packageToPackagePolicy, packageToPackagePolicyInputs } from './package_to_package_policy'; describe('Fleet - packageToPackagePolicy', () => { diff --git a/x-pack/plugins/fleet/common/services/package_to_package_policy.ts b/x-pack/plugins/fleet/common/services/package_to_package_policy.ts index 36f5dc6ec4167..1fa4d39666cee 100644 --- a/x-pack/plugins/fleet/common/services/package_to_package_policy.ts +++ b/x-pack/plugins/fleet/common/services/package_to_package_policy.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { +import type { PackageInfo, RegistryPolicyTemplate, RegistryVarsEntry, diff --git a/x-pack/plugins/fleet/common/types/models/agent.ts b/x-pack/plugins/fleet/common/types/models/agent.ts index 2e18d427272ce..60eb47a6ecc43 100644 --- a/x-pack/plugins/fleet/common/types/models/agent.ts +++ b/x-pack/plugins/fleet/common/types/models/agent.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FullAgentPolicy } from './agent_policy'; +import type { FullAgentPolicy } from './agent_policy'; import { AGENT_TYPE_EPHEMERAL, AGENT_TYPE_PERMANENT, AGENT_TYPE_TEMPORARY } from '../../constants'; export type AgentType = diff --git a/x-pack/plugins/fleet/common/types/models/agent_policy.ts b/x-pack/plugins/fleet/common/types/models/agent_policy.ts index bc139537400cc..1aaca4fc5d932 100644 --- a/x-pack/plugins/fleet/common/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/common/types/models/agent_policy.ts @@ -6,9 +6,9 @@ */ import { agentPolicyStatuses } from '../../constants'; -import { DataType, ValueOf } from '../../types'; -import { PackagePolicy, PackagePolicyPackage } from './package_policy'; -import { Output } from './output'; +import type { DataType, ValueOf } from '../../types'; +import type { PackagePolicy, PackagePolicyPackage } from './package_policy'; +import type { Output } from './output'; export type AgentPolicyStatus = typeof agentPolicyStatuses; diff --git a/x-pack/plugins/fleet/common/types/models/epm.ts b/x-pack/plugins/fleet/common/types/models/epm.ts index 5c99831eaac34..e42ef7515b4c1 100644 --- a/x-pack/plugins/fleet/common/types/models/epm.ts +++ b/x-pack/plugins/fleet/common/types/models/epm.ts @@ -7,7 +7,7 @@ // Follow pattern from https://github.com/elastic/kibana/pull/52447 // TODO: Update when https://github.com/elastic/kibana/issues/53021 is closed -import { SavedObject, SavedObjectAttributes, SavedObjectReference } from 'src/core/public'; +import type { SavedObject, SavedObjectAttributes, SavedObjectReference } from 'src/core/public'; import { ASSETS_SAVED_OBJECT_TYPE, agentAssetTypes, @@ -16,8 +16,8 @@ import { installationStatuses, requiredPackages, } from '../../constants'; -import { ValueOf } from '../../types'; -import { PackageSpecManifest, PackageSpecScreenshot } from './package_spec'; +import type { ValueOf } from '../../types'; +import type { PackageSpecManifest, PackageSpecScreenshot } from './package_spec'; export type InstallationStatus = typeof installationStatuses; diff --git a/x-pack/plugins/fleet/common/types/models/package_spec.ts b/x-pack/plugins/fleet/common/types/models/package_spec.ts index f9de06704a697..65be72cbb7b6b 100644 --- a/x-pack/plugins/fleet/common/types/models/package_spec.ts +++ b/x-pack/plugins/fleet/common/types/models/package_spec.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RegistryPolicyTemplate } from './epm'; +import type { RegistryPolicyTemplate } from './epm'; // Based on https://github.com/elastic/package-spec/blob/master/versions/1/manifest.spec.yml#L8 export interface PackageSpecManifest { diff --git a/x-pack/plugins/fleet/common/types/models/settings.ts b/x-pack/plugins/fleet/common/types/models/settings.ts index 04adfb6a3089c..56557fb6703b4 100644 --- a/x-pack/plugins/fleet/common/types/models/settings.ts +++ b/x-pack/plugins/fleet/common/types/models/settings.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { SavedObjectAttributes } from 'src/core/public'; +import type { SavedObjectAttributes } from 'src/core/public'; export interface BaseSettings { agent_auto_upgrade: boolean; diff --git a/x-pack/plugins/fleet/common/types/rest_spec/agent.ts b/x-pack/plugins/fleet/common/types/rest_spec/agent.ts index 4c4c77c784d84..93cbb8369a3b1 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/agent.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/agent.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { +import type { Agent, AgentAction, NewAgentAction, diff --git a/x-pack/plugins/fleet/common/types/rest_spec/agent_policy.ts b/x-pack/plugins/fleet/common/types/rest_spec/agent_policy.ts index 5f8461019ab49..4b64044e1f2de 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/agent_policy.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/agent_policy.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { AgentPolicy, NewAgentPolicy, FullAgentPolicy } from '../models'; -import { ListWithKuery } from './common'; +import type { AgentPolicy, NewAgentPolicy, FullAgentPolicy } from '../models'; +import type { ListWithKuery } from './common'; export interface GetAgentPoliciesRequest { query: ListWithKuery & { diff --git a/x-pack/plugins/fleet/common/types/rest_spec/common.ts b/x-pack/plugins/fleet/common/types/rest_spec/common.ts index de5e87d2e59a5..15a280a62450a 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/common.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/common.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { HttpFetchQuery } from 'src/core/public'; +import type { HttpFetchQuery } from 'src/core/public'; export interface ListWithKuery extends HttpFetchQuery { page?: number; diff --git a/x-pack/plugins/fleet/common/types/rest_spec/data_stream.ts b/x-pack/plugins/fleet/common/types/rest_spec/data_stream.ts index dc46e0514abd0..bc2eef71721ff 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/data_stream.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/data_stream.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { DataStream } from '../models'; +import type { DataStream } from '../models'; export interface GetDataStreamsResponse { data_streams: DataStream[]; diff --git a/x-pack/plugins/fleet/common/types/rest_spec/enrollment_api_key.ts b/x-pack/plugins/fleet/common/types/rest_spec/enrollment_api_key.ts index b0373e58b045c..da870deb31d9c 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/enrollment_api_key.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/enrollment_api_key.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { EnrollmentAPIKey } from '../models'; +import type { EnrollmentAPIKey } from '../models'; export interface GetEnrollmentAPIKeysRequest { query: { diff --git a/x-pack/plugins/fleet/common/types/rest_spec/epm.ts b/x-pack/plugins/fleet/common/types/rest_spec/epm.ts index af622a51c719b..3a9c9a0cfae9f 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/epm.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/epm.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { +import type { AssetReference, CategorySummaryList, Installable, diff --git a/x-pack/plugins/fleet/common/types/rest_spec/output.ts b/x-pack/plugins/fleet/common/types/rest_spec/output.ts index 43a7e2cfd2e00..ef3c2f9f998ca 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/output.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/output.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Output } from '../models'; +import type { Output } from '../models'; export interface GetOneOutputResponse { item: Output; diff --git a/x-pack/plugins/fleet/common/types/rest_spec/package_policy.ts b/x-pack/plugins/fleet/common/types/rest_spec/package_policy.ts index eeadf6a2f9b6d..e6d893b9376a7 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/package_policy.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/package_policy.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PackagePolicy, NewPackagePolicy, UpdatePackagePolicy } from '../models'; +import type { PackagePolicy, NewPackagePolicy, UpdatePackagePolicy } from '../models'; export interface GetPackagePoliciesRequest { query: { diff --git a/x-pack/plugins/fleet/common/types/rest_spec/settings.ts b/x-pack/plugins/fleet/common/types/rest_spec/settings.ts index caff6573ddd0a..0b01815b2ef44 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/settings.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/settings.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Settings } from '../models'; +import type { Settings } from '../models'; export interface GetSettingsResponse { item: Settings; diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_config.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_config.ts index f32975d1180cd..cee563280e7bf 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_config.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_config.ts @@ -6,7 +6,7 @@ */ import React, { useContext } from 'react'; -import { FleetConfigType } from '../../../plugin'; +import type { FleetConfigType } from '../../../plugin'; export const ConfigContext = React.createContext(null); diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_core.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_core.ts index 21dfdbfc32139..30b3a5da94e1c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_core.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_core.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FleetStartServices } from '../../../plugin'; +import type { FleetStartServices } from '../../../plugin'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; export function useStartServices(): FleetStartServices { diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_link.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_link.ts index 0463e512bff3e..bcb8c4c749211 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_link.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_link.ts @@ -5,13 +5,8 @@ * 2.0. */ -import { - BASE_PATH, - StaticPage, - DynamicPage, - DynamicPagePathValues, - pagePathGetters, -} from '../constants'; +import { BASE_PATH, pagePathGetters } from '../constants'; +import type { StaticPage, DynamicPage, DynamicPagePathValues } from '../constants'; import { useStartServices } from './'; const getPath = (page: StaticPage | DynamicPage, values: DynamicPagePathValues = {}): string => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_package_icon_type.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_package_icon_type.ts index 0d0b455999a8b..679c44f2c0ea9 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_package_icon_type.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_package_icon_type.ts @@ -7,7 +7,7 @@ import { useEffect, useState } from 'react'; import { ICON_TYPES } from '@elastic/eui'; -import { PackageInfo, PackageListItem } from '../types'; +import type { PackageInfo, PackageListItem } from '../types'; import { useLinks } from '../sections/epm/hooks'; import { sendGetPackageInfoByKey } from './index'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agent_policy.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agent_policy.ts index 2cba3b48a9564..d60383c15d2f4 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agent_policy.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agent_policy.ts @@ -5,14 +5,10 @@ * 2.0. */ -import { - useRequest, - sendRequest, - useConditionalRequest, - SendConditionalRequestConfig, -} from './use_request'; +import { useRequest, sendRequest, useConditionalRequest } from './use_request'; +import type { SendConditionalRequestConfig } from './use_request'; import { agentPolicyRouteService } from '../../services'; -import { +import type { GetAgentPoliciesRequest, GetAgentPoliciesResponse, GetOneAgentPolicyResponse, diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agents.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agents.ts index 7f774a85ff9d6..a40ebbf78e0f2 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agents.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agents.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { useRequest, UseRequestConfig, sendRequest } from './use_request'; +import { useRequest, sendRequest } from './use_request'; +import type { UseRequestConfig } from './use_request'; import { agentRouteService } from '../../services'; -import { +import type { GetOneAgentResponse, GetOneAgentEventsResponse, GetOneAgentEventsRequest, diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/app.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/app.ts index 00f093474695f..2e93a1700d08c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/app.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/app.ts @@ -7,7 +7,7 @@ import { sendRequest } from './use_request'; import { appRoutesService } from '../../services'; -import { CheckPermissionsResponse } from '../../types'; +import type { CheckPermissionsResponse } from '../../types'; export const sendGetPermissionsCheck = () => { return sendRequest({ diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/data_stream.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/data_stream.ts index 9e275e606f667..16e27596e7090 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/data_stream.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/data_stream.ts @@ -7,7 +7,7 @@ import { useRequest } from './use_request'; import { dataStreamRouteService } from '../../services'; -import { GetDataStreamsResponse } from '../../types'; +import type { GetDataStreamsResponse } from '../../types'; export const useGetDataStreams = () => { return useRequest({ diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/enrollment_api_keys.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/enrollment_api_keys.ts index cd0397d611df1..4aad8b7314482 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/enrollment_api_keys.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/enrollment_api_keys.ts @@ -5,15 +5,10 @@ * 2.0. */ -import { - useRequest, - UseRequestConfig, - sendRequest, - useConditionalRequest, - SendConditionalRequestConfig, -} from './use_request'; +import { useRequest, sendRequest, useConditionalRequest } from './use_request'; +import type { UseRequestConfig, SendConditionalRequestConfig } from './use_request'; import { enrollmentAPIKeyRouteService } from '../../services'; -import { +import type { GetOneEnrollmentAPIKeyResponse, GetEnrollmentAPIKeysResponse, GetEnrollmentAPIKeysRequest, diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/epm.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/epm.ts index f518ee2ea44ff..45e754849b5bc 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/epm.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/epm.ts @@ -7,7 +7,7 @@ import { useRequest, sendRequest } from './use_request'; import { epmRouteService } from '../../services'; -import { +import type { GetCategoriesRequest, GetCategoriesResponse, GetPackagesRequest, @@ -17,7 +17,7 @@ import { InstallPackageResponse, DeletePackageResponse, } from '../../types'; -import { GetStatsResponse } from '../../../../../common'; +import type { GetStatsResponse } from '../../../../../common'; export const useGetCategories = (query: GetCategoriesRequest['query'] = {}) => { return useRequest({ diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/outputs.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/outputs.ts index 1c43b84b2bc02..64c82d2a04790 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/outputs.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/outputs.ts @@ -7,7 +7,7 @@ import { sendRequest, useRequest } from './use_request'; import { outputRoutesService } from '../../services'; -import { PutOutputRequest, GetOutputsResponse } from '../../types'; +import type { PutOutputRequest, GetOutputsResponse } from '../../types'; export function useGetOutputs() { return useRequest({ diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/package_policy.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/package_policy.ts index ee4a4e4c24e28..1266f47a80e21 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/package_policy.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/package_policy.ts @@ -7,13 +7,13 @@ import { sendRequest, useRequest } from './use_request'; import { packagePolicyRouteService } from '../../services'; -import { +import type { CreatePackagePolicyRequest, CreatePackagePolicyResponse, UpdatePackagePolicyRequest, UpdatePackagePolicyResponse, } from '../../types'; -import { +import type { DeletePackagePoliciesRequest, DeletePackagePoliciesResponse, GetPackagePoliciesRequest, diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/settings.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/settings.ts index 9cc54a5c4223b..bf4ea6eacb3c1 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/settings.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/settings.ts @@ -7,7 +7,7 @@ import { sendRequest, useRequest } from './use_request'; import { settingsRoutesService } from '../../services'; -import { PutSettingsResponse, PutSettingsRequest, GetSettingsResponse } from '../../types'; +import type { PutSettingsResponse, PutSettingsRequest, GetSettingsResponse } from '../../types'; export function useGetSettings() { return useRequest({ diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/setup.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/setup.ts index 0f52712e8ded9..001b8af99aec5 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/setup.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/setup.ts @@ -7,7 +7,7 @@ import { sendRequest } from './use_request'; import { setupRouteService, fleetSetupRouteService } from '../../services'; -import { GetFleetStatusResponse } from '../../types'; +import type { GetFleetStatusResponse } from '../../types'; export const sendSetup = () => { return sendRequest({ diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/use_request.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/use_request.ts index 4c4433c2b4f89..985f4d71d6a75 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/use_request.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/use_request.ts @@ -6,14 +6,16 @@ */ import { useState, useEffect } from 'react'; -import { HttpSetup } from 'src/core/public'; +import type { HttpSetup } from 'src/core/public'; import { - SendRequestConfig, - SendRequestResponse, UseRequestConfig as _UseRequestConfig, sendRequest as _sendRequest, useRequest as _useRequest, } from '../../../../../../../../src/plugins/es_ui_shared/public'; +import type { + SendRequestConfig, + SendRequestResponse, +} from '../../../../../../../../src/plugins/es_ui_shared/public'; let httpClient: HttpSetup; diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_ui_extension.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_ui_extension.ts index 00eff8f91490b..f6b3cfd2b3642 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_ui_extension.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_ui_extension.ts @@ -6,7 +6,7 @@ */ import React, { useContext } from 'react'; -import { UIExtensionPoint, UIExtensionsStorage } from '../types'; +import type { UIExtensionPoint, UIExtensionsStorage } from '../types'; export const UIExtensionsContext = React.createContext({}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_url_pagination.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_url_pagination.ts index 7224a460bf414..090ce34ae244a 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_url_pagination.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_url_pagination.ts @@ -8,7 +8,8 @@ import { useCallback, useEffect, useMemo } from 'react'; import { useHistory, useLocation } from 'react-router-dom'; import { useUrlParams } from './use_url_params'; -import { PAGE_SIZE_OPTIONS, Pagination, usePagination } from './use_pagination'; +import { PAGE_SIZE_OPTIONS, usePagination } from './use_pagination'; +import type { Pagination } from './use_pagination'; type SetUrlPagination = (pagination: Pagination) => void; interface UrlPagination { diff --git a/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_configuration.ts b/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_configuration.ts index c5ae6d7fd4089..81ef6a6703c34 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_configuration.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_configuration.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FleetConfigType } from '../../../plugin'; +import type { FleetConfigType } from '../../../plugin'; export const createConfigurationMock = (): FleetConfigType => { return { diff --git a/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_dependencies.ts b/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_dependencies.ts index f8b05e13e2956..8207e3d89fc56 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_dependencies.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_dependencies.ts @@ -8,7 +8,7 @@ import { dataPluginMock } from '../../../../../../../src/plugins/data/public/mocks'; import { licensingMock } from '../../../../../licensing/public/mocks'; import { homePluginMock } from '../../../../../../../src/plugins/home/public/mocks'; -import { MockedFleetSetupDeps, MockedFleetStartDeps } from './types'; +import type { MockedFleetSetupDeps, MockedFleetStartDeps } from './types'; export const createSetupDepsMock = (): MockedFleetSetupDeps => { return { diff --git a/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_interfaces.ts b/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_interfaces.ts index d11ca5b041be1..3c76452f17ce7 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_interfaces.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_interfaces.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { UIExtensionsStorage } from '../types'; +import type { UIExtensionsStorage } from '../types'; import { createExtensionRegistrationCallback } from '../services/ui_extensions'; -import { MockedFleetStart } from './types'; +import type { MockedFleetStart } from './types'; export const createStartMock = (extensionsStorage: UIExtensionsStorage = {}): MockedFleetStart => { return { diff --git a/x-pack/plugins/fleet/public/applications/fleet/mock/types.ts b/x-pack/plugins/fleet/public/applications/fleet/mock/types.ts index 0a55fa43bf18d..660fe6af29fb1 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/mock/types.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/mock/types.ts @@ -5,8 +5,13 @@ * 2.0. */ -import { MockedKeys } from '@kbn/utility-types/jest'; -import { FleetSetupDeps, FleetStart, FleetStartDeps, FleetStartServices } from '../../../plugin'; +import type { MockedKeys } from '@kbn/utility-types/jest'; +import type { + FleetSetupDeps, + FleetStart, + FleetStartDeps, + FleetStartServices, +} from '../../../plugin'; export type MockedFleetStartServices = MockedKeys; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/has_invalid_but_required_var.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/has_invalid_but_required_var.ts index 84bdb3798f73f..a9a0480098323 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/has_invalid_but_required_var.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/has_invalid_but_required_var.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PackagePolicyConfigRecord, RegistryVarsEntry } from '../../../../types'; +import type { PackagePolicyConfigRecord, RegistryVarsEntry } from '../../../../types'; import { validatePackagePolicyConfig } from './'; export const hasInvalidButRequiredVar = ( diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/is_advanced_var.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/is_advanced_var.ts index 1e60b5e6e0bbb..1f72073573d7b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/is_advanced_var.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/is_advanced_var.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RegistryVarsEntry } from '../../../../types'; +import type { RegistryVarsEntry } from '../../../../types'; export const isAdvancedVar = (varDef: RegistryVarsEntry): boolean => { if (varDef.show_user || (varDef.required && varDef.default === undefined)) { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.test.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.test.ts index 5e05f10cd74be..e1e0d026966c3 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.test.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.test.ts @@ -6,7 +6,7 @@ */ import { installationStatuses } from '../../../../../../../common/constants'; -import { PackageInfo, NewPackagePolicy, RegistryPolicyTemplate } from '../../../../types'; +import type { PackageInfo, NewPackagePolicy, RegistryPolicyTemplate } from '../../../../types'; import { validatePackagePolicy, validationHasErrors } from './validate_package_policy'; describe('Fleet - validatePackagePolicy()', () => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts index c39dfb4a99c12..c727be683c130 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import { safeLoad } from 'js-yaml'; import { getFlattenedObject, isValidNamespace } from '../../../../services'; -import { +import type { NewPackagePolicy, PackagePolicyInput, PackagePolicyInputStream, diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/release_badge.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/release_badge.ts index 21d205f4ac56d..9e4e51e410e7e 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/release_badge.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/release_badge.ts @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import { RegistryRelease } from '../../../types'; +import type { RegistryRelease } from '../../../types'; export const RELEASE_BADGE_LABEL: { [key in Exclude]: string } = { beta: i18n.translate('xpack.fleet.epm.releaseBadge.betaLabel', { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/policies/use_package_policies_with_agent_policy.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/policies/use_package_policies_with_agent_policy.ts index ff8343314b4ac..77811a92093ee 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/policies/use_package_policies_with_agent_policy.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/policies/use_package_policies_with_agent_policy.ts @@ -6,7 +6,7 @@ */ import { useEffect, useMemo, useState } from 'react'; -import { +import type { PackagePolicy, GetAgentPoliciesResponse, GetAgentPoliciesResponseItem, @@ -15,10 +15,8 @@ import { import { agentPolicyRouteService } from '../../../../../services'; import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../../../../constants'; import { useGetPackagePolicies } from '../../../../../hooks'; -import { - SendConditionalRequestConfig, - useConditionalRequest, -} from '../../../../../hooks/use_request/use_request'; +import { useConditionalRequest } from '../../../../../hooks/use_request/use_request'; +import type { SendConditionalRequestConfig } from '../../../../../hooks/use_request/use_request'; export interface PackagePolicyEnriched extends PackagePolicy { _agentPolicy: GetAgentPoliciesResponseItem | undefined; diff --git a/x-pack/plugins/fleet/public/applications/fleet/services/ui_extensions.test.ts b/x-pack/plugins/fleet/public/applications/fleet/services/ui_extensions.test.ts index d0e22f90e2640..bcddcb4afdbb3 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/services/ui_extensions.test.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/services/ui_extensions.test.ts @@ -6,8 +6,7 @@ */ import { lazy } from 'react'; - -import { +import type { PackagePolicyEditExtensionComponent, UIExtensionRegistrationCallback, UIExtensionsStorage, diff --git a/x-pack/plugins/fleet/public/applications/fleet/services/ui_extensions.ts b/x-pack/plugins/fleet/public/applications/fleet/services/ui_extensions.ts index 3583c9be93b99..d8b3e6212dbc1 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/services/ui_extensions.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/services/ui_extensions.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { UIExtensionRegistrationCallback, UIExtensionsStorage } from '../types'; +import type { UIExtensionRegistrationCallback, UIExtensionsStorage } from '../types'; /** Factory that returns a callback that can be used to register UI extensions */ export const createExtensionRegistrationCallback = ( diff --git a/x-pack/plugins/fleet/public/applications/fleet/types/intra_app_route_state.ts b/x-pack/plugins/fleet/public/applications/fleet/types/intra_app_route_state.ts index 52d93924a6312..b118797d7d38e 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/types/intra_app_route_state.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/types/intra_app_route_state.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { ApplicationStart } from 'kibana/public'; -import { PackagePolicy } from './'; +import type { ApplicationStart } from 'kibana/public'; +import type { PackagePolicy } from './'; /** * Supported routing state for the create package policy page routes diff --git a/x-pack/plugins/fleet/public/applications/fleet/types/ui_extensions.ts b/x-pack/plugins/fleet/public/applications/fleet/types/ui_extensions.ts index 2765c7e4b8b84..a9cea79ee7d8b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/types/ui_extensions.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/types/ui_extensions.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { ComponentType, LazyExoticComponent } from 'react'; -import { NewPackagePolicy, PackageInfo, PackagePolicy } from './index'; +import type { ComponentType, LazyExoticComponent } from 'react'; +import type { NewPackagePolicy, PackageInfo, PackagePolicy } from './index'; /** Register a Fleet UI extension */ export type UIExtensionRegistrationCallback = (extensionPoint: UIExtensionPoint) => void; diff --git a/x-pack/plugins/fleet/public/index.ts b/x-pack/plugins/fleet/public/index.ts index 34bdc99abdf77..3b1136747f343 100644 --- a/x-pack/plugins/fleet/public/index.ts +++ b/x-pack/plugins/fleet/public/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PluginInitializerContext } from 'src/core/public'; +import type { PluginInitializerContext } from 'src/core/public'; import { FleetPlugin } from './plugin'; export { FleetSetup, FleetStart } from './plugin'; diff --git a/x-pack/plugins/fleet/public/plugin.ts b/x-pack/plugins/fleet/public/plugin.ts index 50e647e271ecc..7f2fd4ee24d4f 100644 --- a/x-pack/plugins/fleet/public/plugin.ts +++ b/x-pack/plugins/fleet/public/plugin.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { +import type { AppMountParameters, CoreSetup, Plugin, @@ -14,18 +14,18 @@ import { } from 'src/core/public'; import { i18n } from '@kbn/i18n'; import { DEFAULT_APP_CATEGORIES, AppNavLinkStatus } from '../../../../src/core/public'; -import { DataPublicPluginSetup, DataPublicPluginStart } from '../../../../src/plugins/data/public'; -import { - HomePublicPluginSetup, - FeatureCatalogueCategory, -} from '../../../../src/plugins/home/public'; +import type { + DataPublicPluginSetup, + DataPublicPluginStart, +} from '../../../../src/plugins/data/public'; +import { FeatureCatalogueCategory } from '../../../../src/plugins/home/public'; +import type { HomePublicPluginSetup } from '../../../../src/plugins/home/public'; import { Storage } from '../../../../src/plugins/kibana_utils/public'; -import { LicensingPluginSetup } from '../../licensing/public'; -import { PLUGIN_ID, CheckPermissionsResponse, PostIngestSetupResponse } from '../common'; +import type { LicensingPluginSetup } from '../../licensing/public'; +import { PLUGIN_ID, setupRouteService, appRoutesService } from '../common'; +import type { CheckPermissionsResponse, PostIngestSetupResponse } from '../common'; import { BASE_PATH } from './applications/fleet/constants'; - -import { FleetConfigType } from '../common/types'; -import { setupRouteService, appRoutesService } from '../common'; +import type { FleetConfigType } from '../common/types'; import { licenseService } from './applications/fleet/hooks/use_license'; import { setHttpClient } from './applications/fleet/hooks/use_request/use_request'; import { @@ -34,7 +34,10 @@ import { TutorialModuleNotice, } from './applications/fleet/components/home_integration'; import { createExtensionRegistrationCallback } from './applications/fleet/services/ui_extensions'; -import { UIExtensionRegistrationCallback, UIExtensionsStorage } from './applications/fleet/types'; +import type { + UIExtensionRegistrationCallback, + UIExtensionsStorage, +} from './applications/fleet/types'; export { FleetConfigType } from '../common/types'; diff --git a/x-pack/plugins/fleet/scripts/dev_agent/script.ts b/x-pack/plugins/fleet/scripts/dev_agent/script.ts index fc4a10f4f655f..87727ef657e5f 100644 --- a/x-pack/plugins/fleet/scripts/dev_agent/script.ts +++ b/x-pack/plugins/fleet/scripts/dev_agent/script.ts @@ -8,7 +8,7 @@ import { createFlagError, run, ToolingLog } from '@kbn/dev-utils'; import fetch from 'node-fetch'; import os from 'os'; -import { +import type { Agent as _Agent, PostAgentCheckinRequest, PostAgentCheckinResponse, diff --git a/x-pack/plugins/fleet/server/collectors/agent_collectors.ts b/x-pack/plugins/fleet/server/collectors/agent_collectors.ts index ce4fb3e3df7d4..9aeae1dba0ea5 100644 --- a/x-pack/plugins/fleet/server/collectors/agent_collectors.ts +++ b/x-pack/plugins/fleet/server/collectors/agent_collectors.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { ElasticsearchClient, SavedObjectsClient } from 'kibana/server'; +import { SavedObjectsClient } from 'kibana/server'; +import type { ElasticsearchClient } from 'kibana/server'; import { FleetConfigType } from '../../common/types'; import * as AgentService from '../services/agents'; import { isFleetServerSetup } from '../services/fleet_server'; diff --git a/x-pack/plugins/fleet/server/collectors/config_collectors.ts b/x-pack/plugins/fleet/server/collectors/config_collectors.ts index d6a9e4868c9ab..d651ad4b5d3be 100644 --- a/x-pack/plugins/fleet/server/collectors/config_collectors.ts +++ b/x-pack/plugins/fleet/server/collectors/config_collectors.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FleetConfigType } from '..'; +import type { FleetConfigType } from '..'; export const getIsAgentsEnabled = (config: FleetConfigType) => { return config.agents.enabled; diff --git a/x-pack/plugins/fleet/server/collectors/helpers.ts b/x-pack/plugins/fleet/server/collectors/helpers.ts index 6104b8a8adee9..4de2330e70a2c 100644 --- a/x-pack/plugins/fleet/server/collectors/helpers.ts +++ b/x-pack/plugins/fleet/server/collectors/helpers.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { CoreSetup } from 'kibana/server'; -import { ElasticsearchClient, SavedObjectsClient } from '../../../../../src/core/server'; +import type { CoreSetup } from 'kibana/server'; +import { SavedObjectsClient } from '../../../../../src/core/server'; +import type { ElasticsearchClient } from '../../../../../src/core/server'; export async function getInternalClients( core: CoreSetup diff --git a/x-pack/plugins/fleet/server/collectors/package_collectors.ts b/x-pack/plugins/fleet/server/collectors/package_collectors.ts index 542208a557182..e0f5667fbe458 100644 --- a/x-pack/plugins/fleet/server/collectors/package_collectors.ts +++ b/x-pack/plugins/fleet/server/collectors/package_collectors.ts @@ -9,7 +9,7 @@ import { SavedObjectsClient } from 'kibana/server'; import _ from 'lodash'; import { getPackageSavedObjects } from '../services/epm/packages/get'; import { agentPolicyService } from '../services'; -import { NewPackagePolicy } from '../types'; +import type { NewPackagePolicy } from '../types'; export interface PackageUsage { name: string; diff --git a/x-pack/plugins/fleet/server/collectors/register.ts b/x-pack/plugins/fleet/server/collectors/register.ts index c2e043145cd97..30b3ced260172 100644 --- a/x-pack/plugins/fleet/server/collectors/register.ts +++ b/x-pack/plugins/fleet/server/collectors/register.ts @@ -5,13 +5,15 @@ * 2.0. */ -import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; -import { CoreSetup } from 'kibana/server'; +import type { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; +import type { CoreSetup } from 'kibana/server'; import { getIsAgentsEnabled } from './config_collectors'; -import { AgentUsage, getAgentUsage } from './agent_collectors'; +import { getAgentUsage } from './agent_collectors'; +import type { AgentUsage } from './agent_collectors'; import { getInternalClients } from './helpers'; -import { PackageUsage, getPackageUsage } from './package_collectors'; -import { FleetConfigType } from '..'; +import { getPackageUsage } from './package_collectors'; +import type { PackageUsage } from './package_collectors'; +import type { FleetConfigType } from '..'; interface Usage { agents_enabled: boolean; diff --git a/x-pack/plugins/fleet/server/errors/handlers.ts b/x-pack/plugins/fleet/server/errors/handlers.ts index 77db050309a60..2d5339b158d9b 100644 --- a/x-pack/plugins/fleet/server/errors/handlers.ts +++ b/x-pack/plugins/fleet/server/errors/handlers.ts @@ -6,9 +6,9 @@ */ import Boom, { isBoom } from '@hapi/boom'; -import { +import { KibanaRequest } from 'src/core/server'; +import type { RequestHandlerContext, - KibanaRequest, IKibanaResponse, KibanaResponseFactory, } from 'src/core/server'; diff --git a/x-pack/plugins/fleet/server/index.ts b/x-pack/plugins/fleet/server/index.ts index 2d189d5f940ae..cb5eb6413fdf8 100644 --- a/x-pack/plugins/fleet/server/index.ts +++ b/x-pack/plugins/fleet/server/index.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { schema, TypeOf } from '@kbn/config-schema'; -import { PluginConfigDescriptor, PluginInitializerContext } from 'src/core/server'; +import { schema } from '@kbn/config-schema'; +import type { TypeOf } from '@kbn/config-schema'; +import type { PluginConfigDescriptor, PluginInitializerContext } from 'src/core/server'; import { FleetPlugin } from './plugin'; import { AGENT_POLICY_ROLLOUT_RATE_LIMIT_INTERVAL_MS, diff --git a/x-pack/plugins/fleet/server/mocks.ts b/x-pack/plugins/fleet/server/mocks.ts index 430e38bd1bc3e..3a7f9ebcc9e53 100644 --- a/x-pack/plugins/fleet/server/mocks.ts +++ b/x-pack/plugins/fleet/server/mocks.ts @@ -12,12 +12,11 @@ import { } from 'src/core/server/mocks'; import { coreMock } from '../../../../src/core/server/mocks'; import { licensingMock } from '../../../plugins/licensing/server/mocks'; - -import { FleetAppContext } from './plugin'; +import type { FleetAppContext } from './plugin'; import { encryptedSavedObjectsMock } from '../../encrypted_saved_objects/server/mocks'; import { securityMock } from '../../security/server/mocks'; -import { PackagePolicyServiceInterface } from './services/package_policy'; -import { AgentPolicyServiceInterface, AgentService } from './services'; +import type { PackagePolicyServiceInterface } from './services/package_policy'; +import type { AgentPolicyServiceInterface, AgentService } from './services'; export const createAppContextStartContractMock = (): FleetAppContext => { return { diff --git a/x-pack/plugins/fleet/server/routes/agent/acks_handlers.test.ts b/x-pack/plugins/fleet/server/routes/agent/acks_handlers.test.ts index e1ed453a572f6..b1bd10e8a4a77 100644 --- a/x-pack/plugins/fleet/server/routes/agent/acks_handlers.test.ts +++ b/x-pack/plugins/fleet/server/routes/agent/acks_handlers.test.ts @@ -6,7 +6,7 @@ */ import { postAgentAcksHandlerBuilder } from './acks_handlers'; -import { +import type { ElasticsearchClient, KibanaResponseFactory, RequestHandlerContext, @@ -17,9 +17,9 @@ import { httpServerMock, savedObjectsClientMock, } from '../../../../../../src/core/server/mocks'; -import { PostAgentAcksResponse } from '../../../common/types/rest_spec'; +import type { PostAgentAcksResponse } from '../../../common/types/rest_spec'; import { AckEventSchema } from '../../types/models'; -import { AcksService } from '../../services/agents'; +import type { AcksService } from '../../services/agents'; describe('test acks schema', () => { it('validate that ack event schema expect action id', async () => { diff --git a/x-pack/plugins/fleet/server/routes/agent/acks_handlers.ts b/x-pack/plugins/fleet/server/routes/agent/acks_handlers.ts index 22b5035378a20..e05638b9e6d8e 100644 --- a/x-pack/plugins/fleet/server/routes/agent/acks_handlers.ts +++ b/x-pack/plugins/fleet/server/routes/agent/acks_handlers.ts @@ -7,10 +7,10 @@ // handlers that handle events from agents in response to actions received -import { RequestHandler } from 'kibana/server'; -import { AcksService } from '../../services/agents'; -import { AgentEvent } from '../../../common/types/models'; -import { PostAgentAcksRequest, PostAgentAcksResponse } from '../../../common/types/rest_spec'; +import type { RequestHandler } from 'kibana/server'; +import type { AcksService } from '../../services/agents'; +import type { AgentEvent } from '../../../common/types/models'; +import type { PostAgentAcksRequest, PostAgentAcksResponse } from '../../../common/types/rest_spec'; import { defaultIngestErrorHandler } from '../../errors'; export const postAgentAcksHandlerBuilder = function ( diff --git a/x-pack/plugins/fleet/server/routes/agent/actions_handlers.test.ts b/x-pack/plugins/fleet/server/routes/agent/actions_handlers.test.ts index 6affe332b8f87..6c12a826a11df 100644 --- a/x-pack/plugins/fleet/server/routes/agent/actions_handlers.test.ts +++ b/x-pack/plugins/fleet/server/routes/agent/actions_handlers.test.ts @@ -6,7 +6,7 @@ */ import { NewAgentActionSchema } from '../../types/models'; -import { +import type { ElasticsearchClient, KibanaResponseFactory, RequestHandlerContext, @@ -17,10 +17,10 @@ import { savedObjectsClientMock, httpServerMock, } from 'src/core/server/mocks'; -import { ActionsService } from '../../services/agents'; -import { AgentAction } from '../../../common/types/models'; +import type { ActionsService } from '../../services/agents'; +import type { AgentAction } from '../../../common/types/models'; import { postNewAgentActionHandlerBuilder } from './actions_handlers'; -import { +import type { PostNewAgentActionRequest, PostNewAgentActionResponse, } from '../../../common/types/rest_spec'; diff --git a/x-pack/plugins/fleet/server/routes/agent/actions_handlers.ts b/x-pack/plugins/fleet/server/routes/agent/actions_handlers.ts index d032945245faf..2d5cfa4fd5b4f 100644 --- a/x-pack/plugins/fleet/server/routes/agent/actions_handlers.ts +++ b/x-pack/plugins/fleet/server/routes/agent/actions_handlers.ts @@ -7,11 +7,11 @@ // handlers that handle agent actions request -import { RequestHandler } from 'kibana/server'; -import { TypeOf } from '@kbn/config-schema'; +import type { RequestHandler } from 'kibana/server'; +import type { TypeOf } from '@kbn/config-schema'; import { PostNewAgentActionRequestSchema } from '../../types/rest_spec'; -import { ActionsService } from '../../services/agents'; -import { PostNewAgentActionResponse } from '../../../common/types/rest_spec'; +import type { ActionsService } from '../../services/agents'; +import type { PostNewAgentActionResponse } from '../../../common/types/rest_spec'; import { defaultIngestErrorHandler } from '../../errors'; export const postNewAgentActionHandlerBuilder = function ( diff --git a/x-pack/plugins/fleet/server/routes/agent/handlers.ts b/x-pack/plugins/fleet/server/routes/agent/handlers.ts index cd91e8c325c06..d5e2df56da601 100644 --- a/x-pack/plugins/fleet/server/routes/agent/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/agent/handlers.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { RequestHandler } from 'src/core/server'; -import { TypeOf } from '@kbn/config-schema'; +import type { RequestHandler } from 'src/core/server'; +import type { TypeOf } from '@kbn/config-schema'; import { AbortController } from 'abort-controller'; -import { +import type { GetAgentsResponse, GetOneAgentResponse, GetOneAgentEventsResponse, @@ -25,11 +25,11 @@ import { UpdateAgentRequestSchema, DeleteAgentRequestSchema, GetOneAgentEventsRequestSchema, - PostAgentCheckinRequest, GetAgentStatusRequestSchema, PutAgentReassignRequestSchema, PostBulkAgentReassignRequestSchema, } from '../../types'; +import type { PostAgentCheckinRequest } from '../../types'; import { defaultIngestErrorHandler } from '../../errors'; import { licenseService } from '../../services'; import * as AgentService from '../../services/agents'; diff --git a/x-pack/plugins/fleet/server/routes/agent/index.ts b/x-pack/plugins/fleet/server/routes/agent/index.ts index 86c88aeaf46ac..0b9e180a1cfd8 100644 --- a/x-pack/plugins/fleet/server/routes/agent/index.ts +++ b/x-pack/plugins/fleet/server/routes/agent/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter, RouteValidationResultFactory } from 'src/core/server'; +import type { IRouter, RouteValidationResultFactory } from 'src/core/server'; import Ajv from 'ajv'; import { PLUGIN_ID, @@ -51,7 +51,7 @@ import * as AgentService from '../../services/agents'; import { postNewAgentActionHandlerBuilder } from './actions_handlers'; import { appContextService } from '../../services'; import { postAgentUnenrollHandler, postBulkAgentsUnenrollHandler } from './unenroll_handler'; -import { FleetConfigType } from '../..'; +import type { FleetConfigType } from '../..'; import { postAgentUpgradeHandler, postBulkAgentsUpgradeHandler } from './upgrade_handler'; const ajv = new Ajv({ diff --git a/x-pack/plugins/fleet/server/routes/agent/unenroll_handler.ts b/x-pack/plugins/fleet/server/routes/agent/unenroll_handler.ts index 614ccd8a26624..07ca776ef104b 100644 --- a/x-pack/plugins/fleet/server/routes/agent/unenroll_handler.ts +++ b/x-pack/plugins/fleet/server/routes/agent/unenroll_handler.ts @@ -5,9 +5,12 @@ * 2.0. */ -import { RequestHandler } from 'src/core/server'; -import { TypeOf } from '@kbn/config-schema'; -import { PostAgentUnenrollResponse, PostBulkAgentUnenrollResponse } from '../../../common/types'; +import type { RequestHandler } from 'src/core/server'; +import type { TypeOf } from '@kbn/config-schema'; +import type { + PostAgentUnenrollResponse, + PostBulkAgentUnenrollResponse, +} from '../../../common/types'; import { PostAgentUnenrollRequestSchema, PostBulkAgentUnenrollRequestSchema } from '../../types'; import { licenseService } from '../../services'; import * as AgentService from '../../services/agents'; diff --git a/x-pack/plugins/fleet/server/routes/agent/upgrade_handler.ts b/x-pack/plugins/fleet/server/routes/agent/upgrade_handler.ts index 086a9411f20b8..4999801c4122a 100644 --- a/x-pack/plugins/fleet/server/routes/agent/upgrade_handler.ts +++ b/x-pack/plugins/fleet/server/routes/agent/upgrade_handler.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { RequestHandler } from 'src/core/server'; -import { TypeOf } from '@kbn/config-schema'; +import type { RequestHandler } from 'src/core/server'; +import type { TypeOf } from '@kbn/config-schema'; import semverCoerce from 'semver/functions/coerce'; -import { PostAgentUpgradeResponse, PostBulkAgentUpgradeResponse } from '../../../common/types'; +import type { PostAgentUpgradeResponse, PostBulkAgentUpgradeResponse } from '../../../common/types'; import { PostAgentUpgradeRequestSchema, PostBulkAgentUpgradeRequestSchema } from '../../types'; import * as AgentService from '../../services/agents'; import { appContextService } from '../../services'; diff --git a/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts b/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts index 411f7a74a6ab2..a0a30b1c1190b 100644 --- a/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { TypeOf } from '@kbn/config-schema'; -import { RequestHandler, ResponseHeaders } from 'src/core/server'; +import type { TypeOf } from '@kbn/config-schema'; +import type { RequestHandler, ResponseHeaders } from 'src/core/server'; import bluebird from 'bluebird'; import { fullAgentPolicyToYaml } from '../../../common/services'; import { appContextService, agentPolicyService, packagePolicyService } from '../../services'; @@ -20,10 +20,10 @@ import { CopyAgentPolicyRequestSchema, DeleteAgentPolicyRequestSchema, GetFullAgentPolicyRequestSchema, - AgentPolicy, - NewPackagePolicy, } from '../../types'; -import { +import type { AgentPolicy, NewPackagePolicy } from '../../types'; +import { defaultPackages } from '../../../common'; +import type { GetAgentPoliciesResponse, GetAgentPoliciesResponseItem, GetOneAgentPolicyResponse, @@ -32,7 +32,6 @@ import { CopyAgentPolicyResponse, DeleteAgentPolicyResponse, GetFullAgentPolicyResponse, - defaultPackages, } from '../../../common'; import { defaultIngestErrorHandler } from '../../errors'; diff --git a/x-pack/plugins/fleet/server/routes/agent_policy/index.ts b/x-pack/plugins/fleet/server/routes/agent_policy/index.ts index 256e24217558e..5cf58414f7992 100644 --- a/x-pack/plugins/fleet/server/routes/agent_policy/index.ts +++ b/x-pack/plugins/fleet/server/routes/agent_policy/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter } from 'src/core/server'; +import type { IRouter } from 'src/core/server'; import { PLUGIN_ID, AGENT_POLICY_API_ROUTES } from '../../constants'; import { GetAgentPoliciesRequestSchema, diff --git a/x-pack/plugins/fleet/server/routes/app/index.ts b/x-pack/plugins/fleet/server/routes/app/index.ts index 64c1bdf1d02f9..04c5bf2df47be 100644 --- a/x-pack/plugins/fleet/server/routes/app/index.ts +++ b/x-pack/plugins/fleet/server/routes/app/index.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { IRouter, RequestHandler } from 'src/core/server'; +import type { IRouter, RequestHandler } from 'src/core/server'; import { APP_API_ROUTES } from '../../constants'; import { appContextService } from '../../services'; -import { CheckPermissionsResponse } from '../../../common'; +import type { CheckPermissionsResponse } from '../../../common'; export const getCheckPermissionsHandler: RequestHandler = async (context, request, response) => { const body: CheckPermissionsResponse = { success: true }; diff --git a/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts b/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts index 4424fc478c682..2826840d773e0 100644 --- a/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts @@ -5,10 +5,11 @@ * 2.0. */ -import { RequestHandler, SavedObjectsClientContract } from 'src/core/server'; import { keyBy, keys, merge } from 'lodash'; -import { DataStream } from '../../types'; -import { GetDataStreamsResponse, KibanaAssetType, KibanaSavedObjectType } from '../../../common'; +import type { RequestHandler, SavedObjectsClientContract } from 'src/core/server'; +import type { DataStream } from '../../types'; +import { KibanaAssetType, KibanaSavedObjectType } from '../../../common'; +import type { GetDataStreamsResponse } from '../../../common'; import { getPackageSavedObjects, getKibanaSavedObject } from '../../services/epm/packages/get'; import { defaultIngestErrorHandler } from '../../errors'; diff --git a/x-pack/plugins/fleet/server/routes/data_streams/index.ts b/x-pack/plugins/fleet/server/routes/data_streams/index.ts index 7373b684002f2..05efff12d01da 100644 --- a/x-pack/plugins/fleet/server/routes/data_streams/index.ts +++ b/x-pack/plugins/fleet/server/routes/data_streams/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter } from 'src/core/server'; +import type { IRouter } from 'src/core/server'; import { PLUGIN_ID, DATA_STREAM_API_ROUTES } from '../../constants'; import { getListHandler } from './handlers'; diff --git a/x-pack/plugins/fleet/server/routes/enrollment_api_key/handler.ts b/x-pack/plugins/fleet/server/routes/enrollment_api_key/handler.ts index a46675c5be3ff..b41af3b0c770c 100644 --- a/x-pack/plugins/fleet/server/routes/enrollment_api_key/handler.ts +++ b/x-pack/plugins/fleet/server/routes/enrollment_api_key/handler.ts @@ -5,15 +5,15 @@ * 2.0. */ -import { RequestHandler } from 'src/core/server'; -import { TypeOf } from '@kbn/config-schema'; +import type { RequestHandler } from 'src/core/server'; +import type { TypeOf } from '@kbn/config-schema'; import { GetEnrollmentAPIKeysRequestSchema, PostEnrollmentAPIKeyRequestSchema, DeleteEnrollmentAPIKeyRequestSchema, GetOneEnrollmentAPIKeyRequestSchema, } from '../../types'; -import { +import type { GetEnrollmentAPIKeysResponse, GetOneEnrollmentAPIKeyResponse, DeleteEnrollmentAPIKeyResponse, diff --git a/x-pack/plugins/fleet/server/routes/enrollment_api_key/index.ts b/x-pack/plugins/fleet/server/routes/enrollment_api_key/index.ts index ee319987d1e91..cf736edd4633e 100644 --- a/x-pack/plugins/fleet/server/routes/enrollment_api_key/index.ts +++ b/x-pack/plugins/fleet/server/routes/enrollment_api_key/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter } from 'src/core/server'; +import type { IRouter } from 'src/core/server'; import { PLUGIN_ID, ENROLLMENT_API_KEY_ROUTES } from '../../constants'; import { GetEnrollmentAPIKeysRequestSchema, diff --git a/x-pack/plugins/fleet/server/routes/epm/handlers.ts b/x-pack/plugins/fleet/server/routes/epm/handlers.ts index 47e53b27a600f..09a53f2c0d8ff 100644 --- a/x-pack/plugins/fleet/server/routes/epm/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/epm/handlers.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { TypeOf } from '@kbn/config-schema'; +import type { TypeOf } from '@kbn/config-schema'; import mime from 'mime-types'; import path from 'path'; -import { RequestHandler, ResponseHeaders, KnownHeaders } from 'src/core/server'; -import { +import type { RequestHandler, ResponseHeaders, KnownHeaders } from 'src/core/server'; +import type { GetInfoResponse, InstallPackageResponse, DeletePackageResponse, @@ -33,7 +33,6 @@ import { GetStatsRequestSchema, } from '../../types'; import { - BulkInstallResponse, bulkInstallPackages, getCategories, getPackages, @@ -47,6 +46,7 @@ import { getInstallationObject, getInstallation, } from '../../services/epm/packages'; +import type { BulkInstallResponse } from '../../services/epm/packages'; import { defaultIngestErrorHandler, ingestErrorToResponseOptions } from '../../errors'; import { splitPkgKey } from '../../services/epm/registry'; import { licenseService } from '../../services'; diff --git a/x-pack/plugins/fleet/server/routes/epm/index.ts b/x-pack/plugins/fleet/server/routes/epm/index.ts index f5788fe252beb..9ed4d7e11ad29 100644 --- a/x-pack/plugins/fleet/server/routes/epm/index.ts +++ b/x-pack/plugins/fleet/server/routes/epm/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter } from 'src/core/server'; +import type { IRouter } from 'src/core/server'; import { PLUGIN_ID, EPM_API_ROUTES } from '../../constants'; import { getCategoriesHandler, diff --git a/x-pack/plugins/fleet/server/routes/install_script/index.ts b/x-pack/plugins/fleet/server/routes/install_script/index.ts index c7cc0da1ce48c..5fb2ea726c62b 100644 --- a/x-pack/plugins/fleet/server/routes/install_script/index.ts +++ b/x-pack/plugins/fleet/server/routes/install_script/index.ts @@ -6,7 +6,8 @@ */ import url from 'url'; -import { IRouter, BasePath, KibanaRequest } from 'src/core/server'; +import { BasePath, KibanaRequest } from 'src/core/server'; +import type { IRouter } from 'src/core/server'; import { INSTALL_SCRIPT_API_ROUTES } from '../../constants'; import { getScript } from '../../services/install_script'; import { InstallScriptRequestSchema } from '../../types'; diff --git a/x-pack/plugins/fleet/server/routes/limited_concurrency.test.ts b/x-pack/plugins/fleet/server/routes/limited_concurrency.test.ts index f71aeb80a6d3e..626df529c1236 100644 --- a/x-pack/plugins/fleet/server/routes/limited_concurrency.test.ts +++ b/x-pack/plugins/fleet/server/routes/limited_concurrency.test.ts @@ -11,7 +11,7 @@ import { isLimitedRoute, registerLimitedConcurrencyRoutes, } from './limited_concurrency'; -import { FleetConfigType } from '../index'; +import type { FleetConfigType } from '../index'; describe('registerLimitedConcurrencyRoutes', () => { test(`doesn't call registerOnPreAuth if maxConcurrentConnections is 0`, async () => { diff --git a/x-pack/plugins/fleet/server/routes/limited_concurrency.ts b/x-pack/plugins/fleet/server/routes/limited_concurrency.ts index 92195ae08681a..ae4cab2839c79 100644 --- a/x-pack/plugins/fleet/server/routes/limited_concurrency.ts +++ b/x-pack/plugins/fleet/server/routes/limited_concurrency.ts @@ -5,15 +5,15 @@ * 2.0. */ +import { KibanaRequest } from 'kibana/server'; import type { CoreSetup, - KibanaRequest, LifecycleResponseFactory, OnPreAuthToolkit, OnPreAuthHandler, } from 'kibana/server'; import { LIMITED_CONCURRENCY_ROUTE_TAG } from '../../common'; -import { FleetConfigType } from '../index'; +import type { FleetConfigType } from '../index'; export class MaxCounter { constructor(private readonly max: number = 1) {} diff --git a/x-pack/plugins/fleet/server/routes/output/handler.ts b/x-pack/plugins/fleet/server/routes/output/handler.ts index e9f4b8c797689..a1bbe1112d04b 100644 --- a/x-pack/plugins/fleet/server/routes/output/handler.ts +++ b/x-pack/plugins/fleet/server/routes/output/handler.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { RequestHandler } from 'src/core/server'; -import { TypeOf } from '@kbn/config-schema'; +import type { RequestHandler } from 'src/core/server'; +import type { TypeOf } from '@kbn/config-schema'; import { GetOneOutputRequestSchema, PutOutputRequestSchema } from '../../types'; -import { GetOneOutputResponse, GetOutputsResponse } from '../../../common'; +import type { GetOneOutputResponse, GetOutputsResponse } from '../../../common'; import { outputService } from '../../services/output'; import { defaultIngestErrorHandler } from '../../errors'; diff --git a/x-pack/plugins/fleet/server/routes/output/index.ts b/x-pack/plugins/fleet/server/routes/output/index.ts index 7114a7c673d6b..ce4610cf7f85b 100644 --- a/x-pack/plugins/fleet/server/routes/output/index.ts +++ b/x-pack/plugins/fleet/server/routes/output/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter } from 'src/core/server'; +import type { IRouter } from 'src/core/server'; import { PLUGIN_ID, OUTPUT_API_ROUTES } from '../../constants'; import { getOneOuputHandler, getOutputsHandler, putOuputHandler } from './handler'; import { diff --git a/x-pack/plugins/fleet/server/routes/package_policy/handlers.test.ts b/x-pack/plugins/fleet/server/routes/package_policy/handlers.test.ts index 813279f2a800f..a94313282a360 100644 --- a/x-pack/plugins/fleet/server/routes/package_policy/handlers.test.ts +++ b/x-pack/plugins/fleet/server/routes/package_policy/handlers.test.ts @@ -6,14 +6,14 @@ */ import { httpServerMock, httpServiceMock } from 'src/core/server/mocks'; -import { IRouter, KibanaRequest, RequestHandler, RouteConfig } from 'kibana/server'; +import { KibanaRequest } from 'kibana/server'; +import type { IRouter, RequestHandler, RouteConfig } from 'kibana/server'; import { registerRoutes } from './index'; import { PACKAGE_POLICY_API_ROUTES } from '../../../common/constants'; -import { appContextService } from '../../services'; +import { appContextService, packagePolicyService } from '../../services'; import { createAppContextStartContractMock, xpackMocks } from '../../mocks'; -import { PackagePolicyServiceInterface, ExternalCallback } from '../..'; +import type { PackagePolicyServiceInterface, ExternalCallback } from '../..'; import { CreatePackagePolicyRequestSchema } from '../../types/rest_spec'; -import { packagePolicyService } from '../../services'; const packagePolicyServiceMock = packagePolicyService as jest.Mocked; diff --git a/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts b/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts index 6b35f74b3febc..fb2c853f506c9 100644 --- a/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { TypeOf } from '@kbn/config-schema'; +import type { TypeOf } from '@kbn/config-schema'; import Boom from '@hapi/boom'; -import { RequestHandler, SavedObjectsErrorHelpers } from '../../../../../../src/core/server'; +import { SavedObjectsErrorHelpers } from '../../../../../../src/core/server'; +import type { RequestHandler } from '../../../../../../src/core/server'; import { appContextService, packagePolicyService } from '../../services'; import { GetPackagePoliciesRequestSchema, @@ -16,7 +17,7 @@ import { UpdatePackagePolicyRequestSchema, DeletePackagePoliciesRequestSchema, } from '../../types'; -import { CreatePackagePolicyResponse, DeletePackagePoliciesResponse } from '../../../common'; +import type { CreatePackagePolicyResponse, DeletePackagePoliciesResponse } from '../../../common'; import { defaultIngestErrorHandler } from '../../errors'; export const getPackagePoliciesHandler: RequestHandler< diff --git a/x-pack/plugins/fleet/server/routes/package_policy/index.ts b/x-pack/plugins/fleet/server/routes/package_policy/index.ts index 2df70e1a51b34..19fc261685ff7 100644 --- a/x-pack/plugins/fleet/server/routes/package_policy/index.ts +++ b/x-pack/plugins/fleet/server/routes/package_policy/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter } from 'src/core/server'; +import type { IRouter } from 'src/core/server'; import { PLUGIN_ID, PACKAGE_POLICY_API_ROUTES } from '../../constants'; import { GetPackagePoliciesRequestSchema, diff --git a/x-pack/plugins/fleet/server/routes/security.ts b/x-pack/plugins/fleet/server/routes/security.ts index 995dad545ed94..001dbf4b9b2f4 100644 --- a/x-pack/plugins/fleet/server/routes/security.ts +++ b/x-pack/plugins/fleet/server/routes/security.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter, RequestHandler } from 'src/core/server'; +import type { IRouter, RequestHandler } from 'src/core/server'; import { appContextService } from '../services'; export function enforceSuperUser( diff --git a/x-pack/plugins/fleet/server/routes/settings/index.ts b/x-pack/plugins/fleet/server/routes/settings/index.ts index 63b5b9c881e13..2f71e3967c38c 100644 --- a/x-pack/plugins/fleet/server/routes/settings/index.ts +++ b/x-pack/plugins/fleet/server/routes/settings/index.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { IRouter, RequestHandler } from 'src/core/server'; -import { TypeOf } from '@kbn/config-schema'; +import type { IRouter, RequestHandler } from 'src/core/server'; +import type { TypeOf } from '@kbn/config-schema'; import { PLUGIN_ID, SETTINGS_API_ROUTES } from '../../constants'; import { PutSettingsRequestSchema, GetSettingsRequestSchema } from '../../types'; import { defaultIngestErrorHandler } from '../../errors'; diff --git a/x-pack/plugins/fleet/server/routes/setup/handlers.test.ts b/x-pack/plugins/fleet/server/routes/setup/handlers.test.ts index 946f17ad8129d..4016e90ea19b3 100644 --- a/x-pack/plugins/fleet/server/routes/setup/handlers.test.ts +++ b/x-pack/plugins/fleet/server/routes/setup/handlers.test.ts @@ -6,7 +6,7 @@ */ import { httpServerMock } from 'src/core/server/mocks'; -import { PostIngestSetupResponse } from '../../../common'; +import type { PostIngestSetupResponse } from '../../../common'; import { RegistryError } from '../../errors'; import { createAppContextStartContractMock, xpackMocks } from '../../mocks'; import { FleetSetupHandler } from './handlers'; diff --git a/x-pack/plugins/fleet/server/routes/setup/handlers.ts b/x-pack/plugins/fleet/server/routes/setup/handlers.ts index 0c6ba6d14b1be..8d4d44276dfc1 100644 --- a/x-pack/plugins/fleet/server/routes/setup/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/setup/handlers.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { RequestHandler } from 'src/core/server'; -import { TypeOf } from '@kbn/config-schema'; +import type { RequestHandler } from 'src/core/server'; +import type { TypeOf } from '@kbn/config-schema'; import { outputService, appContextService } from '../../services'; -import { GetFleetStatusResponse, PostIngestSetupResponse } from '../../../common'; +import type { GetFleetStatusResponse, PostIngestSetupResponse } from '../../../common'; import { setupIngestManager, setupFleet } from '../../services/setup'; import { PostFleetSetupRequestSchema } from '../../types'; import { defaultIngestErrorHandler } from '../../errors'; diff --git a/x-pack/plugins/fleet/server/routes/setup/index.ts b/x-pack/plugins/fleet/server/routes/setup/index.ts index 3698b74c8c02b..7e07723b4acd8 100644 --- a/x-pack/plugins/fleet/server/routes/setup/index.ts +++ b/x-pack/plugins/fleet/server/routes/setup/index.ts @@ -5,10 +5,9 @@ * 2.0. */ -import { IRouter } from 'src/core/server'; - +import type { IRouter } from 'src/core/server'; import { PLUGIN_ID, AGENTS_SETUP_API_ROUTES, SETUP_API_ROUTE } from '../../constants'; -import { FleetConfigType } from '../../../common'; +import type { FleetConfigType } from '../../../common'; import { getFleetStatusHandler, createFleetSetupHandler, FleetSetupHandler } from './handlers'; import { PostFleetSetupRequestSchema } from '../../types'; diff --git a/x-pack/plugins/fleet/server/saved_objects/index.ts b/x-pack/plugins/fleet/server/saved_objects/index.ts index d6e3cba998907..e41881c6f8b09 100644 --- a/x-pack/plugins/fleet/server/saved_objects/index.ts +++ b/x-pack/plugins/fleet/server/saved_objects/index.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { SavedObjectsServiceSetup, SavedObjectsType } from 'kibana/server'; -import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server'; +import type { SavedObjectsServiceSetup, SavedObjectsType } from 'kibana/server'; +import type { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server'; import { migratePackagePolicyToV7110, migratePackagePolicyToV7120, diff --git a/x-pack/plugins/fleet/server/saved_objects/migrations/to_v7_10_0.ts b/x-pack/plugins/fleet/server/saved_objects/migrations/to_v7_10_0.ts index aa980e4b9428a..976f02e1f242c 100644 --- a/x-pack/plugins/fleet/server/saved_objects/migrations/to_v7_10_0.ts +++ b/x-pack/plugins/fleet/server/saved_objects/migrations/to_v7_10_0.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { SavedObjectMigrationFn, SavedObjectUnsanitizedDoc } from 'kibana/server'; -import { EncryptedSavedObjectsPluginSetup } from '../../../../encrypted_saved_objects/server'; -import { +import type { SavedObjectMigrationFn, SavedObjectUnsanitizedDoc } from 'kibana/server'; +import type { EncryptedSavedObjectsPluginSetup } from '../../../../encrypted_saved_objects/server'; +import type { Agent, AgentEvent, AgentPolicy, diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 44962ea31c56c..bda754a1800b8 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -8,18 +8,18 @@ import { uniq } from 'lodash'; import { safeLoad } from 'js-yaml'; import uuid from 'uuid/v4'; -import { +import type { ElasticsearchClient, SavedObjectsClientContract, SavedObjectsBulkUpdateResponse, } from 'src/core/server'; -import { AuthenticatedUser } from '../../../security/server'; +import type { AuthenticatedUser } from '../../../security/server'; import { DEFAULT_AGENT_POLICY, AGENT_POLICY_SAVED_OBJECT_TYPE, AGENT_SAVED_OBJECT_TYPE, } from '../constants'; -import { +import type { PackagePolicy, NewAgentPolicy, AgentPolicy, @@ -28,15 +28,13 @@ import { ListWithKuery, } from '../types'; import { - DeleteAgentPolicyResponse, - Settings, agentPolicyStatuses, storedPackagePoliciesToAgentInputs, dataTypes, - FleetServerPolicy, AGENT_POLICY_INDEX, DEFAULT_FLEET_SERVER_AGENT_POLICY, } from '../../common'; +import type { DeleteAgentPolicyResponse, Settings, FleetServerPolicy } from '../../common'; import { AgentPolicyNameExistsError, AgentPolicyDeletionError, diff --git a/x-pack/plugins/fleet/server/services/agent_policy_update.ts b/x-pack/plugins/fleet/server/services/agent_policy_update.ts index 561c8043978ae..b6acafc667c9b 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy_update.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy_update.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { ElasticsearchClient, KibanaRequest, SavedObjectsClientContract } from 'src/core/server'; +import { KibanaRequest } from 'src/core/server'; +import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; import { generateEnrollmentAPIKey, deleteEnrollmentApiKeyForAgentPolicyId } from './api_keys'; import { isAgentsSetup, unenrollForAgentPolicyId } from './agents'; import { agentPolicyService } from './agent_policy'; diff --git a/x-pack/plugins/fleet/server/services/agents/acks.test.ts b/x-pack/plugins/fleet/server/services/agents/acks.test.ts index 5aec696f5e144..1a4b89a9b2a94 100644 --- a/x-pack/plugins/fleet/server/services/agents/acks.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/acks.test.ts @@ -6,10 +6,9 @@ */ import Boom from '@hapi/boom'; -import { SavedObjectsBulkResponse } from 'kibana/server'; +import type { SavedObjectsBulkResponse } from 'kibana/server'; import { elasticsearchServiceMock, savedObjectsClientMock } from 'src/core/server/mocks'; - -import { +import type { Agent, AgentActionSOAttributes, BaseAgentActionSOAttributes, diff --git a/x-pack/plugins/fleet/server/services/agents/acks.ts b/x-pack/plugins/fleet/server/services/agents/acks.ts index c639a9b0332ac..0fecc18f7a622 100644 --- a/x-pack/plugins/fleet/server/services/agents/acks.ts +++ b/x-pack/plugins/fleet/server/services/agents/acks.ts @@ -5,16 +5,16 @@ * 2.0. */ -import { +import { KibanaRequest } from 'src/core/server'; +import type { ElasticsearchClient, - KibanaRequest, SavedObjectsBulkCreateObject, SavedObjectsBulkResponse, SavedObjectsClientContract, } from 'src/core/server'; import Boom from '@hapi/boom'; import LRU from 'lru-cache'; -import { +import type { Agent, AgentAction, AgentPolicyAction, diff --git a/x-pack/plugins/fleet/server/services/agents/actions.test.ts b/x-pack/plugins/fleet/server/services/agents/actions.test.ts index 3d391cc89a7e3..18e954d4aa9bd 100644 --- a/x-pack/plugins/fleet/server/services/agents/actions.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/actions.test.ts @@ -6,8 +6,8 @@ */ import { createAgentAction } from './actions'; -import { SavedObject } from 'kibana/server'; -import { AgentAction } from '../../../common/types/models'; +import type { SavedObject } from 'kibana/server'; +import type { AgentAction } from '../../../common/types/models'; import { savedObjectsClientMock, elasticsearchServiceMock } from 'src/core/server/mocks'; describe('test agent actions services', () => { diff --git a/x-pack/plugins/fleet/server/services/agents/actions.ts b/x-pack/plugins/fleet/server/services/agents/actions.ts index 8dfeac11dacf3..58d52f408f1fb 100644 --- a/x-pack/plugins/fleet/server/services/agents/actions.ts +++ b/x-pack/plugins/fleet/server/services/agents/actions.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { ElasticsearchClient, SavedObjectsClientContract } from 'kibana/server'; -import { +import type { ElasticsearchClient, SavedObjectsClientContract } from 'kibana/server'; +import type { Agent, AgentAction, AgentPolicyAction, diff --git a/x-pack/plugins/fleet/server/services/agents/authenticate.ts b/x-pack/plugins/fleet/server/services/agents/authenticate.ts index a03c35bdc6e73..10469fcb3a013 100644 --- a/x-pack/plugins/fleet/server/services/agents/authenticate.ts +++ b/x-pack/plugins/fleet/server/services/agents/authenticate.ts @@ -6,8 +6,9 @@ */ import Boom from '@hapi/boom'; -import { KibanaRequest, SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; -import { Agent } from '../../types'; +import { KibanaRequest } from 'src/core/server'; +import type { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; +import type { Agent } from '../../types'; import * as APIKeyService from '../api_keys'; import { getAgentByAccessAPIKeyId } from './crud'; diff --git a/x-pack/plugins/fleet/server/services/agents/checkin/index.ts b/x-pack/plugins/fleet/server/services/agents/checkin/index.ts index bcebedae2e07a..925006f9e67b3 100644 --- a/x-pack/plugins/fleet/server/services/agents/checkin/index.ts +++ b/x-pack/plugins/fleet/server/services/agents/checkin/index.ts @@ -6,19 +6,18 @@ */ import deepEqual from 'fast-deep-equal'; -import { +import type { ElasticsearchClient, SavedObjectsClientContract, SavedObjectsBulkCreateObject, } from 'src/core/server'; -import { +import type { Agent, NewAgentEvent, AgentEvent, AgentSOAttributes, AgentEventSOAttributes, } from '../../../types'; - import { AGENT_EVENT_SAVED_OBJECT_TYPE } from '../../../constants'; import { agentCheckinState } from './state'; import { getAgentActionsForCheckin } from '../actions'; diff --git a/x-pack/plugins/fleet/server/services/agents/checkin/state.ts b/x-pack/plugins/fleet/server/services/agents/checkin/state.ts index e1cec6292a355..de965646a59c3 100644 --- a/x-pack/plugins/fleet/server/services/agents/checkin/state.ts +++ b/x-pack/plugins/fleet/server/services/agents/checkin/state.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; -import { Agent } from '../../../types'; +import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; +import type { Agent } from '../../../types'; import { appContextService } from '../../app_context'; import { agentCheckinStateConnectedAgentsFactory } from './state_connected_agents'; import { agentCheckinStateNewActionsFactory } from './state_new_actions'; diff --git a/x-pack/plugins/fleet/server/services/agents/checkin/state_new_actions.test.ts b/x-pack/plugins/fleet/server/services/agents/checkin/state_new_actions.test.ts index cd6e0ef61e3f0..1433eccab038b 100644 --- a/x-pack/plugins/fleet/server/services/agents/checkin/state_new_actions.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/checkin/state_new_actions.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ElasticsearchClient } from 'kibana/server'; +import type { ElasticsearchClient } from 'kibana/server'; import { savedObjectsClientMock } from 'src/core/server/mocks'; import { take } from 'rxjs/operators'; import { @@ -13,7 +13,7 @@ import { createNewActionsSharedObservable, } from './state_new_actions'; import { getNewActionsSince } from '../actions'; -import { Agent, AgentAction, AgentPolicyAction } from '../../../types'; +import type { Agent, AgentAction, AgentPolicyAction } from '../../../types'; import { outputType } from '../../../../common/constants'; jest.mock('../../app_context', () => ({ diff --git a/x-pack/plugins/fleet/server/services/agents/checkin/state_new_actions.ts b/x-pack/plugins/fleet/server/services/agents/checkin/state_new_actions.ts index 01759c2015cdf..c66bff30a2e57 100644 --- a/x-pack/plugins/fleet/server/services/agents/checkin/state_new_actions.ts +++ b/x-pack/plugins/fleet/server/services/agents/checkin/state_new_actions.ts @@ -22,8 +22,9 @@ import { timeout, take, } from 'rxjs/operators'; -import { ElasticsearchClient, SavedObjectsClientContract, KibanaRequest } from 'src/core/server'; -import { +import { KibanaRequest } from 'src/core/server'; +import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; +import type { Agent, AgentAction, AgentPolicyAction, diff --git a/x-pack/plugins/fleet/server/services/agents/crud.ts b/x-pack/plugins/fleet/server/services/agents/crud.ts index c80fd77fc11ec..60a2ed8f67cee 100644 --- a/x-pack/plugins/fleet/server/services/agents/crud.ts +++ b/x-pack/plugins/fleet/server/services/agents/crud.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; -import { AgentSOAttributes, Agent, ListWithKuery } from '../../types'; +import type { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; +import type { AgentSOAttributes, Agent, ListWithKuery } from '../../types'; import { appContextService, agentPolicyService } from '../../services'; import * as crudServiceSO from './crud_so'; import * as crudServiceFleetServer from './crud_fleet_server'; diff --git a/x-pack/plugins/fleet/server/services/agents/crud_fleet_server.ts b/x-pack/plugins/fleet/server/services/agents/crud_fleet_server.ts index caff15efff68c..53a22e842a544 100644 --- a/x-pack/plugins/fleet/server/services/agents/crud_fleet_server.ts +++ b/x-pack/plugins/fleet/server/services/agents/crud_fleet_server.ts @@ -6,17 +6,18 @@ */ import Boom from '@hapi/boom'; -import { SearchResponse } from 'elasticsearch'; -import { ElasticsearchClient } from 'src/core/server'; - -import { FleetServerAgent, isAgentUpgradeable, SO_SEARCH_LIMIT } from '../../../common'; +import type { SearchResponse } from 'elasticsearch'; +import type { ElasticsearchClient } from 'src/core/server'; +import { isAgentUpgradeable, SO_SEARCH_LIMIT } from '../../../common'; +import type { FleetServerAgent } from '../../../common'; import { AGENT_SAVED_OBJECT_TYPE, AGENTS_INDEX } from '../../constants'; -import { ESSearchHit } from '../../../../../typings/elasticsearch'; -import { AgentSOAttributes, Agent, ListWithKuery } from '../../types'; +import type { ESSearchHit } from '../../../../../typings/elasticsearch'; +import type { AgentSOAttributes, Agent, ListWithKuery } from '../../types'; import { escapeSearchQueryPhrase, normalizeKuery } from '../saved_object'; import { searchHitToAgent, agentSOAttributesToFleetServerAgentDoc } from './helpers'; import { appContextService } from '../../services'; -import { esKuery, KueryNode } from '../../../../../../src/plugins/data/server'; +import { esKuery } from '../../../../../../src/plugins/data/server'; +import type { KueryNode } from '../../../../../../src/plugins/data/server'; const ACTIVE_AGENT_CONDITION = 'active:true'; const INACTIVE_AGENT_CONDITION = `NOT (${ACTIVE_AGENT_CONDITION})`; diff --git a/x-pack/plugins/fleet/server/services/agents/crud_so.ts b/x-pack/plugins/fleet/server/services/agents/crud_so.ts index c3ceb4b7502e2..2daeff9b7344d 100644 --- a/x-pack/plugins/fleet/server/services/agents/crud_so.ts +++ b/x-pack/plugins/fleet/server/services/agents/crud_so.ts @@ -6,15 +6,15 @@ */ import Boom from '@hapi/boom'; -import { SavedObjectsBulkUpdateObject, SavedObjectsClientContract } from 'src/core/server'; - +import type { SavedObjectsBulkUpdateObject, SavedObjectsClientContract } from 'src/core/server'; import { isAgentUpgradeable } from '../../../common'; import { AGENT_SAVED_OBJECT_TYPE } from '../../constants'; -import { AgentSOAttributes, Agent, ListWithKuery } from '../../types'; +import type { AgentSOAttributes, Agent, ListWithKuery } from '../../types'; import { escapeSearchQueryPhrase, normalizeKuery, findAllSOs } from '../saved_object'; import { savedObjectToAgent } from './saved_objects'; import { appContextService } from '../../services'; -import { esKuery, KueryNode } from '../../../../../../src/plugins/data/server'; +import { esKuery } from '../../../../../../src/plugins/data/server'; +import type { KueryNode } from '../../../../../../src/plugins/data/server'; const ACTIVE_AGENT_CONDITION = `${AGENT_SAVED_OBJECT_TYPE}.attributes.active:true`; const INACTIVE_AGENT_CONDITION = `NOT (${ACTIVE_AGENT_CONDITION})`; diff --git a/x-pack/plugins/fleet/server/services/agents/events.ts b/x-pack/plugins/fleet/server/services/agents/events.ts index 71df5ebad4947..29b42a5de8282 100644 --- a/x-pack/plugins/fleet/server/services/agents/events.ts +++ b/x-pack/plugins/fleet/server/services/agents/events.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'src/core/server'; +import type { SavedObjectsClientContract } from 'src/core/server'; import { AGENT_EVENT_SAVED_OBJECT_TYPE } from '../../constants'; -import { AgentEventSOAttributes, AgentEvent } from '../../types'; +import type { AgentEventSOAttributes, AgentEvent } from '../../types'; import { normalizeKuery } from '../saved_object'; export async function getAgentEvents( diff --git a/x-pack/plugins/fleet/server/services/agents/helpers.ts b/x-pack/plugins/fleet/server/services/agents/helpers.ts index 90d85e98ecd67..1dab3b64755fd 100644 --- a/x-pack/plugins/fleet/server/services/agents/helpers.ts +++ b/x-pack/plugins/fleet/server/services/agents/helpers.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { ESSearchHit } from '../../../../../typings/elasticsearch'; -import { Agent, AgentSOAttributes, FleetServerAgent } from '../../types'; +import type { ESSearchHit } from '../../../../../typings/elasticsearch'; +import type { Agent, AgentSOAttributes, FleetServerAgent } from '../../types'; export function searchHitToAgent(hit: ESSearchHit): Agent { return { diff --git a/x-pack/plugins/fleet/server/services/agents/saved_objects.ts b/x-pack/plugins/fleet/server/services/agents/saved_objects.ts index 7b439c2729987..45d5a0de040ea 100644 --- a/x-pack/plugins/fleet/server/services/agents/saved_objects.ts +++ b/x-pack/plugins/fleet/server/services/agents/saved_objects.ts @@ -6,8 +6,8 @@ */ import Boom from '@hapi/boom'; -import { SavedObject } from 'src/core/server'; -import { +import type { SavedObject } from 'src/core/server'; +import type { Agent, AgentSOAttributes, AgentAction, diff --git a/x-pack/plugins/fleet/server/services/agents/setup.ts b/x-pack/plugins/fleet/server/services/agents/setup.ts index bbd14209b5b37..b55eb8efb1370 100644 --- a/x-pack/plugins/fleet/server/services/agents/setup.ts +++ b/x-pack/plugins/fleet/server/services/agents/setup.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'src/core/server'; +import type { SavedObjectsClientContract } from 'src/core/server'; import { SO_SEARCH_LIMIT } from '../../constants'; import { agentPolicyService } from '../agent_policy'; import { outputService } from '../output'; diff --git a/x-pack/plugins/fleet/server/services/agents/status.test.ts b/x-pack/plugins/fleet/server/services/agents/status.test.ts index a6b8bf41b6cb4..c6a021195f8f8 100644 --- a/x-pack/plugins/fleet/server/services/agents/status.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/status.test.ts @@ -8,8 +8,8 @@ import { elasticsearchServiceMock, savedObjectsClientMock } from 'src/core/server/mocks'; import { getAgentStatusById } from './status'; import { AGENT_TYPE_PERMANENT } from '../../../common/constants'; -import { AgentSOAttributes } from '../../../common/types/models'; -import { SavedObject } from 'kibana/server'; +import type { AgentSOAttributes } from '../../../common/types/models'; +import type { SavedObject } from 'kibana/server'; describe('Agent status service', () => { it('should return inactive when agent is not active', async () => { diff --git a/x-pack/plugins/fleet/server/services/agents/status.ts b/x-pack/plugins/fleet/server/services/agents/status.ts index 42d3aff2b0d70..29171adf92bb9 100644 --- a/x-pack/plugins/fleet/server/services/agents/status.ts +++ b/x-pack/plugins/fleet/server/services/agents/status.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; +import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; import pMap from 'p-map'; import { getAgent, listAgents } from './crud'; import { AGENT_EVENT_SAVED_OBJECT_TYPE, AGENT_SAVED_OBJECT_TYPE } from '../../constants'; -import { AgentStatus } from '../../types'; - +import type { AgentStatus } from '../../types'; import { AgentStatusKueryHelper } from '../../../common/services'; -import { esKuery, KueryNode } from '../../../../../../src/plugins/data/server'; +import { esKuery } from '../../../../../../src/plugins/data/server'; +import type { KueryNode } from '../../../../../../src/plugins/data/server'; import { normalizeKuery } from '../saved_object'; import { appContextService } from '../app_context'; import { removeSOAttributes } from './crud_fleet_server'; diff --git a/x-pack/plugins/fleet/server/services/agents/unenroll.ts b/x-pack/plugins/fleet/server/services/agents/unenroll.ts index 72d551a122980..97dc7ea87706e 100644 --- a/x-pack/plugins/fleet/server/services/agents/unenroll.ts +++ b/x-pack/plugins/fleet/server/services/agents/unenroll.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; +import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; import * as APIKeyService from '../api_keys'; import { createAgentAction, bulkCreateAgentActions } from './actions'; import { diff --git a/x-pack/plugins/fleet/server/services/agents/update.ts b/x-pack/plugins/fleet/server/services/agents/update.ts index 21087be392bcd..81214b6fd0eb5 100644 --- a/x-pack/plugins/fleet/server/services/agents/update.ts +++ b/x-pack/plugins/fleet/server/services/agents/update.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; +import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; import { listAgents } from './crud'; import { AGENT_SAVED_OBJECT_TYPE } from '../../constants'; import { unenrollAgent } from './unenroll'; diff --git a/x-pack/plugins/fleet/server/services/agents/upgrade.ts b/x-pack/plugins/fleet/server/services/agents/upgrade.ts index d73cc38e32c39..9986edd3d805f 100644 --- a/x-pack/plugins/fleet/server/services/agents/upgrade.ts +++ b/x-pack/plugins/fleet/server/services/agents/upgrade.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; -import { AgentAction, AgentActionSOAttributes } from '../../types'; +import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; +import type { AgentAction, AgentActionSOAttributes } from '../../types'; import { AGENT_ACTION_SAVED_OBJECT_TYPE } from '../../constants'; import { agentPolicyService } from '../../services'; import { IngestManagerError } from '../../errors'; diff --git a/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key.ts b/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key.ts index 85812fee3885c..5d86393f0905e 100644 --- a/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key.ts +++ b/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; -import { EnrollmentAPIKey } from '../../types'; +import type { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; +import type { EnrollmentAPIKey } from '../../types'; import { appContextService } from '../app_context'; import * as enrollmentApiKeyServiceSO from './enrollment_api_key_so'; import * as enrollmentApiKeyServiceFleetServer from './enrollment_api_key_fleet_server'; diff --git a/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key_fleet_server.ts b/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key_fleet_server.ts index f5d0015297daa..5cde87da95cdf 100644 --- a/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key_fleet_server.ts +++ b/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key_fleet_server.ts @@ -7,11 +7,11 @@ import uuid from 'uuid'; import Boom from '@hapi/boom'; -import { GetResponse } from 'elasticsearch'; +import type { GetResponse } from 'elasticsearch'; import { ResponseError } from '@elastic/elasticsearch/lib/errors'; -import { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; -import { ESSearchResponse as SearchResponse } from '../../../../../typings/elasticsearch'; -import { EnrollmentAPIKey, FleetServerEnrollmentAPIKey } from '../../types'; +import type { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; +import type { ESSearchResponse as SearchResponse } from '../../../../../typings/elasticsearch'; +import type { EnrollmentAPIKey, FleetServerEnrollmentAPIKey } from '../../types'; import { ENROLLMENT_API_KEYS_INDEX } from '../../constants'; import { createAPIKey, invalidateAPIKeys } from './security'; import { agentPolicyService } from '../agent_policy'; diff --git a/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key_so.ts b/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key_so.ts index 014bc58e747ea..4001cabe76aa3 100644 --- a/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key_so.ts +++ b/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key_so.ts @@ -7,8 +7,8 @@ import uuid from 'uuid'; import Boom from '@hapi/boom'; -import { SavedObjectsClientContract, SavedObject } from 'src/core/server'; -import { EnrollmentAPIKey, EnrollmentAPIKeySOAttributes } from '../../types'; +import type { SavedObjectsClientContract, SavedObject } from 'src/core/server'; +import type { EnrollmentAPIKey, EnrollmentAPIKeySOAttributes } from '../../types'; import { ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE } from '../../constants'; import { createAPIKey, invalidateAPIKeys } from './security'; import { agentPolicyService } from '../agent_policy'; diff --git a/x-pack/plugins/fleet/server/services/api_keys/index.ts b/x-pack/plugins/fleet/server/services/api_keys/index.ts index 911cb700dd56b..724583e42efe0 100644 --- a/x-pack/plugins/fleet/server/services/api_keys/index.ts +++ b/x-pack/plugins/fleet/server/services/api_keys/index.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { SavedObjectsClientContract, KibanaRequest } from 'src/core/server'; +import { KibanaRequest } from 'src/core/server'; +import type { SavedObjectsClientContract } from 'src/core/server'; import { createAPIKey } from './security'; export { invalidateAPIKeys } from './security'; diff --git a/x-pack/plugins/fleet/server/services/api_keys/security.ts b/x-pack/plugins/fleet/server/services/api_keys/security.ts index efd46c1a547dd..356f9012791eb 100644 --- a/x-pack/plugins/fleet/server/services/api_keys/security.ts +++ b/x-pack/plugins/fleet/server/services/api_keys/security.ts @@ -6,9 +6,10 @@ */ import type { Request } from '@hapi/hapi'; -import { KibanaRequest, SavedObjectsClientContract } from '../../../../../../src/core/server'; +import { KibanaRequest } from '../../../../../../src/core/server'; +import type { SavedObjectsClientContract } from '../../../../../../src/core/server'; import { FleetAdminUserInvalidError, isESClientError } from '../../errors'; -import { CallESAsCurrentUser } from '../../types'; +import type { CallESAsCurrentUser } from '../../types'; import { appContextService } from '../app_context'; import { outputService } from '../output'; diff --git a/x-pack/plugins/fleet/server/services/app_context.ts b/x-pack/plugins/fleet/server/services/app_context.ts index 1ada940dd793c..f63d3b2d7ccab 100644 --- a/x-pack/plugins/fleet/server/services/app_context.ts +++ b/x-pack/plugins/fleet/server/services/app_context.ts @@ -8,22 +8,21 @@ import { BehaviorSubject, Observable } from 'rxjs'; import { first } from 'rxjs/operators'; import { kibanaPackageJson } from '@kbn/utils'; - -import { +import { KibanaRequest } from 'src/core/server'; +import type { ElasticsearchClient, SavedObjectsServiceStart, HttpServiceSetup, Logger, - KibanaRequest, } from 'src/core/server'; -import { +import type { EncryptedSavedObjectsClient, EncryptedSavedObjectsPluginSetup, } from '../../../encrypted_saved_objects/server'; -import { SecurityPluginStart } from '../../../security/server'; -import { FleetConfigType } from '../../common'; -import { ExternalCallback, ExternalCallbacksStorage, FleetAppContext } from '../plugin'; -import { CloudSetup } from '../../../cloud/server'; +import type { SecurityPluginStart } from '../../../security/server'; +import type { FleetConfigType } from '../../common'; +import type { ExternalCallback, ExternalCallbacksStorage, FleetAppContext } from '../plugin'; +import type { CloudSetup } from '../../../cloud/server'; class AppContextService { private encryptedSavedObjects: EncryptedSavedObjectsClient | undefined; diff --git a/x-pack/plugins/fleet/server/services/config.ts b/x-pack/plugins/fleet/server/services/config.ts index 3e2c7be1e3fde..d14e31e5b510f 100644 --- a/x-pack/plugins/fleet/server/services/config.ts +++ b/x-pack/plugins/fleet/server/services/config.ts @@ -6,7 +6,7 @@ */ import { Observable, Subscription } from 'rxjs'; -import { FleetConfigType } from '../'; +import type { FleetConfigType } from '../'; /** * Kibana config observable service, *NOT* agent policy diff --git a/x-pack/plugins/fleet/server/services/epm/agent/agent.ts b/x-pack/plugins/fleet/server/services/epm/agent/agent.ts index a71776af245f7..38631ad784ea9 100644 --- a/x-pack/plugins/fleet/server/services/epm/agent/agent.ts +++ b/x-pack/plugins/fleet/server/services/epm/agent/agent.ts @@ -7,7 +7,7 @@ import Handlebars from 'handlebars'; import { safeLoad, safeDump } from 'js-yaml'; -import { PackagePolicyConfigRecord } from '../../../../common'; +import type { PackagePolicyConfigRecord } from '../../../../common'; const handlebars = Handlebars.create(); diff --git a/x-pack/plugins/fleet/server/services/epm/archive/cache.ts b/x-pack/plugins/fleet/server/services/epm/archive/cache.ts index 97e0303e9f50f..8d4234e3cf538 100644 --- a/x-pack/plugins/fleet/server/services/epm/archive/cache.ts +++ b/x-pack/plugins/fleet/server/services/epm/archive/cache.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { ArchiveEntry } from './index'; -import { ArchivePackage, RegistryPackage } from '../../../../common'; +import type { ArchiveEntry } from './index'; +import type { ArchivePackage, RegistryPackage } from '../../../../common'; const archiveEntryCache: Map = new Map(); export const getArchiveEntry = (key: string) => archiveEntryCache.get(key); diff --git a/x-pack/plugins/fleet/server/services/epm/archive/extract.ts b/x-pack/plugins/fleet/server/services/epm/archive/extract.ts index 817eff7d42788..8d576310813c0 100644 --- a/x-pack/plugins/fleet/server/services/epm/archive/extract.ts +++ b/x-pack/plugins/fleet/server/services/epm/archive/extract.ts @@ -8,7 +8,7 @@ import tar from 'tar'; import yauzl from 'yauzl'; import { bufferToStream, streamToBuffer } from '../streams'; -import { ArchiveEntry } from './index'; +import type { ArchiveEntry } from './index'; export async function untarBuffer( buffer: Buffer, diff --git a/x-pack/plugins/fleet/server/services/epm/archive/index.ts b/x-pack/plugins/fleet/server/services/epm/archive/index.ts index 7ee217979cdae..44046ac749f6c 100644 --- a/x-pack/plugins/fleet/server/services/epm/archive/index.ts +++ b/x-pack/plugins/fleet/server/services/epm/archive/index.ts @@ -5,10 +5,9 @@ * 2.0. */ -import { AssetParts, InstallSource } from '../../../../common/types'; +import type { AssetParts, InstallSource } from '../../../../common/types'; import { PackageInvalidArchiveError, PackageUnsupportedMediaTypeError } from '../../../errors'; import { - SharedKey, getArchiveEntry, setArchiveEntry, deleteArchiveEntry, @@ -17,6 +16,7 @@ import { deleteArchiveFilelist, deletePackageInfo, } from './cache'; +import type { SharedKey } from './cache'; import { getBufferExtractor } from './extract'; export * from './cache'; diff --git a/x-pack/plugins/fleet/server/services/epm/archive/storage.ts b/x-pack/plugins/fleet/server/services/epm/archive/storage.ts index 20e1e8825fbd8..671d428918caf 100644 --- a/x-pack/plugins/fleet/server/services/epm/archive/storage.ts +++ b/x-pack/plugins/fleet/server/services/epm/archive/storage.ts @@ -11,15 +11,16 @@ import { safeLoad } from 'js-yaml'; import { isBinaryFile } from 'isbinaryfile'; import mime from 'mime-types'; import uuidv5 from 'uuid/v5'; -import { SavedObjectsClientContract, SavedObjectsBulkCreateObject } from 'src/core/server'; -import { - ASSETS_SAVED_OBJECT_TYPE, +import type { SavedObjectsClientContract, SavedObjectsBulkCreateObject } from 'src/core/server'; +import { ASSETS_SAVED_OBJECT_TYPE } from '../../../../common'; +import type { InstallablePackage, InstallSource, PackageAssetReference, RegistryDataStream, } from '../../../../common'; -import { ArchiveEntry, getArchiveEntry, setArchiveEntry, setArchiveFilelist } from './index'; +import { getArchiveEntry, setArchiveEntry, setArchiveFilelist } from './index'; +import type { ArchiveEntry } from './index'; import { parseAndVerifyPolicyTemplates, parseAndVerifyStreams } from './validation'; import { pkgToPkgKey } from '../registry'; diff --git a/x-pack/plugins/fleet/server/services/epm/archive/validation.ts b/x-pack/plugins/fleet/server/services/epm/archive/validation.ts index 05daa98579079..03f30cab45734 100644 --- a/x-pack/plugins/fleet/server/services/epm/archive/validation.ts +++ b/x-pack/plugins/fleet/server/services/epm/archive/validation.ts @@ -7,7 +7,7 @@ import yaml from 'js-yaml'; import { pick, uniq } from 'lodash'; -import { +import type { ArchivePackage, RegistryPolicyTemplate, RegistryDataStream, diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/install.ts index a18c2710ce776..e18cf2eb52bcd 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/install.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'kibana/server'; -import { - ElasticsearchAssetType, +import type { SavedObjectsClientContract } from 'kibana/server'; +import { ElasticsearchAssetType } from '../../../../../common/types/models'; +import type { EsAssetReference, InstallablePackage, RegistryDataStream, } from '../../../../../common/types/models'; -import { CallESAsCurrentUser } from '../../../../types'; +import type { CallESAsCurrentUser } from '../../../../types'; import { getInstallation } from '../../packages'; import { deleteIlmRefs, deleteIlms } from './remove'; import { saveInstalledEsRefs } from '../../packages/install'; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/remove.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/remove.ts index 6f0cd6ecc935f..7da980e61f0ec 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/remove.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'kibana/server'; -import { CallESAsCurrentUser, ElasticsearchAssetType, EsAssetReference } from '../../../../types'; +import type { SavedObjectsClientContract } from 'kibana/server'; +import { ElasticsearchAssetType } from '../../../../types'; +import type { CallESAsCurrentUser, EsAssetReference } from '../../../../types'; import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../../../common/constants'; export const deleteIlms = async (callCluster: CallESAsCurrentUser, ilmPolicyIds: string[]) => { diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts index 644baa3a77e7d..b6123d190c0eb 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { CallESAsCurrentUser, ElasticsearchAssetType } from '../../../../types'; +import { ElasticsearchAssetType } from '../../../../types'; +import type { CallESAsCurrentUser } from '../../../../types'; import { getAsset, getPathParts } from '../../archive'; export async function installILMPolicy(paths: string[], callCluster: CallESAsCurrentUser) { diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/index.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/index.test.ts index 178d0c53703f3..aa64cd7a6ed02 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/index.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/index.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RegistryDataStream } from '../../../types'; +import type { RegistryDataStream } from '../../../types'; import { getRegistryDataStreamAssetBaseName } from './index'; test('getBaseName', () => { diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/index.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/index.ts index 95873ef0c9b29..81e05ef7d6314 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/index.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RegistryDataStream } from '../../../types'; +import type { RegistryDataStream } from '../../../types'; /** * Creates the base name for Elasticsearch assets in the form of diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/ingest_pipelines.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/ingest_pipelines.test.ts index 001add36ea95d..0a96186339bc0 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/ingest_pipelines.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/ingest_pipelines.test.ts @@ -8,7 +8,7 @@ import { readFileSync } from 'fs'; import path from 'path'; import { rewriteIngestPipeline, getPipelineNameForInstallation } from './install'; -import { RegistryDataStream } from '../../../../types'; +import type { RegistryDataStream } from '../../../../types'; test('a json-format pipeline with pipeline references is correctly rewritten', () => { const inputStandard = readFileSync( diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/install.ts index 983e10e15bfff..ff3262cb65418 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/install.ts @@ -5,15 +5,16 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'src/core/server'; -import { +import type { SavedObjectsClientContract } from 'src/core/server'; +import { ElasticsearchAssetType } from '../../../../types'; +import type { EsAssetReference, RegistryDataStream, - ElasticsearchAssetType, InstallablePackage, + CallESAsCurrentUser, } from '../../../../types'; -import { ArchiveEntry, getAsset, getPathParts } from '../../archive'; -import { CallESAsCurrentUser } from '../../../../types'; +import { getAsset, getPathParts } from '../../archive'; +import type { ArchiveEntry } from '../../archive'; import { saveInstalledEsRefs } from '../../packages/install'; import { getInstallationObject } from '../../packages'; import { deletePipelineRefs } from './remove'; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/remove.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/remove.ts index 4acc4767de525..d78c9d989bd4d 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/remove.ts @@ -5,12 +5,14 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'src/core/server'; +import type { SavedObjectsClientContract } from 'src/core/server'; import { appContextService } from '../../../'; -import { CallESAsCurrentUser, ElasticsearchAssetType } from '../../../../types'; +import { ElasticsearchAssetType } from '../../../../types'; +import type { CallESAsCurrentUser } from '../../../../types'; import { IngestManagerError } from '../../../../errors'; import { getInstallation } from '../../packages/get'; -import { PACKAGES_SAVED_OBJECT_TYPE, EsAssetReference } from '../../../../../common'; +import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../../../common'; +import type { EsAssetReference } from '../../../../../common'; export const deletePreviousPipelines = async ( callCluster: CallESAsCurrentUser, diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.test.ts index cdcd3972fd189..42e724794b791 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.test.ts @@ -5,9 +5,8 @@ * 2.0. */ -import { RegistryDataStream } from '../../../../types'; -import { Field } from '../../fields/field'; - +import type { RegistryDataStream } from '../../../../types'; +import type { Field } from '../../fields/field'; import { elasticsearchServiceMock } from 'src/core/server/mocks'; import { installTemplate } from './install'; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts index 70afa78e723bc..353331528ca3c 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts @@ -6,16 +6,17 @@ */ import Boom from '@hapi/boom'; -import { SavedObjectsClientContract } from 'src/core/server'; -import { +import type { SavedObjectsClientContract } from 'src/core/server'; +import { ElasticsearchAssetType } from '../../../../types'; +import type { RegistryDataStream, - ElasticsearchAssetType, TemplateRef, RegistryElasticsearch, InstallablePackage, + CallESAsCurrentUser, } from '../../../../types'; -import { CallESAsCurrentUser } from '../../../../types'; -import { Field, loadFieldsFromYaml, processFields } from '../../fields/field'; +import { loadFieldsFromYaml, processFields } from '../../fields/field'; +import type { Field } from '../../fields/field'; import { getPipelineNameForInstallation } from '../ingest_pipeline/install'; import { generateMappings, diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts index a176805307845..95e9e8e6d5c71 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts @@ -8,8 +8,9 @@ import { readFileSync } from 'fs'; import { safeLoad } from 'js-yaml'; import path from 'path'; -import { RegistryDataStream } from '../../../../types'; -import { Field, processFields } from '../../fields/field'; +import type { RegistryDataStream } from '../../../../types'; +import { processFields } from '../../fields/field'; +import type { Field } from '../../fields/field'; import { generateMappings, getTemplate, diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts index b86c989f8c24c..a13ad007663d8 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { Field, Fields } from '../../fields/field'; -import { +import type { Field, Fields } from '../../fields/field'; +import type { RegistryDataStream, CallESAsCurrentUser, TemplateRef, diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts index 948a9c56746f3..e68c5070affd3 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts @@ -5,16 +5,12 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'kibana/server'; - +import type { SavedObjectsClientContract } from 'kibana/server'; import { saveInstalledEsRefs } from '../../packages/install'; import { getPathParts } from '../../archive'; -import { - ElasticsearchAssetType, - EsAssetReference, - InstallablePackage, -} from '../../../../../common/types/models'; -import { CallESAsCurrentUser } from '../../../../types'; +import { ElasticsearchAssetType } from '../../../../../common/types/models'; +import type { EsAssetReference, InstallablePackage } from '../../../../../common/types/models'; +import type { CallESAsCurrentUser } from '../../../../types'; import { getInstallation } from '../../packages'; import { deleteTransforms, deleteTransformRefs } from './remove'; import { getAsset } from './common'; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.test.ts index 658a130d70c61..6df9f34489aeb 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.test.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'kibana/server'; +import type { SavedObjectsClientContract } from 'kibana/server'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { savedObjectsClientMock } from '../../../../../../../../src/core/server/saved_objects/service/saved_objects_client.mock'; import { deleteTransformRefs } from './remove'; -import { EsAssetReference } from '../../../../../common/types/models'; +import type { EsAssetReference } from '../../../../../common/types/models'; describe('test transform install', () => { let savedObjectsClient: jest.Mocked; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.ts index 0e947e0f0b90b..510071f119910 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'kibana/server'; -import { CallESAsCurrentUser, ElasticsearchAssetType, EsAssetReference } from '../../../../types'; +import type { SavedObjectsClientContract } from 'kibana/server'; +import { ElasticsearchAssetType } from '../../../../types'; +import type { CallESAsCurrentUser, EsAssetReference } from '../../../../types'; import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../../../common/constants'; import { appContextService } from '../../../app_context'; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/transform.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/transform.test.ts index bd944391b5f23..602908c5908e5 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/transform.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/transform.test.ts @@ -19,8 +19,13 @@ jest.mock('./common', () => { import { errors as LegacyESErrors } from 'elasticsearch'; import { installTransform } from './install'; -import { ILegacyScopedClusterClient, SavedObject, SavedObjectsClientContract } from 'kibana/server'; -import { ElasticsearchAssetType, Installation, RegistryPackage } from '../../../../types'; +import type { + ILegacyScopedClusterClient, + SavedObject, + SavedObjectsClientContract, +} from 'kibana/server'; +import { ElasticsearchAssetType } from '../../../../types'; +import type { Installation, RegistryPackage } from '../../../../types'; import { getInstallation, getInstallationObject } from '../../packages'; import { getAsset } from './common'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths diff --git a/x-pack/plugins/fleet/server/services/epm/fields/field.test.ts b/x-pack/plugins/fleet/server/services/epm/fields/field.test.ts index b10c417210656..21c0fc52f6b3f 100644 --- a/x-pack/plugins/fleet/server/services/epm/fields/field.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/fields/field.test.ts @@ -9,7 +9,8 @@ import { readFileSync } from 'fs'; import glob from 'glob'; import { safeLoad } from 'js-yaml'; import path from 'path'; -import { Field, Fields, getField, processFields } from './field'; +import { getField, processFields } from './field'; +import type { Field, Fields } from './field'; // Add our own serialiser to just do JSON.stringify expect.addSnapshotSerializer({ diff --git a/x-pack/plugins/fleet/server/services/epm/fields/field.ts b/x-pack/plugins/fleet/server/services/epm/fields/field.ts index cc925bbb14ba0..7144a4ca4e7f0 100644 --- a/x-pack/plugins/fleet/server/services/epm/fields/field.ts +++ b/x-pack/plugins/fleet/server/services/epm/fields/field.ts @@ -6,7 +6,7 @@ */ import { safeLoad } from 'js-yaml'; -import { InstallablePackage } from '../../../types'; +import type { InstallablePackage } from '../../../types'; import { getAssetsData } from '../packages/assets'; // This should become a copy of https://github.com/elastic/beats/blob/d9a4c9c240a9820fab15002592e5bb6db318543b/libbeat/mapping/field.go#L39 diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts index 64d65da2c3e14..a004bf0f21f62 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts @@ -5,20 +5,15 @@ * 2.0. */ -import { +import type { SavedObject, SavedObjectsBulkCreateObject, SavedObjectsClientContract, } from 'src/core/server'; import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../../../common'; import { getAsset, getPathParts } from '../../archive'; -import { - AssetType, - KibanaAssetType, - AssetReference, - AssetParts, - KibanaSavedObjectType, -} from '../../../../types'; +import { KibanaAssetType, KibanaSavedObjectType } from '../../../../types'; +import type { AssetType, AssetReference, AssetParts } from '../../../../types'; import { savedObjectTypes } from '../../packages'; import { indexPatternTypes } from '../index_pattern/install'; diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.test.ts b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.test.ts index afac05f6ecaec..e6d36235f0384 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.test.ts @@ -14,12 +14,12 @@ import { dedupeFields, transformField, findFieldByPath, - IndexPatternField, createFieldFormatMap, createIndexPatternFields, createIndexPattern, } from './install'; -import { Fields, Field } from '../../fields/field'; +import type { IndexPatternField } from './install'; +import type { Fields, Field } from '../../fields/field'; import { dupeFields } from './tests/test_data'; // Add our own serialiser to just do JSON.stringify diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts index 8b8ff8b4c9d95..f45eeab8bc2ba 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts @@ -5,12 +5,18 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'src/core/server'; +import type { SavedObjectsClientContract } from 'src/core/server'; import { INDEX_PATTERN_SAVED_OBJECT_TYPE } from '../../../../constants'; -import { loadFieldsFromYaml, Fields, Field } from '../../fields/field'; +import { loadFieldsFromYaml } from '../../fields/field'; +import type { Fields, Field } from '../../fields/field'; import { dataTypes, installationStatuses } from '../../../../../common/constants'; -import { ArchivePackage, Installation, InstallSource, ValueOf } from '../../../../../common/types'; -import { RegistryPackage, DataType } from '../../../../types'; +import type { + ArchivePackage, + Installation, + InstallSource, + ValueOf, +} from '../../../../../common/types'; +import type { RegistryPackage, DataType } from '../../../../types'; import { getInstallation, getPackageFromSource, getPackageSavedObjects } from '../../packages/get'; interface FieldFormatMap { diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/tests/test_data.ts b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/tests/test_data.ts index 1b17c6d812b4c..49a32de703776 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/tests/test_data.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/tests/test_data.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IndexPatternField } from '../install'; +import type { IndexPatternField } from '../install'; export const dupeFields: IndexPatternField[] = [ { diff --git a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.test.ts index a55b763d7b2bb..cf928d5b80d63 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.test.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { SavedObjectsClientContract, LegacyScopedClusterClient } from 'src/core/server'; +import { LegacyScopedClusterClient } from 'src/core/server'; +import type { SavedObjectsClientContract } from 'src/core/server'; import { savedObjectsClientMock, elasticsearchServiceMock } from 'src/core/server/mocks'; import { appContextService } from '../../app_context'; import { createAppContextStartContractMock } from '../../../mocks'; diff --git a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts index 2a6a4c93cb8e0..206bef75df14b 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts @@ -5,20 +5,15 @@ * 2.0. */ -import { SavedObject, SavedObjectsClientContract } from 'src/core/server'; -import { - InstallablePackage, - InstallSource, - PackageAssetReference, - MAX_TIME_COMPLETE_INSTALL, - ASSETS_SAVED_OBJECT_TYPE, -} from '../../../../common'; +import type { SavedObject, SavedObjectsClientContract } from 'src/core/server'; +import { MAX_TIME_COMPLETE_INSTALL, ASSETS_SAVED_OBJECT_TYPE } from '../../../../common'; +import type { InstallablePackage, InstallSource, PackageAssetReference } from '../../../../common'; import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../constants'; -import { +import { ElasticsearchAssetType } from '../../../types'; +import type { AssetReference, Installation, CallESAsCurrentUser, - ElasticsearchAssetType, InstallType, } from '../../../types'; import { installIndexPatterns } from '../kibana/index_pattern/install'; diff --git a/x-pack/plugins/fleet/server/services/epm/packages/assets.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/assets.test.ts index aa35ddd2c294b..6e5c257badef7 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/assets.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/assets.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { InstallablePackage } from '../../../types'; +import type { InstallablePackage } from '../../../types'; import { getAssets } from './assets'; import { getArchiveFilelist } from '../archive/cache'; diff --git a/x-pack/plugins/fleet/server/services/epm/packages/assets.ts b/x-pack/plugins/fleet/server/services/epm/packages/assets.ts index a2a2bce91d8e5..c28c982f4ea4c 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/assets.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/assets.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { InstallablePackage } from '../../../types'; -import { ArchiveEntry, getArchiveFilelist, getAsset } from '../archive'; +import type { InstallablePackage } from '../../../types'; +import { getArchiveFilelist, getAsset } from '../archive'; +import type { ArchiveEntry } from '../archive'; // paths from RegistryPackage are routes to the assets on EPR // e.g. `/package/nginx/1.2.0/data_stream/access/fields/fields.yml` diff --git a/x-pack/plugins/fleet/server/services/epm/packages/bulk_install_packages.ts b/x-pack/plugins/fleet/server/services/epm/packages/bulk_install_packages.ts index ac41f550c1c72..64fd132145ffc 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/bulk_install_packages.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/bulk_install_packages.ts @@ -5,11 +5,12 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'src/core/server'; -import { CallESAsCurrentUser } from '../../../types'; +import type { SavedObjectsClientContract } from 'src/core/server'; +import type { CallESAsCurrentUser } from '../../../types'; import * as Registry from '../registry'; import { getInstallationObject } from './index'; -import { BulkInstallResponse, IBulkInstallPackageError, upgradePackage } from './install'; +import { upgradePackage } from './install'; +import type { BulkInstallResponse, IBulkInstallPackageError } from './install'; interface BulkInstallPackagesParams { savedObjectsClient: SavedObjectsClientContract; diff --git a/x-pack/plugins/fleet/server/services/epm/packages/ensure_installed_default_packages.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/ensure_installed_default_packages.test.ts index aeb08bad06184..6c2a98450c1a7 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/ensure_installed_default_packages.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/ensure_installed_default_packages.test.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { ElasticsearchAssetType, Installation, KibanaSavedObjectType } from '../../../types'; -import { SavedObject, SavedObjectsClientContract } from 'src/core/server'; +import { ElasticsearchAssetType, KibanaSavedObjectType } from '../../../types'; +import type { Installation } from '../../../types'; +import type { SavedObject, SavedObjectsClientContract } from 'src/core/server'; jest.mock('./install'); jest.mock('./bulk_install_packages'); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/get.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/get.test.ts index afd150c3335af..354bcf88685cb 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/get.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/get.test.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { SavedObjectsClientContract, SavedObjectsFindResult } from 'kibana/server'; +import type { SavedObjectsClientContract, SavedObjectsFindResult } from 'kibana/server'; import { savedObjectsClientMock } from '../../../../../../../src/core/server/mocks'; -import { PACKAGE_POLICY_SAVED_OBJECT_TYPE, PackagePolicySOAttributes } from '../../../../common'; +import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../../common'; +import type { PackagePolicySOAttributes } from '../../../../common'; import { getPackageUsageStats } from './get'; describe('When using EPM `get` services', () => { diff --git a/x-pack/plugins/fleet/server/services/epm/packages/get.ts b/x-pack/plugins/fleet/server/services/epm/packages/get.ts index c07b88a45e6dc..a32ac2ad4d88f 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/get.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/get.ts @@ -5,17 +5,21 @@ * 2.0. */ -import { SavedObjectsClientContract, SavedObjectsFindOptions } from 'src/core/server'; +import type { SavedObjectsClientContract, SavedObjectsFindOptions } from 'src/core/server'; import { isPackageLimited, installationStatuses, - PackageUsageStats, - PackagePolicySOAttributes, PACKAGE_POLICY_SAVED_OBJECT_TYPE, } from '../../../../common'; +import type { PackageUsageStats, PackagePolicySOAttributes } from '../../../../common'; import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../constants'; -import { ArchivePackage, RegistryPackage, EpmPackageAdditions } from '../../../../common/types'; -import { Installation, PackageInfo, KibanaAssetType } from '../../../types'; +import type { + ArchivePackage, + RegistryPackage, + EpmPackageAdditions, +} from '../../../../common/types'; +import { KibanaAssetType } from '../../../types'; +import type { Installation, PackageInfo } from '../../../types'; import { IngestManagerError } from '../../../errors'; import * as Registry from '../registry'; import { createInstallableFrom, isRequiredPackage } from './index'; diff --git a/x-pack/plugins/fleet/server/services/epm/packages/get_install_type.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/get_install_type.test.ts index f7bc2ce1b07b4..ae29a1c7956cf 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/get_install_type.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/get_install_type.test.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { SavedObject } from 'src/core/server'; -import { ElasticsearchAssetType, Installation, KibanaSavedObjectType } from '../../../types'; import { getInstallType } from './install'; +import type { SavedObject } from 'src/core/server'; +import { ElasticsearchAssetType, KibanaSavedObjectType } from '../../../types'; +import type { Installation } from '../../../types'; const mockInstallation: SavedObject = { id: 'test-pkg', diff --git a/x-pack/plugins/fleet/server/services/epm/packages/index.ts b/x-pack/plugins/fleet/server/services/epm/packages/index.ts index b03d260e8e080..2dc845f94991e 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/index.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/index.ts @@ -5,14 +5,11 @@ * 2.0. */ -import { SavedObject } from 'src/core/server'; -import { - RequiredPackage, - requiredPackages, - ValueOf, - installationStatuses, -} from '../../../../common'; -import { AssetType, Installable, Installation, KibanaAssetType } from '../../../types'; +import type { SavedObject } from 'src/core/server'; +import { requiredPackages, installationStatuses } from '../../../../common'; +import type { RequiredPackage, ValueOf } from '../../../../common'; +import { KibanaAssetType } from '../../../types'; +import type { AssetType, Installable, Installation } from '../../../types'; export { bulkInstallPackages, isBulkInstallError } from './bulk_install_packages'; export { diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install.ts b/x-pack/plugins/fleet/server/services/epm/packages/install.ts index ac3c0f3952127..96b4b63312edd 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install.ts @@ -8,35 +8,32 @@ import semverGt from 'semver/functions/gt'; import semverLt from 'semver/functions/lt'; import Boom from '@hapi/boom'; -import { UnwrapPromise } from '@kbn/utility-types'; -import { SavedObject, SavedObjectsClientContract } from 'src/core/server'; +import type { UnwrapPromise } from '@kbn/utility-types'; +import type { SavedObject, SavedObjectsClientContract } from 'src/core/server'; import { generateESIndexPatterns } from '../elasticsearch/template/template'; -import { isRequiredPackage } from './index'; import { - BulkInstallPackageInfo, - InstallablePackage, - InstallSource, - defaultPackages, -} from '../../../../common'; + isRequiredPackage, + getInstallation, + getInstallationObject, + bulkInstallPackages, + isBulkInstallError, +} from './index'; +import { defaultPackages } from '../../../../common'; +import type { BulkInstallPackageInfo, InstallablePackage, InstallSource } from '../../../../common'; import { PACKAGES_SAVED_OBJECT_TYPE, MAX_TIME_COMPLETE_INSTALL } from '../../../constants'; -import { +import { KibanaAssetType } from '../../../types'; +import type { AssetReference, Installation, CallESAsCurrentUser, AssetType, EsAssetReference, InstallType, - KibanaAssetType, } from '../../../types'; import * as Registry from '../registry'; import { setPackageInfo, parseAndVerifyArchiveEntries, unpackBufferToCache } from '../archive'; -import { - getInstallation, - getInstallationObject, - bulkInstallPackages, - isBulkInstallError, -} from './index'; -import { toAssetReference, ArchiveAsset } from '../kibana/assets/install'; +import { toAssetReference } from '../kibana/assets/install'; +import type { ArchiveAsset } from '../kibana/assets/install'; import { removeInstallation } from './remove'; import { IngestManagerError, diff --git a/x-pack/plugins/fleet/server/services/epm/packages/remove.ts b/x-pack/plugins/fleet/server/services/epm/packages/remove.ts index 78471f70adc3c..4d05daaf82500 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/remove.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'src/core/server'; +import type { SavedObjectsClientContract } from 'src/core/server'; import Boom from '@hapi/boom'; import { PACKAGE_POLICY_SAVED_OBJECT_TYPE, PACKAGES_SAVED_OBJECT_TYPE } from '../../../constants'; -import { +import { ElasticsearchAssetType } from '../../../types'; +import type { AssetReference, AssetType, CallESAsCurrentUser, - ElasticsearchAssetType, EsAssetReference, KibanaAssetReference, Installation, diff --git a/x-pack/plugins/fleet/server/services/epm/registry/index.test.ts b/x-pack/plugins/fleet/server/services/epm/registry/index.test.ts index ca476b4ee2033..e7ac5a0ce912e 100644 --- a/x-pack/plugins/fleet/server/services/epm/registry/index.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/registry/index.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AssetParts } from '../../../types'; +import type { AssetParts } from '../../../types'; import { getBufferExtractor, getPathParts, untarBuffer, unzipBuffer } from '../archive'; import { splitPkgKey } from './index'; diff --git a/x-pack/plugins/fleet/server/services/epm/registry/index.ts b/x-pack/plugins/fleet/server/services/epm/registry/index.ts index bee979a58076b..8c5e2c9530b61 100644 --- a/x-pack/plugins/fleet/server/services/epm/registry/index.ts +++ b/x-pack/plugins/fleet/server/services/epm/registry/index.ts @@ -9,12 +9,12 @@ import mime from 'mime-types'; import semverValid from 'semver/functions/valid'; import { Response } from 'node-fetch'; import { URL } from 'url'; -import { +import { KibanaAssetType } from '../../../types'; +import type { AssetsGroupedByServiceByType, CategoryId, CategorySummaryList, InstallSource, - KibanaAssetType, RegistryPackage, RegistrySearchResults, RegistrySearchResult, diff --git a/x-pack/plugins/fleet/server/services/epm/registry/proxy.ts b/x-pack/plugins/fleet/server/services/epm/registry/proxy.ts index 655e1318d5134..0be25da2bca23 100644 --- a/x-pack/plugins/fleet/server/services/epm/registry/proxy.ts +++ b/x-pack/plugins/fleet/server/services/epm/registry/proxy.ts @@ -6,11 +6,10 @@ */ import HttpProxyAgent from 'http-proxy-agent'; -import HttpsProxyAgent, { - HttpsProxyAgent as IHttpsProxyAgent, - HttpsProxyAgentOptions, -} from 'https-proxy-agent'; +import HttpsProxyAgent, { HttpsProxyAgent as IHttpsProxyAgent } from 'https-proxy-agent'; +import type { HttpsProxyAgentOptions } from 'https-proxy-agent'; import { appContextService } from '../../index'; + export interface RegistryProxySettings { proxyUrl: string; proxyHeaders?: Record; diff --git a/x-pack/plugins/fleet/server/services/epm/registry/requests.ts b/x-pack/plugins/fleet/server/services/epm/registry/requests.ts index 8612e1d50d7e8..1b4abbc7e9b71 100644 --- a/x-pack/plugins/fleet/server/services/epm/registry/requests.ts +++ b/x-pack/plugins/fleet/server/services/epm/registry/requests.ts @@ -5,7 +5,8 @@ * 2.0. */ -import fetch, { FetchError, Response, RequestInit } from 'node-fetch'; +import fetch, { FetchError, Response } from 'node-fetch'; +import type { RequestInit } from 'node-fetch'; import pRetry from 'p-retry'; import { streamToString } from '../streams'; import { appContextService } from '../../app_context'; diff --git a/x-pack/plugins/fleet/server/services/es_index_pattern.ts b/x-pack/plugins/fleet/server/services/es_index_pattern.ts index 0d5a4c888e93f..015fb91a9660e 100644 --- a/x-pack/plugins/fleet/server/services/es_index_pattern.ts +++ b/x-pack/plugins/fleet/server/services/es_index_pattern.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'kibana/server'; +import type { SavedObjectsClientContract } from 'kibana/server'; import { getInstallation } from './epm/packages'; -import { ESIndexPatternService } from '../../server'; +import type { ESIndexPatternService } from '../../server'; export class ESIndexPatternSavedObjectService implements ESIndexPatternService { public async getESIndexPattern( diff --git a/x-pack/plugins/fleet/server/services/fleet_server/elastic_index.ts b/x-pack/plugins/fleet/server/services/fleet_server/elastic_index.ts index 4b85f753740e3..9722c28d96d23 100644 --- a/x-pack/plugins/fleet/server/services/fleet_server/elastic_index.ts +++ b/x-pack/plugins/fleet/server/services/fleet_server/elastic_index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ElasticsearchClient } from 'kibana/server'; +import type { ElasticsearchClient } from 'kibana/server'; import hash from 'object-hash'; import { FLEET_SERVER_INDICES, FLEET_SERVER_INDICES_VERSION } from '../../../common'; diff --git a/x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts b/x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts index 84e6b06e59844..d160925544adf 100644 --- a/x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts +++ b/x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts @@ -12,15 +12,16 @@ import { ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE, AGENT_POLICY_INDEX, AGENTS_INDEX, - FleetServerEnrollmentAPIKey, AGENT_SAVED_OBJECT_TYPE, + SO_SEARCH_LIMIT, +} from '../../../common'; +import type { + FleetServerEnrollmentAPIKey, AgentSOAttributes, FleetServerAgent, - SO_SEARCH_LIMIT, } from '../../../common'; import { listEnrollmentApiKeys, getEnrollmentAPIKey } from '../api_keys/enrollment_api_key_so'; import { appContextService } from '../app_context'; - import { isAgentsSetup } from '../agents'; import { agentPolicyService } from '../agent_policy'; diff --git a/x-pack/plugins/fleet/server/services/index.ts b/x-pack/plugins/fleet/server/services/index.ts index 77ce882275b6b..3f28a3f987a8e 100644 --- a/x-pack/plugins/fleet/server/services/index.ts +++ b/x-pack/plugins/fleet/server/services/index.ts @@ -5,13 +5,14 @@ * 2.0. */ -import { ElasticsearchClient, SavedObjectsClientContract, KibanaRequest } from 'kibana/server'; -import { AgentStatus, Agent, EsAssetReference } from '../types'; -import * as settingsService from './settings'; +import { KibanaRequest } from 'kibana/server'; +import type { ElasticsearchClient, SavedObjectsClientContract } from 'kibana/server'; +import type { AgentStatus, Agent, EsAssetReference } from '../types'; import { getAgent, listAgents } from './agents'; -export { ESIndexPatternSavedObjectService } from './es_index_pattern'; import { agentPolicyService } from './agent_policy'; +import * as settingsService from './settings'; +export { ESIndexPatternSavedObjectService } from './es_index_pattern'; export { getRegistryUrl } from './epm/registry/registry_url'; /** diff --git a/x-pack/plugins/fleet/server/services/install_script/install_templates/linux.ts b/x-pack/plugins/fleet/server/services/install_script/install_templates/linux.ts index dc04d099c4eb7..4e31193efc0e6 100644 --- a/x-pack/plugins/fleet/server/services/install_script/install_templates/linux.ts +++ b/x-pack/plugins/fleet/server/services/install_script/install_templates/linux.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { InstallTemplateFunction } from './types'; +import type { InstallTemplateFunction } from './types'; export const linuxInstallTemplate: InstallTemplateFunction = (variables) => { const artifact = `elastic-agent-${variables.kibanaVersion}-linux-x86_64`; diff --git a/x-pack/plugins/fleet/server/services/install_script/install_templates/macos.ts b/x-pack/plugins/fleet/server/services/install_script/install_templates/macos.ts index 14043fe8647fe..abe52f64d0e5c 100644 --- a/x-pack/plugins/fleet/server/services/install_script/install_templates/macos.ts +++ b/x-pack/plugins/fleet/server/services/install_script/install_templates/macos.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { InstallTemplateFunction } from './types'; +import type { InstallTemplateFunction } from './types'; export const macosInstallTemplate: InstallTemplateFunction = (variables) => { const artifact = `elastic-agent-${variables.kibanaVersion}-darwin-x86_64`; diff --git a/x-pack/plugins/fleet/server/services/output.ts b/x-pack/plugins/fleet/server/services/output.ts index c3e453bc0e24f..2301570c54cd2 100644 --- a/x-pack/plugins/fleet/server/services/output.ts +++ b/x-pack/plugins/fleet/server/services/output.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'src/core/server'; -import { NewOutput, Output, OutputSOAttributes } from '../types'; +import type { SavedObjectsClientContract } from 'src/core/server'; +import type { NewOutput, Output, OutputSOAttributes } from '../types'; import { DEFAULT_OUTPUT, OUTPUT_SAVED_OBJECT_TYPE } from '../constants'; import { appContextService } from './app_context'; import { decodeCloudId } from '../../common'; diff --git a/x-pack/plugins/fleet/server/services/package_policy.test.ts b/x-pack/plugins/fleet/server/services/package_policy.test.ts index 604592a0a8d87..e8991f2d66647 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.test.ts @@ -5,14 +5,17 @@ * 2.0. */ -import { elasticsearchServiceMock, savedObjectsClientMock } from 'src/core/server/mocks'; +import { + elasticsearchServiceMock, + savedObjectsClientMock, + httpServerMock, +} from 'src/core/server/mocks'; import { createPackagePolicyMock } from '../../common/mocks'; import { packagePolicyService } from './package_policy'; -import { PackageInfo, PackagePolicySOAttributes } from '../types'; -import { SavedObjectsUpdateResponse } from 'src/core/server'; -import { httpServerMock } from 'src/core/server/mocks'; +import type { PackageInfo, PackagePolicySOAttributes } from '../types'; +import type { SavedObjectsUpdateResponse } from 'src/core/server'; import { KibanaRequest } from 'kibana/server'; -import { ExternalCallback } from '..'; +import type { ExternalCallback } from '..'; import { appContextService } from './app_context'; import { createAppContextStartContractMock, xpackMocks } from '../mocks'; diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index 335cd7c956faf..3a350ded2d7ed 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -5,15 +5,20 @@ * 2.0. */ -import { +import { KibanaRequest } from 'src/core/server'; +import type { ElasticsearchClient, - KibanaRequest, RequestHandlerContext, SavedObjectsClientContract, } from 'src/core/server'; import uuid from 'uuid'; -import { AuthenticatedUser } from '../../../security/server'; +import type { AuthenticatedUser } from '../../../security/server'; import { + packageToPackagePolicy, + isPackageLimited, + doesAgentPolicyAlreadyIncludePackage, +} from '../../common'; +import type { DeletePackagePoliciesResponse, PackagePolicyInput, NewPackagePolicyInput, @@ -21,21 +26,17 @@ import { PackageInfo, ListWithKuery, ListResult, - packageToPackagePolicy, - isPackageLimited, - doesAgentPolicyAlreadyIncludePackage, } from '../../common'; import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../constants'; import { IngestManagerError, ingestErrorToResponseOptions } from '../errors'; -import { +import { NewPackagePolicySchema, UpdatePackagePolicySchema } from '../types'; +import type { NewPackagePolicy, UpdatePackagePolicy, PackagePolicy, PackagePolicySOAttributes, RegistryPackage, CallESAsCurrentUser, - NewPackagePolicySchema, - UpdatePackagePolicySchema, } from '../types'; import { agentPolicyService } from './agent_policy'; import { outputService } from './output'; @@ -45,7 +46,7 @@ import { getAssetsData } from './epm/packages/assets'; import { compileTemplate } from './epm/agent/agent'; import { normalizeKuery } from './saved_object'; import { appContextService } from '.'; -import { ExternalCallback } from '..'; +import type { ExternalCallback } from '..'; const SAVED_OBJECT_TYPE = PACKAGE_POLICY_SAVED_OBJECT_TYPE; diff --git a/x-pack/plugins/fleet/server/services/saved_object.ts b/x-pack/plugins/fleet/server/services/saved_object.ts index e6a792e4179f7..da416fa812cc4 100644 --- a/x-pack/plugins/fleet/server/services/saved_object.ts +++ b/x-pack/plugins/fleet/server/services/saved_object.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { SavedObjectsClientContract, SavedObjectsFindResponse } from 'src/core/server'; +import type { SavedObjectsClientContract, SavedObjectsFindResponse } from 'src/core/server'; import { SO_SEARCH_LIMIT } from '../constants'; -import { ListWithKuery } from '../types'; +import type { ListWithKuery } from '../types'; /** * Escape a value with double quote to use with saved object search diff --git a/x-pack/plugins/fleet/server/services/settings.ts b/x-pack/plugins/fleet/server/services/settings.ts index c58d3de9db1a7..01454c6217c05 100644 --- a/x-pack/plugins/fleet/server/services/settings.ts +++ b/x-pack/plugins/fleet/server/services/settings.ts @@ -6,15 +6,10 @@ */ import Boom from '@hapi/boom'; -import { SavedObjectsClientContract } from 'kibana/server'; +import type { SavedObjectsClientContract } from 'kibana/server'; import url from 'url'; -import { - GLOBAL_SETTINGS_SAVED_OBJECT_TYPE, - SettingsSOAttributes, - Settings, - decodeCloudId, - BaseSettings, -} from '../../common'; +import { GLOBAL_SETTINGS_SAVED_OBJECT_TYPE, decodeCloudId } from '../../common'; +import type { SettingsSOAttributes, Settings, BaseSettings } from '../../common'; import { appContextService } from './app_context'; export async function getSettings(soClient: SavedObjectsClientContract): Promise { diff --git a/x-pack/plugins/fleet/server/services/setup.ts b/x-pack/plugins/fleet/server/services/setup.ts index 2a3166e9dc729..b90f223629b60 100644 --- a/x-pack/plugins/fleet/server/services/setup.ts +++ b/x-pack/plugins/fleet/server/services/setup.ts @@ -6,8 +6,8 @@ */ import uuid from 'uuid'; -import { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; -import { CallESAsCurrentUser } from '../types'; +import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; +import type { CallESAsCurrentUser } from '../types'; import { agentPolicyService } from './agent_policy'; import { outputService } from './output'; import { @@ -17,13 +17,10 @@ import { } from './epm/packages/install'; import { packageToPackagePolicy, - PackagePolicy, - AgentPolicy, - Installation, - Output, DEFAULT_AGENT_POLICIES_PACKAGES, FLEET_SERVER_PACKAGE, } from '../../common'; +import type { PackagePolicy, AgentPolicy, Installation, Output } from '../../common'; import { SO_SEARCH_LIMIT } from '../constants'; import { getPackageInfo } from './epm/packages'; import { packagePolicyService } from './package_policy'; diff --git a/x-pack/plugins/fleet/server/types/rest_spec/common.ts b/x-pack/plugins/fleet/server/types/rest_spec/common.ts index 78af66dd50f41..2d12bd5d7c987 100644 --- a/x-pack/plugins/fleet/server/types/rest_spec/common.ts +++ b/x-pack/plugins/fleet/server/types/rest_spec/common.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { schema, TypeOf } from '@kbn/config-schema'; +import { schema } from '@kbn/config-schema'; +import type { TypeOf } from '@kbn/config-schema'; export const ListWithKuerySchema = schema.object({ page: schema.maybe(schema.number({ defaultValue: 1 })), From 5788a6bd785d4848c95ec94a79fe3ea87c4085f0 Mon Sep 17 00:00:00 2001 From: Scotty Bollinger Date: Tue, 2 Mar 2021 11:22:20 -0600 Subject: [PATCH 08/33] [Workplace Search] Role Mappings to Kibana (#93123) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add routes for role mapings * Initial copy/paste * Update RoleMappingsRouter - Update all paths - Change router to use children instead of render props - Remove legacy app chrome * Update RoleMappings - Update all paths - Use global flash messages * Update RoleMapping - Update all paths - Use global flash messages - Add types to fix errors - Use React Router Hooks instead of legacy withRouter HOC * Fix path in index and add route helper * Update paths in RoleMappingsLogic * Remove history in favor of KibanaLogic.navigateToUrl * Add Role type * Remove ID prop This is not needed because the ID is actually passed in the URL itself and is not a requirement in the body of the request * Replace contextual flash messages with global It appeared that the server sometimes sent flash messages with the API response, but I checked the Rails server code and there is no `flashMessages` sent back from the server so I am omitting that from the `RoleMappingsServerDetails` interface as well. * Replace Rails http with kibana http * Fix route path * Add route and update global navigation * Add breadcrumb/page title * Update flash messages in RoleMapping I did this for RoleMappings but forgot this one * Use explicit AttributeName type instead of string * Add i18n * Fix type issue Because the shared role mapping components work for both App Search and Workplace Search, the more generic string is used here because App Search has different role names. * Add tests for components and router * Add optional to interface In the case of a new role mapping, the server is called at the ‘/new’ route and the server responds without a roleMapping prop, as it has not yet been created. * Add tests for RoleMappingsLogic Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/layout/nav.tsx | 5 +- .../applications/workplace_search/index.tsx | 7 + .../applications/workplace_search/routes.ts | 1 + .../applications/workplace_search/types.ts | 2 + .../views/role_mappings/constants.ts | 105 +++++ .../views/role_mappings/index.ts | 8 + .../views/role_mappings/role_mapping.test.tsx | 121 ++++++ .../views/role_mappings/role_mapping.tsx | 216 ++++++++++ .../role_mappings/role_mappings.test.tsx | 57 +++ .../views/role_mappings/role_mappings.tsx | 70 ++++ .../role_mappings/role_mappings_logic.test.ts | 394 ++++++++++++++++++ .../role_mappings/role_mappings_logic.ts | 311 ++++++++++++++ .../role_mappings_router.test.tsx | 26 ++ .../role_mappings/role_mappings_router.tsx | 34 ++ .../server/routes/workplace_search/index.ts | 2 + .../workplace_search/role_mappings.test.ts | 154 +++++++ .../routes/workplace_search/role_mappings.ts | 117 ++++++ 17 files changed, 1626 insertions(+), 4 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/constants.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/index.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mapping.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mapping.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_logic.test.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_logic.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_router.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_router.tsx create mode 100644 x-pack/plugins/enterprise_search/server/routes/workplace_search/role_mappings.test.ts create mode 100644 x-pack/plugins/enterprise_search/server/routes/workplace_search/role_mappings.ts diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.tsx index 16722c1554ddf..f2edc04a5661c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.tsx @@ -10,7 +10,6 @@ import React from 'react'; import { EuiSpacer } from '@elastic/eui'; import { WORKPLACE_SEARCH_PLUGIN } from '../../../../../common/constants'; -import { getWorkplaceSearchUrl } from '../../../shared/enterprise_search_url'; import { SideNav, SideNavLink } from '../../../shared/layout'; import { NAV } from '../../constants'; import { @@ -43,9 +42,7 @@ export const WorkplaceSearchNav: React.FC = ({ {NAV.GROUPS} - - {NAV.ROLE_MAPPINGS} - + {NAV.ROLE_MAPPINGS} {NAV.SECURITY} {NAV.SETTINGS} diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx index 3cd1a3bd136b8..656c93053e22b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx @@ -26,6 +26,7 @@ import { SOURCES_PATH, PERSONAL_SOURCES_PATH, ORG_SETTINGS_PATH, + ROLE_MAPPINGS_PATH, SECURITY_PATH, } from './routes'; import { SourcesRouter } from './views/content_sources'; @@ -36,6 +37,7 @@ import { GroupsRouter } from './views/groups'; import { GroupSubNav } from './views/groups/components/group_sub_nav'; import { Overview } from './views/overview'; import { Overview as OverviewMVP } from './views/overview_mvp'; +import { RoleMappingsRouter } from './views/role_mappings'; import { Security } from './views/security'; import { SettingsRouter } from './views/settings'; import { SettingsSubNav } from './views/settings/components/settings_sub_nav'; @@ -111,6 +113,11 @@ export const WorkplaceSearchConfigured: React.FC = (props) => { + + } restrictWidth readOnlyMode={readOnlyMode}> + + + } restrictWidth readOnlyMode={readOnlyMode}> diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.ts index 462f89abd6143..50f6596a860c5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.ts @@ -133,3 +133,4 @@ export const getReindexJobRoute = ( isOrganization: boolean ) => getSourcesPath(generatePath(REINDEX_JOB_PATH, { sourceId, activeReindexJobId }), isOrganization); +export const getRoleMappingPath = (roleId: string) => generatePath(ROLE_MAPPING_PATH, { roleId }); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/types.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/types.ts index 44e0fd5b6f287..79fe6dc8c92cb 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/types.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/types.ts @@ -22,6 +22,8 @@ export interface Meta { page: MetaPage; } +export type Role = 'admin' | 'user'; + export interface Group { id: string; name: string; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/constants.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/constants.ts new file mode 100644 index 0000000000000..5930f7862cd83 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/constants.ts @@ -0,0 +1,105 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const DELETE_ROLE_MAPPING_MESSAGE = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.deleteRoleMappingButtonMessage', + { + defaultMessage: + 'Are you sure you want to permanently delete this mapping? This action is not reversible and some users might lose access.', + } +); + +export const DEFAULT_GROUP_NAME = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.defaultGroupName', + { + defaultMessage: 'Default', + } +); + +export const ADMIN_ROLE_TYPE_DESCRIPTION = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.adminRoleTypeDescription', + { + defaultMessage: + 'Admins have complete access to all organization-wide settings, including content source, group and user management functionality.', + } +); + +export const USER_ROLE_TYPE_DESCRIPTION = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.userRoleTypeDescription', + { + defaultMessage: + "Users' feature access is limited to search interfaces and personal settings management.", + } +); + +export const ROLE_SELECTOR_DISABLED_TEXT = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.roleSelectorDisabledText', + { + defaultMessage: + 'You need at least one admin role mapping before you can create a user role mapping.', + } +); + +export const GROUP_ASSIGNMENT_TITLE = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.groupAssignmentTitle', + { + defaultMessage: 'Group assignment', + } +); + +export const GROUP_ASSIGNMENT_INVALID_ERROR = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.groupAssignmentInvalidError', + { + defaultMessage: 'At least one assigned group is required.', + } +); + +export const GROUP_ASSIGNMENT_ALL_GROUPS_LABEL = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.groupAssignmentAllGroupsLabel', + { + defaultMessage: 'Include in all groups, including future groups', + } +); + +export const EMPTY_ROLE_MAPPINGS_TITLE = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.emptyRoleMappingsTitle', + { + defaultMessage: 'No role mappings yet', + } +); + +export const EMPTY_ROLE_MAPPINGS_BODY = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.emptyRoleMappingsBody', + { + defaultMessage: + 'New team members are assigned the admin role by default. An admin can access everything. Create a new role to override the default.', + } +); + +export const ROLE_MAPPINGS_TABLE_HEADER = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.roleMappingsTableHeader', + { + defaultMessage: 'Group Access', + } +); + +export const ROLE_MAPPINGS_TITLE = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.roleMappingsTitle', + { + defaultMessage: 'Users & roles', + } +); + +export const ROLE_MAPPINGS_DESCRIPTION = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.roleMappingsDescription', + { + defaultMessage: + 'Define role mappings for elasticsearch-native and elasticsearch-saml authentication.', + } +); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/index.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/index.ts new file mode 100644 index 0000000000000..ce4b1de6e399d --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { RoleMappingsRouter } from './role_mappings_router'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mapping.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mapping.test.tsx new file mode 100644 index 0000000000000..4742b741c9640 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mapping.test.tsx @@ -0,0 +1,121 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import '../../../__mocks__/shallow_useeffect.mock'; +import { setMockActions, setMockValues } from '../../../__mocks__'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiCheckbox } from '@elastic/eui'; + +import { Loading } from '../../../shared/loading'; +import { + AttributeSelector, + DeleteMappingCallout, + RoleSelector, +} from '../../../shared/role_mapping'; +import { wsRoleMapping } from '../../../shared/role_mapping/__mocks__/roles'; + +import { RoleMapping } from './role_mapping'; + +describe('RoleMapping', () => { + const initializeRoleMappings = jest.fn(); + const initializeRoleMapping = jest.fn(); + const handleSaveMapping = jest.fn(); + const handleGroupSelectionChange = jest.fn(); + const handleAllGroupsSelectionChange = jest.fn(); + const handleAttributeValueChange = jest.fn(); + const handleAttributeSelectorChange = jest.fn(); + const handleDeleteMapping = jest.fn(); + const handleRoleChange = jest.fn(); + const handleAuthProviderChange = jest.fn(); + const resetState = jest.fn(); + const groups = [ + { + name: 'Group 1', + id: 'g1', + }, + { + name: 'Group 2', + id: 'g2', + }, + ]; + const mockValues = { + attributes: [], + elasticsearchRoles: [], + dataLoading: false, + roleType: 'admin', + roleMappings: [wsRoleMapping], + attributeValue: '', + attributeName: 'username', + availableGroups: groups, + selectedGroups: new Set(), + includeInAllGroups: false, + availableAuthProviders: [], + multipleAuthProvidersConfig: true, + selectedAuthProviders: [], + }; + + beforeEach(() => { + setMockActions({ + initializeRoleMappings, + initializeRoleMapping, + handleSaveMapping, + handleGroupSelectionChange, + handleAllGroupsSelectionChange, + handleAttributeValueChange, + handleAttributeSelectorChange, + handleDeleteMapping, + handleRoleChange, + handleAuthProviderChange, + resetState, + }); + setMockValues(mockValues); + }); + + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find(AttributeSelector)).toHaveLength(1); + expect(wrapper.find(RoleSelector)).toHaveLength(2); + }); + + it('returns Loading when loading', () => { + setMockValues({ ...mockValues, dataLoading: true }); + const wrapper = shallow(); + + expect(wrapper.find(Loading)).toHaveLength(1); + }); + + it('hides DeleteMappingCallout for new mapping', () => { + const wrapper = shallow(); + + expect(wrapper.find(DeleteMappingCallout)).toHaveLength(0); + }); + + it('handles group checkbox click', () => { + const wrapper = shallow(); + wrapper + .find(EuiCheckbox) + .first() + .simulate('change', { target: { checked: true } }); + + expect(handleGroupSelectionChange).toHaveBeenCalledWith(groups[0].id, true); + }); + + it('handles all groups checkbox click', () => { + const wrapper = shallow(); + wrapper + .find(EuiCheckbox) + .last() + .simulate('change', { target: { checked: true } }); + + expect(handleAllGroupsSelectionChange).toHaveBeenCalledWith(true); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mapping.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mapping.tsx new file mode 100644 index 0000000000000..b2911bbcc64c2 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mapping.tsx @@ -0,0 +1,216 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useEffect } from 'react'; + +import { useParams } from 'react-router-dom'; + +import { useActions, useValues } from 'kea'; + +import { + EuiButton, + EuiCheckbox, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiPanel, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { FlashMessages } from '../../../shared/flash_messages'; +import { Loading } from '../../../shared/loading'; +import { + AttributeSelector, + DeleteMappingCallout, + RoleSelector, +} from '../../../shared/role_mapping'; +import { ROLE_LABEL } from '../../../shared/role_mapping/constants'; +import { ViewContentHeader } from '../../components/shared/view_content_header'; +import { Role } from '../../types'; + +import { + ADMIN_ROLE_TYPE_DESCRIPTION, + USER_ROLE_TYPE_DESCRIPTION, + ROLE_SELECTOR_DISABLED_TEXT, + GROUP_ASSIGNMENT_TITLE, + GROUP_ASSIGNMENT_INVALID_ERROR, + GROUP_ASSIGNMENT_ALL_GROUPS_LABEL, +} from './constants'; + +import { RoleMappingsLogic } from './role_mappings_logic'; + +interface RoleType { + type: Role; + description: string; +} + +const roleTypes = [ + { + type: 'admin', + description: ADMIN_ROLE_TYPE_DESCRIPTION, + }, + { + type: 'user', + description: USER_ROLE_TYPE_DESCRIPTION, + }, +] as RoleType[]; + +interface RoleMappingProps { + isNew?: boolean; +} + +export const RoleMapping: React.FC = ({ isNew }) => { + const { roleId } = useParams() as { roleId: string }; + const { + initializeRoleMappings, + initializeRoleMapping, + handleSaveMapping, + handleGroupSelectionChange, + handleAllGroupsSelectionChange, + handleAttributeValueChange, + handleAttributeSelectorChange, + handleDeleteMapping, + handleRoleChange, + handleAuthProviderChange, + resetState, + } = useActions(RoleMappingsLogic); + + const { + attributes, + elasticsearchRoles, + dataLoading, + roleType, + roleMappings, + attributeValue, + attributeName, + availableGroups, + selectedGroups, + includeInAllGroups, + availableAuthProviders, + multipleAuthProvidersConfig, + selectedAuthProviders, + } = useValues(RoleMappingsLogic); + + useEffect(() => { + initializeRoleMappings(); + initializeRoleMapping(roleId); + return resetState; + }, [roleId]); + + if (dataLoading) return ; + + const hasGroupAssignment = selectedGroups.size > 0 || includeInAllGroups; + + const SAVE_ROLE_MAPPING_LABEL = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.saveRoleMappingButtonMessage', + { + defaultMessage: '{operation} role mapping', + values: { operation: isNew ? 'Save' : 'Update' }, + } + ); + + const saveRoleMappingButton = ( + + {SAVE_ROLE_MAPPING_LABEL} + + ); + + const hasAdminRoleMapping = roleMappings.some( + ({ roleType: roleMappingRoleType }: { roleType: string }) => + roleMappingRoleType === ('admin' as string) + ); + + return ( + <> + + +
+ + + + + + + +

{ROLE_LABEL}

+
+ + {roleTypes.map(({ type, description }) => ( + + ))} +
+
+ + + +

{GROUP_ASSIGNMENT_TITLE}

+
+ +
+ + <> + {availableGroups.map(({ id, name }) => ( + { + handleGroupSelectionChange(id, e.target.checked); + }} + label={name} + disabled={includeInAllGroups} + /> + ))} + + { + handleAllGroupsSelectionChange(e.target.checked); + }} + label={GROUP_ASSIGNMENT_ALL_GROUPS_LABEL} + /> + + +
+
+
+
+ + {!isNew && } +
+ + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.test.tsx new file mode 100644 index 0000000000000..c6da903e20912 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.test.tsx @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import '../../../__mocks__/shallow_useeffect.mock'; +import { setMockActions, setMockValues } from '../../../__mocks__'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiEmptyPrompt } from '@elastic/eui'; + +import { Loading } from '../../../shared/loading'; +import { RoleMappingsTable } from '../../../shared/role_mapping'; +import { wsRoleMapping } from '../../../shared/role_mapping/__mocks__/roles'; + +import { RoleMappings } from './role_mappings'; + +describe('RoleMappings', () => { + const initializeRoleMappings = jest.fn(); + const mockValues = { + roleMappings: [wsRoleMapping], + dataLoading: false, + multipleAuthProvidersConfig: false, + }; + + beforeEach(() => { + setMockActions({ + initializeRoleMappings, + }); + setMockValues(mockValues); + }); + + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find(RoleMappingsTable)).toHaveLength(1); + }); + + it('returns Loading when loading', () => { + setMockValues({ ...mockValues, dataLoading: true }); + const wrapper = shallow(); + + expect(wrapper.find(Loading)).toHaveLength(1); + }); + + it('renders empty state', () => { + setMockValues({ ...mockValues, roleMappings: [] }); + const wrapper = shallow(); + + expect(wrapper.find(EuiEmptyPrompt)).toHaveLength(1); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.tsx new file mode 100644 index 0000000000000..e47b2646459df --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.tsx @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useEffect } from 'react'; + +import { useActions, useValues } from 'kea'; + +import { EuiEmptyPrompt } from '@elastic/eui'; + +import { FlashMessages } from '../../../shared/flash_messages'; +import { Loading } from '../../../shared/loading'; +import { AddRoleMappingButton, RoleMappingsTable } from '../../../shared/role_mapping'; +import { ViewContentHeader } from '../../components/shared/view_content_header'; +import { getRoleMappingPath, ROLE_MAPPING_NEW_PATH } from '../../routes'; + +import { + EMPTY_ROLE_MAPPINGS_TITLE, + EMPTY_ROLE_MAPPINGS_BODY, + ROLE_MAPPINGS_TABLE_HEADER, + ROLE_MAPPINGS_TITLE, + ROLE_MAPPINGS_DESCRIPTION, +} from './constants'; + +import { RoleMappingsLogic } from './role_mappings_logic'; + +export const RoleMappings: React.FC = () => { + const { initializeRoleMappings } = useActions(RoleMappingsLogic); + + const { roleMappings, dataLoading, multipleAuthProvidersConfig } = useValues(RoleMappingsLogic); + + useEffect(() => { + initializeRoleMappings(); + }, []); + + if (dataLoading) return ; + + const addMappingButton = ; + const emptyPrompt = ( + {EMPTY_ROLE_MAPPINGS_TITLE}} + body={

{EMPTY_ROLE_MAPPINGS_BODY}

} + actions={addMappingButton} + /> + ); + const roleMappingsTable = ( + + ); + + return ( + <> + +
+ + {roleMappings.length === 0 ? emptyPrompt : roleMappingsTable} +
+ + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_logic.test.ts new file mode 100644 index 0000000000000..a9526d9450993 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_logic.test.ts @@ -0,0 +1,394 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { mockFlashMessageHelpers, mockHttpValues, mockKibanaValues } from '../../../__mocks__'; +import { LogicMounter } from '../../../__mocks__/kea.mock'; + +import { groups } from '../../__mocks__/groups.mock'; + +import { nextTick } from '@kbn/test/jest'; + +import { wsRoleMapping } from '../../../shared/role_mapping/__mocks__/roles'; +import { ANY_AUTH_PROVIDER } from '../../../shared/role_mapping/constants'; + +import { RoleMappingsLogic } from './role_mappings_logic'; + +describe('RoleMappingsLogic', () => { + const { http } = mockHttpValues; + const { navigateToUrl } = mockKibanaValues; + const { clearFlashMessages, flashAPIErrors } = mockFlashMessageHelpers; + const { mount } = new LogicMounter(RoleMappingsLogic); + const defaultValues = { + attributes: [], + availableAuthProviders: [], + elasticsearchRoles: [], + roleMapping: null, + roleMappings: [], + roleType: 'admin', + attributeValue: '', + attributeName: 'username', + dataLoading: true, + multipleAuthProvidersConfig: false, + availableGroups: [], + selectedGroups: new Set(), + includeInAllGroups: false, + selectedAuthProviders: [ANY_AUTH_PROVIDER], + }; + const roleGroup = { + id: '123', + name: 'Role Group', + }; + const defaultGroup = { + id: '124', + name: 'Default', + }; + + const mappingsServerProps = { multipleAuthProvidersConfig: true, roleMappings: [wsRoleMapping] }; + const mappingServerProps = { + attributes: [], + authProviders: [], + availableGroups: [roleGroup, defaultGroup], + elasticsearchRoles: [], + multipleAuthProvidersConfig: false, + roleMapping: wsRoleMapping, + }; + + beforeEach(() => { + jest.clearAllMocks(); + mount(); + }); + + it('has expected default values', () => { + expect(RoleMappingsLogic.values).toEqual(defaultValues); + }); + + describe('actions', () => { + it('setRoleMappingsData', () => { + RoleMappingsLogic.actions.setRoleMappingsData(mappingsServerProps); + + expect(RoleMappingsLogic.values.roleMappings).toEqual([wsRoleMapping]); + expect(RoleMappingsLogic.values.dataLoading).toEqual(false); + expect(RoleMappingsLogic.values.multipleAuthProvidersConfig).toEqual(true); + }); + + describe('setRoleMappingData', () => { + it('sets data correctly', () => { + RoleMappingsLogic.actions.setRoleMappingData(mappingServerProps); + + expect(RoleMappingsLogic.values.roleMapping).toEqual(wsRoleMapping); + expect(RoleMappingsLogic.values.dataLoading).toEqual(false); + expect(RoleMappingsLogic.values.attributes).toEqual(mappingServerProps.attributes); + expect(RoleMappingsLogic.values.availableGroups).toEqual( + mappingServerProps.availableGroups + ); + expect(RoleMappingsLogic.values.includeInAllGroups).toEqual(true); + expect(RoleMappingsLogic.values.elasticsearchRoles).toEqual( + mappingServerProps.elasticsearchRoles + ); + expect(RoleMappingsLogic.values.selectedGroups).toEqual( + new Set([wsRoleMapping.groups[0].id]) + ); + }); + + it('sets default group with new role mapping', () => { + RoleMappingsLogic.actions.setRoleMappingData({ + ...mappingServerProps, + roleMapping: undefined, + }); + + expect(RoleMappingsLogic.values.selectedGroups).toEqual(new Set([defaultGroup.id])); + }); + }); + + it('handleRoleChange', () => { + RoleMappingsLogic.actions.handleRoleChange('user'); + + expect(RoleMappingsLogic.values.roleType).toEqual('user'); + }); + + it('handleGroupSelectionChange', () => { + const group = wsRoleMapping.groups[0]; + const otherGroup = groups[0]; + RoleMappingsLogic.actions.setRoleMappingData({ + ...mappingServerProps, + roleMapping: { + ...wsRoleMapping, + groups: [group, otherGroup], + }, + }); + + RoleMappingsLogic.actions.handleGroupSelectionChange(otherGroup.id, true); + expect(RoleMappingsLogic.values.selectedGroups).toEqual(new Set([group.id, otherGroup.id])); + + RoleMappingsLogic.actions.handleGroupSelectionChange(otherGroup.id, false); + expect(RoleMappingsLogic.values.selectedGroups).toEqual(new Set([group.id])); + }); + + it('handleAllGroupsSelectionChange', () => { + RoleMappingsLogic.actions.handleAllGroupsSelectionChange(true); + + expect(RoleMappingsLogic.values.includeInAllGroups).toEqual(true); + }); + + describe('handleAttributeSelectorChange', () => { + const elasticsearchRoles = ['foo', 'bar']; + + it('sets values correctly', () => { + RoleMappingsLogic.actions.setRoleMappingData({ + ...mappingServerProps, + elasticsearchRoles, + }); + RoleMappingsLogic.actions.handleAttributeSelectorChange('role', elasticsearchRoles[0]); + + expect(RoleMappingsLogic.values.attributeValue).toEqual(elasticsearchRoles[0]); + expect(RoleMappingsLogic.values.attributeName).toEqual('role'); + }); + + it('correctly handles "role" fallback', () => { + RoleMappingsLogic.actions.handleAttributeSelectorChange('username', elasticsearchRoles[0]); + + expect(RoleMappingsLogic.values.attributeValue).toEqual(''); + }); + }); + + it('handleAttributeValueChange', () => { + RoleMappingsLogic.actions.handleAttributeValueChange('changed_value'); + + expect(RoleMappingsLogic.values.attributeValue).toEqual('changed_value'); + }); + + describe('handleAuthProviderChange', () => { + beforeEach(() => { + RoleMappingsLogic.actions.setRoleMappingData({ + ...mappingServerProps, + roleMapping: { + ...wsRoleMapping, + authProvider: ['foo'], + }, + }); + }); + const providers = ['bar', 'baz']; + const providerWithAny = [ANY_AUTH_PROVIDER, providers[1]]; + it('handles empty state', () => { + RoleMappingsLogic.actions.handleAuthProviderChange([]); + + expect(RoleMappingsLogic.values.selectedAuthProviders).toEqual([ANY_AUTH_PROVIDER]); + }); + + it('handles single value', () => { + RoleMappingsLogic.actions.handleAuthProviderChange([providers[0]]); + + expect(RoleMappingsLogic.values.selectedAuthProviders).toEqual([providers[0]]); + }); + + it('handles multiple values', () => { + RoleMappingsLogic.actions.handleAuthProviderChange(providers); + + expect(RoleMappingsLogic.values.selectedAuthProviders).toEqual(providers); + }); + + it('handles "any" auth in previous state', () => { + RoleMappingsLogic.actions.setRoleMappingData({ + ...mappingServerProps, + roleMapping: { + ...wsRoleMapping, + authProvider: [ANY_AUTH_PROVIDER], + }, + }); + RoleMappingsLogic.actions.handleAuthProviderChange(providerWithAny); + + expect(RoleMappingsLogic.values.selectedAuthProviders).toEqual([providers[1]]); + }); + + it('handles catch-all state', () => { + RoleMappingsLogic.actions.handleAuthProviderChange(providerWithAny); + + expect(RoleMappingsLogic.values.selectedAuthProviders).toEqual([ANY_AUTH_PROVIDER]); + }); + }); + + it('resetState', () => { + RoleMappingsLogic.actions.setRoleMappingsData(mappingsServerProps); + RoleMappingsLogic.actions.setRoleMappingData(mappingServerProps); + RoleMappingsLogic.actions.resetState(); + + expect(RoleMappingsLogic.values.dataLoading).toEqual(true); + expect(RoleMappingsLogic.values.roleMappings).toEqual([]); + expect(RoleMappingsLogic.values.roleMapping).toEqual(null); + expect(RoleMappingsLogic.values.attributeValue).toEqual(''); + expect(RoleMappingsLogic.values.attributeName).toEqual('username'); + expect(clearFlashMessages).toHaveBeenCalled(); + }); + }); + + describe('listeners', () => { + describe('initializeRoleMappings', () => { + it('calls API and sets values', async () => { + const setRoleMappingsDataSpy = jest.spyOn(RoleMappingsLogic.actions, 'setRoleMappingsData'); + http.get.mockReturnValue(Promise.resolve(mappingsServerProps)); + RoleMappingsLogic.actions.initializeRoleMappings(); + + expect(http.get).toHaveBeenCalledWith('/api/workplace_search/org/role_mappings'); + await nextTick(); + expect(setRoleMappingsDataSpy).toHaveBeenCalledWith(mappingsServerProps); + }); + + it('handles error', async () => { + http.get.mockReturnValue(Promise.reject('this is an error')); + RoleMappingsLogic.actions.initializeRoleMappings(); + await nextTick(); + + expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); + }); + }); + + describe('initializeRoleMapping', () => { + it('calls API and sets values for new mapping', async () => { + const setRoleMappingDataSpy = jest.spyOn(RoleMappingsLogic.actions, 'setRoleMappingData'); + http.get.mockReturnValue(Promise.resolve(mappingServerProps)); + RoleMappingsLogic.actions.initializeRoleMapping(); + + expect(http.get).toHaveBeenCalledWith('/api/workplace_search/org/role_mappings/new'); + await nextTick(); + expect(setRoleMappingDataSpy).toHaveBeenCalledWith(mappingServerProps); + }); + + it('calls API and sets values for existing mapping', async () => { + const setRoleMappingDataSpy = jest.spyOn(RoleMappingsLogic.actions, 'setRoleMappingData'); + http.get.mockReturnValue(Promise.resolve(mappingServerProps)); + RoleMappingsLogic.actions.initializeRoleMapping('123'); + + expect(http.get).toHaveBeenCalledWith('/api/workplace_search/org/role_mappings/123'); + await nextTick(); + expect(setRoleMappingDataSpy).toHaveBeenCalledWith(mappingServerProps); + }); + + it('handles error', async () => { + http.get.mockReturnValue(Promise.reject('this is an error')); + RoleMappingsLogic.actions.initializeRoleMapping(); + await nextTick(); + + expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); + }); + + it('redirects when there is a 404 status', async () => { + http.get.mockReturnValue(Promise.reject({ status: 404 })); + RoleMappingsLogic.actions.initializeRoleMapping(); + await nextTick(); + + expect(navigateToUrl).toHaveBeenCalled(); + }); + }); + + describe('handleSaveMapping', () => { + it('calls API and navigates when new mapping', async () => { + RoleMappingsLogic.actions.setRoleMappingsData(mappingsServerProps); + + http.post.mockReturnValue(Promise.resolve(mappingServerProps)); + RoleMappingsLogic.actions.handleSaveMapping(); + + expect(http.post).toHaveBeenCalledWith('/api/workplace_search/org/role_mappings', { + body: JSON.stringify({ + rules: { + username: '', + }, + roleType: 'admin', + groups: [], + allGroups: false, + authProvider: [ANY_AUTH_PROVIDER], + }), + }); + await nextTick(); + + expect(navigateToUrl).toHaveBeenCalled(); + }); + + it('calls API and navigates when existing mapping', async () => { + RoleMappingsLogic.actions.setRoleMappingData(mappingServerProps); + + http.put.mockReturnValue(Promise.resolve(mappingServerProps)); + RoleMappingsLogic.actions.handleSaveMapping(); + + expect(http.put).toHaveBeenCalledWith( + `/api/workplace_search/org/role_mappings/${wsRoleMapping.id}`, + { + body: JSON.stringify({ + rules: { + username: 'user', + }, + roleType: 'admin', + groups: [], + allGroups: true, + authProvider: [ANY_AUTH_PROVIDER, 'other_auth'], + }), + } + ); + await nextTick(); + + expect(navigateToUrl).toHaveBeenCalled(); + }); + + it('handles error', async () => { + http.post.mockReturnValue(Promise.reject('this is an error')); + RoleMappingsLogic.actions.handleSaveMapping(); + await nextTick(); + + expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); + }); + }); + + describe('handleDeleteMapping', () => { + let confirmSpy: any; + + beforeEach(() => { + confirmSpy = jest.spyOn(window, 'confirm'); + confirmSpy.mockImplementation(jest.fn(() => true)); + }); + + afterEach(() => { + confirmSpy.mockRestore(); + }); + + it('returns when no mapping', () => { + RoleMappingsLogic.actions.handleDeleteMapping(); + + expect(http.delete).not.toHaveBeenCalled(); + }); + + it('calls API and navigates', async () => { + RoleMappingsLogic.actions.setRoleMappingData(mappingServerProps); + http.delete.mockReturnValue(Promise.resolve({})); + RoleMappingsLogic.actions.handleDeleteMapping(); + + expect(http.delete).toHaveBeenCalledWith( + `/api/workplace_search/org/role_mappings/${wsRoleMapping.id}` + ); + await nextTick(); + + expect(navigateToUrl).toHaveBeenCalled(); + }); + + it('handles error', async () => { + RoleMappingsLogic.actions.setRoleMappingData(mappingServerProps); + http.delete.mockReturnValue(Promise.reject('this is an error')); + RoleMappingsLogic.actions.handleDeleteMapping(); + await nextTick(); + + expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); + }); + + it('will do nothing if not confirmed', async () => { + RoleMappingsLogic.actions.setRoleMappingData(mappingServerProps); + window.confirm = () => false; + RoleMappingsLogic.actions.handleDeleteMapping(); + + expect(http.delete).not.toHaveBeenCalled(); + await nextTick(); + }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_logic.ts new file mode 100644 index 0000000000000..6fc3867d7ab1e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_logic.ts @@ -0,0 +1,311 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { kea, MakeLogicType } from 'kea'; + +import { clearFlashMessages, flashAPIErrors } from '../../../shared/flash_messages'; +import { HttpLogic } from '../../../shared/http'; +import { KibanaLogic } from '../../../shared/kibana'; +import { AttributeName } from '../../../shared/role_mapping/attribute_selector'; +import { ANY_AUTH_PROVIDER } from '../../../shared/role_mapping/constants'; +import { ROLE_MAPPINGS_PATH } from '../../routes'; +import { RoleGroup, WSRoleMapping, Role } from '../../types'; + +import { DELETE_ROLE_MAPPING_MESSAGE, DEFAULT_GROUP_NAME } from './constants'; + +interface RoleMappingsServerDetails { + multipleAuthProvidersConfig: boolean; + roleMappings: WSRoleMapping[]; +} + +interface RoleMappingServerDetails { + attributes: string[]; + authProviders: string[]; + availableGroups: RoleGroup[]; + elasticsearchRoles: string[]; + multipleAuthProvidersConfig: boolean; + roleMapping?: WSRoleMapping; +} + +interface RoleMappingsActions { + setRoleMappingsData(data: RoleMappingsServerDetails): RoleMappingsServerDetails; + setRoleMappingData(data: RoleMappingServerDetails): RoleMappingServerDetails; + handleRoleChange(roleType: Role): { roleType: Role }; + handleAllGroupsSelectionChange(selected: boolean): { selected: boolean }; + handleAttributeSelectorChange( + value: AttributeName, + firstElasticsearchRole: string + ): { value: AttributeName; firstElasticsearchRole: string }; + handleAttributeValueChange(value: string): { value: string }; + handleGroupSelectionChange( + groupId: string, + selected: boolean + ): { groupId: string; selected: boolean }; + handleAuthProviderChange(value: string[]): { value: string[] }; + resetState(): void; + initializeRoleMapping(roleId?: string): { roleId?: string }; + handleSaveMapping(): void; + handleDeleteMapping(): void; + initializeRoleMappings(): void; +} + +interface RoleMappingsValues { + attributes: string[]; + availableAuthProviders: string[]; + elasticsearchRoles: string[]; + roleMapping: WSRoleMapping | null; + roleMappings: WSRoleMapping[]; + roleType: Role; + attributeValue: string; + attributeName: AttributeName; + dataLoading: boolean; + multipleAuthProvidersConfig: boolean; + availableGroups: RoleGroup[]; + selectedGroups: Set; + includeInAllGroups: boolean; + selectedAuthProviders: string[]; +} + +const getFirstAttributeName = (roleMapping: WSRoleMapping): AttributeName => + Object.entries(roleMapping.rules)[0][0] as AttributeName; +const getFirstAttributeValue = (roleMapping: WSRoleMapping): string => + Object.entries(roleMapping.rules)[0][1] as string; + +export const RoleMappingsLogic = kea>({ + actions: { + setRoleMappingsData: (data: RoleMappingsServerDetails) => data, + setRoleMappingData: (data: RoleMappingServerDetails) => data, + handleRoleChange: (roleType: Role) => ({ roleType }), + handleGroupSelectionChange: (groupId: string, selected: boolean) => ({ groupId, selected }), + handleAllGroupsSelectionChange: (selected: boolean) => ({ selected }), + handleAttributeSelectorChange: (value: string, firstElasticsearchRole: string) => ({ + value, + firstElasticsearchRole, + }), + handleAttributeValueChange: (value: string) => ({ value }), + handleAuthProviderChange: (value: string[]) => ({ value }), + resetState: () => true, + initializeRoleMapping: (roleId?: string) => ({ roleId }), + handleSaveMapping: () => true, + handleDeleteMapping: () => true, + initializeRoleMappings: () => true, + }, + reducers: { + dataLoading: [ + true, + { + setRoleMappingsData: () => false, + setRoleMappingData: () => false, + resetState: () => true, + }, + ], + roleMappings: [ + [], + { + setRoleMappingsData: (_, { roleMappings }) => roleMappings, + resetState: () => [], + }, + ], + attributes: [ + [], + { + setRoleMappingData: (_, { attributes }) => attributes, + }, + ], + availableGroups: [ + [], + { + setRoleMappingData: (_, { availableGroups }) => availableGroups, + }, + ], + selectedGroups: [ + new Set(), + { + setRoleMappingData: (_, { roleMapping, availableGroups }) => + roleMapping + ? new Set(roleMapping.groups.map((group) => group.id)) + : new Set( + availableGroups + .filter((group) => group.name === DEFAULT_GROUP_NAME) + .map((group) => group.id) + ), + handleGroupSelectionChange: (groups, { groupId, selected }) => { + const newSelectedGroupNames = new Set(groups as Set); + if (selected) { + newSelectedGroupNames.add(groupId); + } else { + newSelectedGroupNames.delete(groupId); + } + return newSelectedGroupNames; + }, + }, + ], + includeInAllGroups: [ + false, + { + setRoleMappingData: (_, { roleMapping }) => (roleMapping ? roleMapping.allGroups : false), + handleAllGroupsSelectionChange: (_, { selected }) => selected, + }, + ], + elasticsearchRoles: [ + [], + { + setRoleMappingData: (_, { elasticsearchRoles }) => elasticsearchRoles, + }, + ], + roleMapping: [ + null, + { + setRoleMappingData: (_, { roleMapping }) => roleMapping || null, + resetState: () => null, + }, + ], + roleType: [ + 'admin', + { + setRoleMappingData: (_, { roleMapping }) => + roleMapping ? (roleMapping.roleType as Role) : 'admin', + handleRoleChange: (_, { roleType }) => roleType, + }, + ], + attributeValue: [ + '', + { + setRoleMappingData: (_, { roleMapping }) => + roleMapping ? getFirstAttributeValue(roleMapping) : '', + handleAttributeSelectorChange: (_, { value, firstElasticsearchRole }) => + value === 'role' ? firstElasticsearchRole : '', + handleAttributeValueChange: (_, { value }) => value, + resetState: () => '', + }, + ], + attributeName: [ + 'username', + { + setRoleMappingData: (_, { roleMapping }) => + roleMapping ? getFirstAttributeName(roleMapping) : 'username', + handleAttributeSelectorChange: (_, { value }) => value, + resetState: () => 'username', + }, + ], + availableAuthProviders: [ + [], + { + setRoleMappingData: (_, { authProviders }) => authProviders, + }, + ], + multipleAuthProvidersConfig: [ + false, + { + setRoleMappingsData: (_, { multipleAuthProvidersConfig }) => multipleAuthProvidersConfig, + setRoleMappingData: (_, { multipleAuthProvidersConfig }) => multipleAuthProvidersConfig, + resetState: () => false, + }, + ], + selectedAuthProviders: [ + [ANY_AUTH_PROVIDER], + { + handleAuthProviderChange: (previous, { value }) => { + const previouslyContainedAny = previous.includes(ANY_AUTH_PROVIDER); + const newSelectionsContainAny = value.includes(ANY_AUTH_PROVIDER); + + if (value.length < 1) return [ANY_AUTH_PROVIDER]; + if (value.length === 1) return value; + if (!newSelectionsContainAny) return value; + if (previouslyContainedAny) return value.filter((v) => v !== ANY_AUTH_PROVIDER); + return [ANY_AUTH_PROVIDER]; + }, + setRoleMappingData: (_, { roleMapping }) => + roleMapping ? roleMapping.authProvider : [ANY_AUTH_PROVIDER], + }, + ], + }, + listeners: ({ actions, values }) => ({ + initializeRoleMappings: async () => { + const { http } = HttpLogic.values; + const route = '/api/workplace_search/org/role_mappings'; + + try { + const response = await http.get(route); + actions.setRoleMappingsData(response); + } catch (e) { + flashAPIErrors(e); + } + }, + initializeRoleMapping: async ({ roleId }) => { + const { http } = HttpLogic.values; + const { navigateToUrl } = KibanaLogic.values; + const route = roleId + ? `/api/workplace_search/org/role_mappings/${roleId}` + : '/api/workplace_search/org/role_mappings/new'; + + try { + const response = await http.get(route); + actions.setRoleMappingData(response); + } catch (e) { + if (e.status === 404) { + navigateToUrl(ROLE_MAPPINGS_PATH); + } + flashAPIErrors(e); + } + }, + handleDeleteMapping: async () => { + const { http } = HttpLogic.values; + const { navigateToUrl } = KibanaLogic.values; + const { roleMapping } = values; + if (!roleMapping) { + return; + } + const route = `/api/workplace_search/org/role_mappings/${roleMapping.id}`; + if (window.confirm(DELETE_ROLE_MAPPING_MESSAGE)) { + try { + await http.delete(route); + navigateToUrl(ROLE_MAPPINGS_PATH); + } catch (e) { + flashAPIErrors(e); + } + } + }, + handleSaveMapping: async () => { + const { http } = HttpLogic.values; + const { navigateToUrl } = KibanaLogic.values; + const { + attributeName, + attributeValue, + roleType, + roleMapping, + selectedGroups, + includeInAllGroups, + selectedAuthProviders, + } = values; + + const body = JSON.stringify({ + rules: { + [attributeName]: attributeValue, + }, + roleType, + groups: includeInAllGroups ? [] : Array.from(selectedGroups), + allGroups: includeInAllGroups, + authProvider: selectedAuthProviders, + }); + + const request = !roleMapping + ? http.post('/api/workplace_search/org/role_mappings', { body }) + : http.put(`/api/workplace_search/org/role_mappings/${roleMapping.id}`, { body }); + + try { + await request; + navigateToUrl(ROLE_MAPPINGS_PATH); + } catch (e) { + flashAPIErrors(e); + } + }, + resetState: () => { + clearFlashMessages(); + }, + }), +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_router.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_router.test.tsx new file mode 100644 index 0000000000000..e9fc40ba1dbb4 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_router.test.tsx @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { Route, Switch } from 'react-router-dom'; + +import { shallow } from 'enzyme'; + +import { RoleMapping } from './role_mapping'; +import { RoleMappings } from './role_mappings'; +import { RoleMappingsRouter } from './role_mappings_router'; + +describe('RoleMappingsRouter', () => { + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find(Switch)).toHaveLength(1); + expect(wrapper.find(Route)).toHaveLength(3); + expect(wrapper.find(RoleMapping)).toHaveLength(2); + expect(wrapper.find(RoleMappings)).toHaveLength(1); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_router.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_router.tsx new file mode 100644 index 0000000000000..fa5ab12c8afc0 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_router.tsx @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { Route, Switch } from 'react-router-dom'; + +import { SetWorkplaceSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; +import { NAV } from '../../constants'; +import { ROLE_MAPPING_NEW_PATH, ROLE_MAPPING_PATH, ROLE_MAPPINGS_PATH } from '../../routes'; + +import { RoleMapping } from './role_mapping'; +import { RoleMappings } from './role_mappings'; + +export const RoleMappingsRouter: React.FC = () => ( + <> + + + + + + + + + + + + + +); diff --git a/x-pack/plugins/enterprise_search/server/routes/workplace_search/index.ts b/x-pack/plugins/enterprise_search/server/routes/workplace_search/index.ts index cc6226e340653..a21ffac02a48c 100644 --- a/x-pack/plugins/enterprise_search/server/routes/workplace_search/index.ts +++ b/x-pack/plugins/enterprise_search/server/routes/workplace_search/index.ts @@ -9,6 +9,7 @@ import { RouteDependencies } from '../../plugin'; import { registerGroupsRoutes } from './groups'; import { registerOverviewRoute } from './overview'; +import { registerRoleMappingsRoutes } from './role_mappings'; import { registerSecurityRoutes } from './security'; import { registerSettingsRoutes } from './settings'; import { registerSourcesRoutes } from './sources'; @@ -16,6 +17,7 @@ import { registerSourcesRoutes } from './sources'; export const registerWorkplaceSearchRoutes = (dependencies: RouteDependencies) => { registerOverviewRoute(dependencies); registerGroupsRoutes(dependencies); + registerRoleMappingsRoutes(dependencies); registerSourcesRoutes(dependencies); registerSettingsRoutes(dependencies); registerSecurityRoutes(dependencies); diff --git a/x-pack/plugins/enterprise_search/server/routes/workplace_search/role_mappings.test.ts b/x-pack/plugins/enterprise_search/server/routes/workplace_search/role_mappings.test.ts new file mode 100644 index 0000000000000..0dade134767e4 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/routes/workplace_search/role_mappings.test.ts @@ -0,0 +1,154 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { MockRouter, mockRequestHandler, mockDependencies } from '../../__mocks__'; + +import { + registerOrgRoleMappingsRoute, + registerOrgRoleMappingRoute, + registerOrgNewRoleMappingRoute, +} from './role_mappings'; + +describe('role mappings routes', () => { + describe('GET /api/workplace_search/org/role_mappings', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'get', + path: '/api/workplace_search/org/role_mappings', + }); + + registerOrgRoleMappingsRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/role_mappings/collection', + }); + }); + }); + + describe('POST /api/workplace_search/org/role_mappings', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'post', + path: '/api/workplace_search/org/role_mappings', + }); + + registerOrgRoleMappingsRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/role_mappings/collection', + }); + }); + }); + + describe('GET /api/workplace_search/org/role_mappings/{id}', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'get', + path: '/api/workplace_search/org/role_mappings/{id}', + }); + + registerOrgRoleMappingRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/role_mappings/:id', + }); + }); + }); + + describe('PUT /api/workplace_search/org/role_mappings/{id}', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'put', + path: '/api/workplace_search/org/role_mappings/{id}', + }); + + registerOrgRoleMappingRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/role_mappings/:id', + }); + }); + }); + + describe('DELETE /api/workplace_search/org/role_mappings/{id}', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'delete', + path: '/api/workplace_search/org/role_mappings/{id}', + }); + + registerOrgRoleMappingRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/role_mappings/:id', + }); + }); + }); + + describe('GET /api/workplace_search/org/role_mappings/new', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'get', + path: '/api/workplace_search/org/role_mappings/new', + }); + + registerOrgNewRoleMappingRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/role_mappings/new', + }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/server/routes/workplace_search/role_mappings.ts b/x-pack/plugins/enterprise_search/server/routes/workplace_search/role_mappings.ts new file mode 100644 index 0000000000000..8c7792f56fd6c --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/routes/workplace_search/role_mappings.ts @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; + +import { RouteDependencies } from '../../plugin'; + +const roleMappingBaseSchema = { + rules: schema.recordOf(schema.string(), schema.string()), + roleType: schema.string(), + groups: schema.arrayOf(schema.string()), + allGroups: schema.boolean(), + authProvider: schema.arrayOf(schema.string()), +}; + +export function registerOrgRoleMappingsRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/workplace_search/org/role_mappings', + validate: false, + }, + enterpriseSearchRequestHandler.createRequest({ + path: '/ws/org/role_mappings/collection', + }) + ); + + router.post( + { + path: '/api/workplace_search/org/role_mappings', + validate: { + body: schema.object(roleMappingBaseSchema), + }, + }, + enterpriseSearchRequestHandler.createRequest({ + path: '/ws/org/role_mappings/collection', + }) + ); +} + +export function registerOrgRoleMappingRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/workplace_search/org/role_mappings/{id}', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + enterpriseSearchRequestHandler.createRequest({ + path: '/ws/org/role_mappings/:id', + }) + ); + + router.put( + { + path: '/api/workplace_search/org/role_mappings/{id}', + validate: { + body: schema.object({ + ...roleMappingBaseSchema, + id: schema.string(), + }), + params: schema.object({ + id: schema.string(), + }), + }, + }, + enterpriseSearchRequestHandler.createRequest({ + path: '/ws/org/role_mappings/:id', + }) + ); + + router.delete( + { + path: '/api/workplace_search/org/role_mappings/{id}', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + enterpriseSearchRequestHandler.createRequest({ + path: '/ws/org/role_mappings/:id', + }) + ); +} + +export function registerOrgNewRoleMappingRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/workplace_search/org/role_mappings/new', + validate: false, + }, + enterpriseSearchRequestHandler.createRequest({ + path: '/ws/org/role_mappings/new', + }) + ); +} + +export const registerRoleMappingsRoutes = (dependencies: RouteDependencies) => { + registerOrgRoleMappingsRoute(dependencies); + registerOrgRoleMappingRoute(dependencies); + registerOrgNewRoleMappingRoute(dependencies); +}; From b2b16d6aafa8d1675a03a9c9308787f098f7013b Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Tue, 2 Mar 2021 18:23:12 +0100 Subject: [PATCH 09/33] [Discover] Change icon of saved search in open search panel and embeddable selection (#93001) --- .../public/application/components/top_nav/open_search_panel.tsx | 2 +- .../public/application/embeddable/search_embeddable_factory.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/discover/public/application/components/top_nav/open_search_panel.tsx b/src/plugins/discover/public/application/components/top_nav/open_search_panel.tsx index 8c5f44b97f4b3..f6881d1856566 100644 --- a/src/plugins/discover/public/application/components/top_nav/open_search_panel.tsx +++ b/src/plugins/discover/public/application/components/top_nav/open_search_panel.tsx @@ -59,7 +59,7 @@ export function OpenSearchPanel(props: OpenSearchPanelProps) { savedObjectMetaData={[ { type: SEARCH_OBJECT_TYPE, - getIconForSavedObject: () => 'search', + getIconForSavedObject: () => 'discoverApp', name: i18n.translate('discover.savedSearch.savedObjectName', { defaultMessage: 'Saved search', }), diff --git a/src/plugins/discover/public/application/embeddable/search_embeddable_factory.ts b/src/plugins/discover/public/application/embeddable/search_embeddable_factory.ts index 043869f99bb35..77da138d118dd 100644 --- a/src/plugins/discover/public/application/embeddable/search_embeddable_factory.ts +++ b/src/plugins/discover/public/application/embeddable/search_embeddable_factory.ts @@ -36,7 +36,7 @@ export class SearchEmbeddableFactory defaultMessage: 'Saved search', }), type: 'search', - getIconForSavedObject: () => 'search', + getIconForSavedObject: () => 'discoverApp', }; constructor( From 5521fe400fba04eee8176c7b64c71491bf12ea40 Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Tue, 2 Mar 2021 09:30:03 -0800 Subject: [PATCH 10/33] [Bazel] More resilient Workspace Status (#93244) Signed-off-by: Tyler Smalley --- src/dev/bazel_workspace_status.js | 37 ++++++++++++++----------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/dev/bazel_workspace_status.js b/src/dev/bazel_workspace_status.js index fe60f9176d243..3c3ef1574cd8e 100644 --- a/src/dev/bazel_workspace_status.js +++ b/src/dev/bazel_workspace_status.js @@ -43,25 +43,23 @@ // Commit SHA const commitSHACmdResult = await runCmd('git', ['rev-parse', 'HEAD']); - if (commitSHACmdResult.exitCode !== 0) { - process.exit(1); - } - console.log(`COMMIT_SHA ${commitSHACmdResult.stdout}`); + if (commitSHACmdResult.exitCode === 0) { + console.log(`COMMIT_SHA ${commitSHACmdResult.stdout}`); - // Git branch - const gitBranchCmdResult = await runCmd('git', ['rev-parse', '--abbrev-ref', 'HEAD']); - if (gitBranchCmdResult.exitCode !== 0) { - process.exit(1); - } - console.log(`GIT_BRANCH ${gitBranchCmdResult.stdout}`); + // Branch + const gitBranchCmdResult = await runCmd('git', ['rev-parse', '--abbrev-ref', 'HEAD']); + if (gitBranchCmdResult.exitCode === 0) { + console.log(`GIT_BRANCH ${gitBranchCmdResult.stdout}`); + } - // Tree status - const treeStatusCmdResult = await runCmd('git', ['diff-index', '--quiet', 'HEAD', '--']); - const treeStatusVarStr = 'GIT_TREE_STATUS'; - if (treeStatusCmdResult.exitCode === 0) { - console.log(`${treeStatusVarStr} Clean`); - } else { - console.log(`${treeStatusVarStr} Modified`); + // Tree status + const treeStatusCmdResult = await runCmd('git', ['diff-index', '--quiet', 'HEAD', '--']); + const treeStatusVarStr = 'GIT_TREE_STATUS'; + if (treeStatusCmdResult.exitCode === 0) { + console.log(`${treeStatusVarStr} Clean`); + } else { + console.log(`${treeStatusVarStr} Modified`); + } } // Host @@ -72,9 +70,8 @@ return !cpu.model.includes('Intel') || index % 2 === 1; }).length; - if (hostCmdResult.exitCode !== 0) { - process.exit(1); + if (hostCmdResult.exitCode === 0) { + console.log(`HOST ${hostStr}-${coresStr}`); } - console.log(`HOST ${hostStr}-${coresStr}`); } })(); From 84dc217aff4d4b05a29c5c5804fd42277535a1cb Mon Sep 17 00:00:00 2001 From: Clint Andrew Hall Date: Tue, 2 Mar 2021 11:44:18 -0600 Subject: [PATCH 11/33] Convert Canvas docs to MDX for use in Elastic Docs (#91969) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/canvas/PLUGINS.mdx | 239 +++++++++++++++++ x-pack/plugins/canvas/README.md | 240 ------------------ .../{README.md => README.mdx} | 47 +--- 3 files changed, 249 insertions(+), 277 deletions(-) create mode 100644 x-pack/plugins/canvas/PLUGINS.mdx rename x-pack/plugins/canvas/shareable_runtime/{README.md => README.mdx} (88%) diff --git a/x-pack/plugins/canvas/PLUGINS.mdx b/x-pack/plugins/canvas/PLUGINS.mdx new file mode 100644 index 0000000000000..0f93948d663a0 --- /dev/null +++ b/x-pack/plugins/canvas/PLUGINS.mdx @@ -0,0 +1,239 @@ +--- +id: canvasPlugins +slug: /playground/kibana/canvas-plugins +title: Develop Canvas plugins +summary: Introduction to +date: 2021-02-18 +tags: ['kibana', 'canvas', 'plugins'] +related: [] +--- + +To develop your own Canvas plugins, you simply create a Kibana plugin, and register your customizations with Canvas. + +The following is a step-by-step guide to adding your own custom random number Canvas plugin. + +## Generating a Kibana plugin + +```bash +# in the kibana directory +# Rename canvas_example to whatever you want your plugin to be named +node scripts/generate_plugin.js canvas_example +``` + +This will prompt you for some input. Generally, you can answer as follows: + +``` +❯ node scripts/generate_plugin.js canvas_example +? Would you like to create the plugin in a different folder? No +? Provide a short description An awesome Kibana plugin +? What Kibana version are you targeting? master +? Should an app component be generated? No +? Should a server API be generated? No +? Should translation files be generated? No +? Would you like to use a custom eslint file? No +``` + +Once this has completed, go to your plugin directory: + +```bash +cd plugins/canvas_example +``` + +Open that folder in your code editor of choice: `code .` + +### Creating a Canvas element and function +Open your plugin's `kibana.json` file. Make sure that `ui` has a value of true, and that `'canvas'` is included in `requiredPlugins`. It should look something like this. + +```json +{ + "id": "canvasExample", + "version": "7.8.0", + "server": false, + "ui": true, + "requiredPlugins": ["canvas"], + "optionalPlugins": [] +} +``` + +In your plugin folder, create a new folder `public` and an `index.ts` file within it. + +This `index.ts` will need export a Kibana Plugin. You can use this as a starting point for your plugin. + +```typescript +import { Plugin, CoreSetup, CoreStart } from '../../../src/core/public'; +import { CanvasSetup } from '../../../x-pack/plugins/canvas/public'; + +interface CanvasExampleSetupPlugins { + canvas: CanvasSetup; +} + +interface CanvasExampleStartPlugins {} + +class CanvasExamplePlugin + implements Plugin { + setup(core: CoreSetup, plugins: CanvasExampleSetupPlugins) {} + + start(core: CoreStart) {} +} + +export const plugin = () => new CanvasExamplePlugin(); +``` + + +Now that the Kibana plugin boilerplate is out of the way, you can start adding functionality to Canvas. + +Let's start by adding a new function. + +In your `index.ts` add a new function definition: + +```typescript +const canvasFunctions = [ + () => ({ + name: 'random', + help: 'Make a random number between 1 and 100', + args: {}, + fn() { + return Math.floor(Math.random() * 100) + 1; + } + }), +]; +``` + +Then, in the `setup` method of your plugin, you can add this new function definition to Canvas: + +```typescript +setup(core: CoreSetup, plugins: CanvasExampleSetupPlugins) { + plugins.canvas.addFunctions(canvasFunctions); +} +``` + +Now, let's add a new Element type. In your `index.ts` add a new element definition: + +```typescript +const elements = [ + () => ({ + name: 'randomNumber', + displayName: 'Random Number', + help: 'A random number between 1 and 100', + image: 'https://images.contentstack.io/v3/assets/bltefdd0b53724fa2ce/bltb59c89a07c05b937/5c583a6602ac90e80ba0ab8f/icon-white-circle-elastic-stack.svg', + expression: 'random | metric "Random Number"', + }), +]; +``` + +And then, in the `setup` method of the plugin, add this new element definition to Canvas, just like you did with the function: + +```typescript +setup(core: CoreSetup, plugins: CanvasExampleSetupPlugins) { + plugins.canvas.addFunctions(canvasFunctions); + plugins.canvas.addElements(elements); +} +``` + +Now, your 'Random Number' element will show up in the list of other Canvas elements. + +### Trying out your new plugin + +In the terminal, in your plugin's directory, run: + +```bash +# In plugins/canvas_example +yarn start +``` + +- Pull up Kibana in your browser: `http://localhost:5601` +- Go to canvas, and click: "Create workpad" +- Click: "Add element" +- Click: "Other" +- Click: "Random Number" + +### Adding a server-side function + +> Server side functions may be deprecated in a later version of Kibana + +Now, let's add a function which runs on the server. + +In your plugin's `kibana.json` file, set `server` to true, and add `"expressions"` as a requiredPlugin. + +```typescript +{ + "id": "canvasExample", + "version": "8.0.0", + "server": false, + "ui": true, + "requiredPlugins": ["canvas", "expressions"], + "optionalPlugins": [] +} +``` + +Now, much like we made the client plugin, we'll make a server plugin. + +Start by making the `server` directory and an `index.ts` file with a shell for your server plugin: + +```typescript +import { Plugin, CoreSetup, CoreStart } from '../../../src/core/server'; +import { ExpressionsServerSetup } from '../../../src/plugins/expressions/server'; + +interface CanvasExamplePluginsSetup { + expressions: ExpressionsServerSetup; +} + +class CanvasExamplePlugin implements Plugin { + setup(core: CoreSetup, plugins: CanvasExamplePluginsSetup) {} + + start(core: CoreStart) {} +} + +export const plugin = () => new CanvasExamplePlugin(); +``` + +Now, we'll create a simple function definition that we will register on the server: + +```typescript +const serverFunctions = [ + () => ({ + name: 'serverTime', + help: 'Get the server time in milliseconds', + args: {}, + fn() { + return Date.now(); + }, + }), +]; +``` + +And then in our setup method, register it with the Expressions plugin: + +```typescript +setup(core: CoreSetup, plugins: CanvasExamplePluginsSetup) { + serverFunctions.forEach((f) => plugins.expressions.registerFunction(f)); +} +``` + +Now, let's try out our new server function. + +- Refresh your browser. +- In the same Canvas workpad: + - Add another Random Number element as before + - Click that element to select it + - Click "Expression editor" + - Modify the expression to look like this: `serverTime | metric "Server Time in ms"` + - Click "Run" + +You should now see one random number and one "Server Time in ms" value. + +> More information about building Kibana Plugins can be found in [src/core](https://github.com/elastic/kibana/blob/master/src/core/README.md) + +### My Canvas Plugin stopped working + +If your Kibana Server is crashing on startup with a message like + +> **FATAL** Error: Unmet requirement "canvas" for plugin "your_plugin_name" + +or + +> **FATAL** Error: Unmet requirement "interpreter" for plugin "your_plugin_name" + +then your plugin was likely created to work on a previous version of Kibana. Starting with version 7.8, the plugin system was redesigned and caused breaking changes to these earlier plugins. + +The good news is that all of your existing Canvas extension code can be reused, it just needs to be in an updated Kibana plugin. Follow the [instructions](#generating-a-kibana-plugin) for creating a new Canvas Kibana plugin, and then add in your existing functions and elements. diff --git a/x-pack/plugins/canvas/README.md b/x-pack/plugins/canvas/README.md index f77585b5b062c..754a4dc29d007 100644 --- a/x-pack/plugins/canvas/README.md +++ b/x-pack/plugins/canvas/README.md @@ -6,246 +6,6 @@ Canvas is included with X-Pack and requires a Basic license or better to use. -## Developing in Canvas - -To develop your own Canvas plugins, you simply create a Kibana plugin, and register your customizations with Canvas. - -The following is a step-by-step guide to adding your own custom random number Canvas plugin. - -### Generating a Kibana plugin - -```bash -# in the kibana directory -# Rename canvas_example to whatever you want your plugin to be named -node scripts/generate_plugin.js canvas_example -``` - -This will prompt you for some input. Generally, you can answer as follows: - -``` -❯ node scripts/generate_plugin.js canvas_example -? Would you like to create the plugin in a different folder? No -? Provide a short description An awesome Kibana plugin -? What Kibana version are you targeting? master -? Should an app component be generated? No -? Should a server API be generated? No -? Should translation files be generated? No -? Would you like to use a custom eslint file? No -``` - -Once this has completed, go to your plugin directory: - -```bash -cd plugins/canvas_example -``` - -Open that folder in your code editor of choice: `code .` - -#### Creating a Canvas element and function -Open your plugin's `kibana.json` file. Make sure that `ui` has a value of true, and that `'canvas'` is included in `requiredPlugins`. It should look something like this. - -```json -{ - "id": "canvasExample", - "version": "7.8.0", - "server": false, - "ui": true, - "requiredPlugins": ["canvas"], - "optionalPlugins": [] -} -``` - -In your plugin folder, create a new folder `public` and an `index.ts` file within it. - -This `index.ts` will need export a Kibana Plugin. You can use this as a starting point for your plugin. - -```typescript -import { Plugin, CoreSetup, CoreStart } from '../../../src/core/public'; -import { CanvasSetup } from '../../../x-pack/plugins/canvas/public'; - -interface CanvasExampleSetupPlugins { - canvas: CanvasSetup; -} - -interface CanvasExampleStartPlugins {} - -class CanvasExamplePlugin - implements Plugin { - setup(core: CoreSetup, plugins: CanvasExampleSetupPlugins) {} - - start(core: CoreStart) {} -} - -export const plugin = () => new CanvasExamplePlugin(); -``` - - -Now that the Kibana plugin boilerplate is out of the way, you can start adding functionality to Canvas. - -Let's start by adding a new function. - -In your `index.ts` add a new function definition: - -```typescript -const canvasFunctions = [ - () => ({ - name: 'random', - help: 'Make a random number between 1 and 100', - args: {}, - fn() { - return Math.floor(Math.random() * 100) + 1; - } - }), -]; -``` - -Then, in the `setup` method of your plugin, you can add this new function definition to Canvas: - -```typescript -setup(core: CoreSetup, plugins: CanvasExampleSetupPlugins) { - plugins.canvas.addFunctions(canvasFunctions); -} -``` - -Now, let's add a new Element type. In your `index.ts` add a new element definition: - -```typescript -const elements = [ - () => ({ - name: 'randomNumber', - displayName: 'Random Number', - help: 'A random number between 1 and 100', - image: 'https://images.contentstack.io/v3/assets/bltefdd0b53724fa2ce/bltb59c89a07c05b937/5c583a6602ac90e80ba0ab8f/icon-white-circle-elastic-stack.svg', - expression: 'random | metric "Random Number"', - }), -]; -``` - -And then, in the `setup` method of the plugin, add this new element definition to Canvas, just like you did with the function: - -```typescript -setup(core: CoreSetup, plugins: CanvasExampleSetupPlugins) { - plugins.canvas.addFunctions(canvasFunctions); - plugins.canvas.addElements(elements); -} -``` - -Now, your 'Random Number' element will show up in the list of other Canvas elements. - -#### Trying out your new plugin - -In the terminal, in your plugin's directory, run: - -```bash -# In plugins/canvas_example -yarn start -``` - -- Pull up Kibana in your browser: `http://localhost:5601` -- Go to canvas, and click: "Create workpad" -- Click: "Add element" -- Click: "Other" -- Click: "Random Number" - -#### Adding a server-side function - -> Server side functions may be deprecated in a later version of Kibana - -Now, let's add a function which runs on the server. - -In your plugin's `kibana.json` file, set `server` to true, and add `"expressions"` as a requiredPlugin. - -```typescript -{ - "id": "canvasExample", - "version": "8.0.0", - "server": false, - "ui": true, - "requiredPlugins": ["canvas", "expressions"], - "optionalPlugins": [] -} -``` - -Now, much like we made the client plugin, we'll make a server plugin. - -Start by making the `server` directory and an `index.ts` file with a shell for your server plugin: - -```typescript -import { Plugin, CoreSetup, CoreStart } from '../../../src/core/server'; -import { ExpressionsServerSetup } from '../../../src/plugins/expressions/server'; - -interface CanvasExamplePluginsSetup { - expressions: ExpressionsServerSetup; -} - -class CanvasExamplePlugin implements Plugin { - setup(core: CoreSetup, plugins: CanvasExamplePluginsSetup) {} - - start(core: CoreStart) {} -} - -export const plugin = () => new CanvasExamplePlugin(); -``` - -Now, we'll create a simple function definition that we will register on the server: - -```typescript -const serverFunctions = [ - () => ({ - name: 'serverTime', - help: 'Get the server time in milliseconds', - args: {}, - fn() { - return Date.now(); - }, - }), -]; -``` - -And then in our setup method, register it with the Expressions plugin: - -```typescript -setup(core: CoreSetup, plugins: CanvasExamplePluginsSetup) { - serverFunctions.forEach((f) => plugins.expressions.registerFunction(f)); -} -``` - -Now, let's try out our new server function. - -- Refresh your browser. -- In the same Canvas workpad: - - Add another Random Number element as before - - Click that element to select it - - Click "Expression editor" - - Modify the expression to look like this: `serverTime | metric "Server Time in ms"` - - Click "Run" - -You should now see one random number and one "Server Time in ms" value. - -> More information about building Kibana Plugins can be found in [src/core](https://github.com/elastic/kibana/blob/master/src/core/README.md) - -#### My Canvas Plugin stopped working - -If your Kibana Server is crashing on startup with a message like - -> **FATAL** Error: Unmet requirement "canvas" for plugin "your_plugin_name" - -or - -> **FATAL** Error: Unmet requirement "interpreter" for plugin "your_plugin_name" - -then your plugin was likely created to work on a previous version of Kibana. Starting with version 7.8, the plugin system was redesigned and caused breaking changes to these earlier plugins. - -The good news is that all of your existing Canvas extension code can be reused, it just needs to be in an updated Kibana plugin. Follow the [instructions](#generating-a-kibana-plugin) for creating a new Canvas Kibana plugin, and then add in your existing functions and elements. - -## Scripts - -There are several scripts available once you are in that path as well. - -- `node scripts/lint` - local linter setup, can also be used with the `--fix` flag for automatic fixes. -- `node scripts/test` - local test runner, does not require a real Kibana instance. Runs all the same unit tests the normal runner does, just limited to Canvas, and *waaaaaay* faster (currently 12 seconds or less). -- `node scripts/test_dev` - Same as above, but watches for changes and only runs tests for the given scope (browser, server, or common). - ## Feature Questions **Why are there no tooltips** diff --git a/x-pack/plugins/canvas/shareable_runtime/README.md b/x-pack/plugins/canvas/shareable_runtime/README.mdx similarity index 88% rename from x-pack/plugins/canvas/shareable_runtime/README.md rename to x-pack/plugins/canvas/shareable_runtime/README.mdx index 3839e7c4ecb3f..8f1c9e06ca788 100644 --- a/x-pack/plugins/canvas/shareable_runtime/README.md +++ b/x-pack/plugins/canvas/shareable_runtime/README.mdx @@ -1,35 +1,12 @@ -# Canvas Shareable Workpads - -- [Introduction](#introduction) -- [Quick Start](#quick-start) -- [Using the Runtime](#using-the-runtime) - - [Assumptions](#assumptions) - - [Restrictions](#restrictions) - - [JS](#js) - - [HTML](#html) - - [Options](#options) -- [Testing](#testing) - - [Download a ZIP from Canvas](#download-a-zip-from-canvas) - - [Test the Runtime Directly from Webpack](#test-the-runtime-directly-from-webpack) - - [Run the Canvas Storybook](#run-the-canvas-storybook) - - [Run the Jest Tests](#run-the-jest-tests) - - [Gathering Test Coverage](#gathering-test-coverage) -- [Building](#building) - - [Build Options](#build-options) -- [Development](#development) - - [Prerequisite](#prerequisite) - - [Webpack Dev Server](#webpack-dev-server) - - [Gathering Statistics](#gathering-statistics) -- [Architecture](#architecture) - - [The Build](#the-build) - - [Supported Expressions](#supported-expressions) - - [Expression Interpreter](#expression-interpreter) - - [Build Size](#build-size) - - [The App](#the-app) - - [App State](#app-state) - - [CSS](#css) - -## Introduction +--- +id: canvasShareableWorkpads +slug: /playground/kibana/canvas-shareable-workpads +title: Share a Canvas Workpad on a Website +summary: How to share a static snapshot of a workpad on an external website. +date: 2021-02-18 +tags: ['kibana', 'canvas', 'share'] +related: [] +--- The Canvas Shareable Runtime is designed to render Shareable Canvas Workpads outside of Kibana in a different website or application. It uses the intermediate, "transient" state of a workpad, which is a JSON-blob state after element expressions are initially evaluated against their data sources, but before the elements are rendered to the screen. This "transient" state, therefore, has no dependency or access to ES/Kibana data, making it lightweight and portable. @@ -228,11 +205,7 @@ The `index.html` file contains a call to the `CanvasShareable` runtime. Currentl ``` -There are three workpads available, in `test/workpads`: - -- `hello.json` - A simple 'Hello, Canvas' workpad. -- `austin.json` - A workpad from an Elastic{ON} talk in Austin, TX. -- `test.json` - A couple of pages with customized CSS animations and charts. +There are three test workpads available, in `test/workpads`. ### Gathering Statistics From 3dd32973715ffad09478c62f6d7b67690b37f40f Mon Sep 17 00:00:00 2001 From: ymao1 Date: Tue, 2 Mar 2021 13:09:53 -0500 Subject: [PATCH 12/33] [Actions][Docs] Moving subaction and subaction params back to README (#92878) * Moving subaction and subaction params back to README * Apply suggestions from code review Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> * PR fixes Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> --- docs/user/alerting/action-types/jira.asciidoc | 45 +---- .../alerting/action-types/resilient.asciidoc | 29 +-- .../alerting/action-types/servicenow.asciidoc | 33 +-- x-pack/plugins/actions/README.md | 190 +++++++++++++++--- 4 files changed, 175 insertions(+), 122 deletions(-) diff --git a/docs/user/alerting/action-types/jira.asciidoc b/docs/user/alerting/action-types/jira.asciidoc index 0740cf7838b15..d37f565c1739b 100644 --- a/docs/user/alerting/action-types/jira.asciidoc +++ b/docs/user/alerting/action-types/jira.asciidoc @@ -65,44 +65,13 @@ API token (or password):: Jira API authentication token (or password) for HTTP Jira actions have the following configuration properties: -Subaction:: The subaction to perform: `pushToService`, `getIncident`, `issueTypes`, `fieldsByIssueType`, `issues`, `issue`, or `getFields`. -Subaction params:: The parameters of the subaction. - -==== `pushToService` subaction configuration - -Incident:: A Jira incident has the following properties: -* `summary` - The title of the issue. -* `description` - A description of the issue. -* `externalId` - The ID of the issue in Jira. If present, the issue is updated. Otherwise, a new issue is created. -* `issueType` - The ID of the issue type in Jira. -* `priority` - The priority level in Jira. Example: `Medium`. -* `labels` - An array of labels. Labels cannot contain spaces. -* `parent` - The parent issue ID or key. Only for subtask issue types. -Comments:: A comment in the form of `{ commentId: string, version: string, comment: string }`. - -==== `getIncident` subaction configuration - -External ID:: The ID of the issue in Jira. - -==== `issueTypes` subaction configuration - -The `issueTypes` subaction has no parameters. Provide an empty object `{}`. - -==== `fieldsByIssueType` subaction configuration - -ID:: The ID of the issue in Jira. - -==== `issues` subaction configuration - -Title:: The title to search for. - -==== `issue` subaction configuration - -ID:: The ID of the issue in Jira. - -==== `getFields` subaction configuration - -The `getFields` subaction has no parameters. Provide an empty object `{}`. +Issue type:: The type of the issue. +Priority:: The priority of the incident. +Labels:: The labels for the incident. +Title:: A title for the issue, used for searching the contents of the knowledge base. +Description:: The details about the incident. +Parent:: The ID or key of the parent issue. Only for `Subtask` issue types. +Additional comments:: Additional information for the client, such as how to troubleshoot the issue. [[configuring-jira]] ==== Configuring and testing Jira diff --git a/docs/user/alerting/action-types/resilient.asciidoc b/docs/user/alerting/action-types/resilient.asciidoc index dfa95e2deec00..feca42a542a2f 100644 --- a/docs/user/alerting/action-types/resilient.asciidoc +++ b/docs/user/alerting/action-types/resilient.asciidoc @@ -65,30 +65,11 @@ API key secret:: The authentication key secret for HTTP Basic authentication. IBM Resilient actions have the following configuration properties: -Subaction:: The subaction to perform: `pushToService`, `getFields`, `incidentTypes`, or `severity`. -Subaction params:: The parameters of the subaction. - -==== `pushToService` subaction configuration - -Incident:: The IBM resilient incident has the following properties: -* `name` - A name for the issue, used for searching the contents of the knowledge base. -* `description` - The details about the incident. -* `externalId` - The ID of the incident in IBM Resilient. If present, the incident is updated. Otherwise, a new incident is created. -* `incidentTypes` - An array with the IDs of IBM Resilient incident types. -* `severityCode` - The IBM Resilient ID of the severity code. -Comments:: A comment in the form of `{ commentId: string, version: string, comment: string }`. - -===== `getFields` subaction configuration - -The `getFields` subaction has not parameters. Provide an empty object `{}`. - -===== `incidentTypes` subaction configuration - -The `incidentTypes` subaction has no parameters. Provide an empty object `{}`. - -===== `severity` subaction configuration - -The `severity` subaction has no parameters. Provide an empty object `{}`. +Incident types:: The type of the incident. +Severity code:: The severity of the incident. +Name:: A name for the issue, used for searching the contents of the knowledge base. +Description:: The details about the incident. +Additional comments:: Additional information for the client, such as how to troubleshoot the issue. [[configuring-resilient]] ==== Configuring and testing IBM Resilient diff --git a/docs/user/alerting/action-types/servicenow.asciidoc b/docs/user/alerting/action-types/servicenow.asciidoc index d1ee1b9357737..4a11a2e28712a 100644 --- a/docs/user/alerting/action-types/servicenow.asciidoc +++ b/docs/user/alerting/action-types/servicenow.asciidoc @@ -60,33 +60,12 @@ Password:: Password for HTTP Basic authentication. ServiceNow actions have the following configuration properties: -Subaction:: The subaction to perform: `pushToService`, `getFields`, `getIncident`, or `getChoices`. -Subaction params:: The parameters of the subaction. - -==== `pushToService` subaction configuration - -Incident:: The ServiceNow incident has the following properties: -* `short_description` - A short description for the incident, used for searching the contents of the knowledge base. -* `description` - The details about the incident. -* `externalId` - The ID of the incident in ServiceNow. If present, the incident is updated. Otherwise, a new incident is created. -* `severity` - The severity of the incident. -* `urgency` - The extent to which the incident resolution can delay. -* `impact` - The effect an incident has on business. Can be measured by the number of affected users or by how critical it is to the business in question. -* `category` - The name of the category in ServiceNow. -* `subcategory` - The name of the subcategory in ServiceNow. -Comments:: A comment in the form of `{ commentId: string, version: string, comment: string }`. - -===== `getFields` subaction configuration - -The `getFields` subaction has no parameters. Provide an empty object `{}`. - -===== `getIncident` subaction configuration - -External ID:: The ID of the incident in ServiceNow. - -===== `getChoices` subaction configuration - -Fields:: An array of fields. Example: `[priority, category, impact]`. +Urgency:: The extent to which the incident resolution can delay. +Severity:: The severity of the incident. +Impact:: The effect an incident has on business. Can be measured by the number of affected users or by how critical it is to the business in question. +Short description:: A short description for the incident, used for searching the contents of the knowledge base. +Description:: The details about the incident. +Additional comments:: Additional information for the client, such as how to troubleshoot the issue. [[configuring-servicenow]] ==== Configuring and testing ServiceNow diff --git a/x-pack/plugins/actions/README.md b/x-pack/plugins/actions/README.md index 78094f4c0eb0b..f1be1ec12b79c 100644 --- a/x-pack/plugins/actions/README.md +++ b/x-pack/plugins/actions/README.md @@ -33,42 +33,14 @@ Table of Contents - [actionsClient.execute(options)](#actionsclientexecuteoptions) - [Example](#example-2) - [Built-in Action Types](#built-in-action-types) - - [Server log](#server-log) - - [`config`](#config) - - [`secrets`](#secrets) - - [`params`](#params) - - [Email](#email) - - [`config`](#config-1) - - [`secrets`](#secrets-1) - - [`params`](#params-1) - - [Slack](#slack) - - [`config`](#config-2) - - [`secrets`](#secrets-2) - - [`params`](#params-2) - - [Index](#index) - - [`config`](#config-3) - - [`secrets`](#secrets-3) - - [`params`](#params-3) - - [Webhook](#webhook) - - [`config`](#config-4) - - [`secrets`](#secrets-4) - - [`params`](#params-4) - - [PagerDuty](#pagerduty) - - [`config`](#config-5) - - [`secrets`](#secrets-5) - - [`params`](#params-5) - [ServiceNow](#servicenow) - - [`config`](#config-6) - - [`secrets`](#secrets-6) - - [`params`](#params-6) + - [`params`](#params) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice) - [`subActionParams (getFields)`](#subactionparams-getfields) - [`subActionParams (getIncident)`](#subactionparams-getincident) - [`subActionParams (getChoices)`](#subactionparams-getchoices) - [Jira](#jira) - - [`config`](#config-7) - - [`secrets`](#secrets-7) - - [`params`](#params-7) + - [`params`](#params-1) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-1) - [`subActionParams (getIncident)`](#subactionparams-getincident-1) - [`subActionParams (issueTypes)`](#subactionparams-issuetypes) @@ -77,9 +49,7 @@ Table of Contents - [`subActionParams (issue)`](#subactionparams-issue) - [`subActionParams (getFields)`](#subactionparams-getfields-1) - [IBM Resilient](#ibm-resilient) - - [`config`](#config-8) - - [`secrets`](#secrets-8) - - [`params`](#params-8) + - [`params`](#params-2) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-2) - [`subActionParams (getFields)`](#subactionparams-getfields-2) - [`subActionParams (incidentTypes)`](#subactionparams-incidenttypes) @@ -272,6 +242,160 @@ const result = await actionsClient.execute({ Kibana ships with a set of built-in action types. See [Actions and connector types Documentation](https://www.elastic.co/guide/en/kibana/master/action-types.html). +In addition to the documented configurations, several built in action type offer additional `params` configurations. + +## ServiceNow + +The [ServiceNow user documentation `params`](https://www.elastic.co/guide/en/kibana/master/servicenow-action-type.html) lists configuration properties for the `pushToService` subaction. In addition, several other subaction types are available. +### `params` + +| Property | Description | Type | +| --------------- | -------------------------------------------------------------------------------------------------- | ------ | +| subAction | The subaction to perform. It can be `pushToService`, `getFields`, `getIncident`, and `getChoices`. | string | +| subActionParams | The parameters of the subaction. | object | + +#### `subActionParams (pushToService)` + +| Property | Description | Type | +| -------- | ------------------------------------------------------------------------------------------------------------- | --------------------- | +| incident | The ServiceNow incident. | object | +| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }`. | object[] _(optional)_ | + +The following table describes the properties of the `incident` object. + +| Property | Description | Type | +| ----------------- | ------------------------------------------------------------------------------------------------------------------------- | ------------------- | +| short_description | The title of the incident. | string | +| description | The description of the incident. | string _(optional)_ | +| externalId | The ID of the incident in ServiceNow. If present, the incident is updated. Otherwise, a new incident is created. | string _(optional)_ | +| severity | The severity in ServiceNow. | string _(optional)_ | +| urgency | The urgency in ServiceNow. | string _(optional)_ | +| impact | The impact in ServiceNow. | string _(optional)_ | +| category | The category in ServiceNow. | string _(optional)_ | +| subcategory | The subcategory in ServiceNow. | string _(optional)_ | + +#### `subActionParams (getFields)` + +No parameters for the `getFields` subaction. Provide an empty object `{}`. + +#### `subActionParams (getIncident)` + +| Property | Description | Type | +| ---------- | ------------------------------------- | ------ | +| externalId | The ID of the incident in ServiceNow. | string | + + +#### `subActionParams (getChoices)` + +| Property | Description | Type | +| -------- | ------------------------------------------------------------ | -------- | +| fields | An array of fields. Example: `[priority, category, impact]`. | string[] | + +--- + +## Jira + +The [Jira user documentation `params`](https://www.elastic.co/guide/en/kibana/master/jira-action-type.html) lists configuration properties for the `pushToService` subaction. In addition, several other subaction types are available. +### `params` + +| Property | Description | Type | +| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------ | +| subAction | The subaction to perform. It can be `pushToService`, `getIncident`, `issueTypes`, `fieldsByIssueType`, `issues`, `issue`, and `getFields`. | string | +| subActionParams | The parameters of the subaction. | object | + +#### `subActionParams (pushToService)` + +| Property | Description | Type | +| -------- | ------------------------------------------------------------------------------------------------------------- | --------------------- | +| incident | The Jira incident. | object | +| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }`. | object[] _(optional)_ | + +The following table describes the properties of the `incident` object. + +| Property | Description | Type | +| ----------- | ---------------------------------------------------------------------------------------------------------------- | --------------------- | +| summary | The title of the issue. | string | +| description | The description of the issue. | string _(optional)_ | +| externalId | The ID of the issue in Jira. If present, the incident is updated. Otherwise, a new incident is created. | string _(optional)_ | +| issueType | The ID of the issue type in Jira. | string _(optional)_ | +| priority | The name of the priority in Jira. Example: `Medium`. | string _(optional)_ | +| labels | An array of labels. Labels cannot contain spaces. | string[] _(optional)_ | +| parent | The ID or key of the parent issue. Only for `Sub-task` issue types. | string _(optional)_ | + +#### `subActionParams (getIncident)` + +| Property | Description | Type | +| ---------- | --------------------------- | ------ | +| externalId | The ID of the issue in Jira. | string | + +#### `subActionParams (issueTypes)` + +No parameters for the `issueTypes` subaction. Provide an empty object `{}`. + +#### `subActionParams (fieldsByIssueType)` + +| Property | Description | Type | +| -------- | -------------------------------- | ------ | +| id | The ID of the issue type in Jira. | string | + +#### `subActionParams (issues)` + +| Property | Description | Type | +| -------- | ----------------------- | ------ | +| title | The title to search for. | string | + +#### `subActionParams (issue)` + +| Property | Description | Type | +| -------- | --------------------------- | ------ | +| id | The ID of the issue in Jira. | string | + +#### `subActionParams (getFields)` + +No parameters for the `getFields` subaction. Provide an empty object `{}`. + +--- +## IBM Resilient + +The [IBM Resilient user documentation `params`](https://www.elastic.co/guide/en/kibana/master/resilient-action-type.html) lists configuration properties for the `pushToService` subaction. In addition, several other subaction types are available. + +### `params` + +| Property | Description | Type | +| --------------- | -------------------------------------------------------------------------------------------------- | ------ | +| subAction | The subaction to perform. It can be `pushToService`, `getFields`, `incidentTypes`, and `severity. | string | +| subActionParams | The parameters of the subaction. | object | + +#### `subActionParams (pushToService)` + +| Property | Description | Type | +| -------- | ------------------------------------------------------------------------------------------------------------- | --------------------- | +| incident | The IBM Resilient incident. | object | +| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }`. | object[] _(optional)_ | + +The following table describes the properties of the `incident` object. + +| Property | Description | Type | +| ------------- | ---------------------------------------------------------------------------------------------------------------------------- | --------------------- | +| name | The title of the incident. | string _(optional)_ | +| description | The description of the incident. | string _(optional)_ | +| externalId | The ID of the incident in IBM Resilient. If present, the incident is updated. Otherwise, a new incident is created. | string _(optional)_ | +| incidentTypes | An array with the IDs of IBM Resilient incident types. | number[] _(optional)_ | +| severityCode | IBM Resilient ID of the severity code. | number _(optional)_ | + +#### `subActionParams (getFields)` + +No parameters for the `getFields` subaction. Provide an empty object `{}`. + +#### `subActionParams (incidentTypes)` + +No parameters for the `incidentTypes` subaction. Provide an empty object `{}`. + +#### `subActionParams (severity)` + +No parameters for the `severity` subaction. Provide an empty object `{}`. + +--- # Command Line Utility The [`kbn-action`](https://github.com/pmuellr/kbn-action) tool can be used to send HTTP requests to the Actions plugin. For instance, to create a Slack action from the `.slack` Action Type, use the following command: From 81348b86934097c10133373cd1d7e08f8ff77cb5 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Tue, 2 Mar 2021 11:21:39 -0700 Subject: [PATCH 13/33] [core.logging] Fix calculating payload bytes for arrays and zlib streams. (#92100) --- .../src/utils/get_payload_size.test.ts | 106 +++++++++---- .../src/utils/get_payload_size.ts | 10 +- .../http/logging/get_payload_size.test.ts | 142 +++++++++++++----- .../server/http/logging/get_payload_size.ts | 35 +++-- 4 files changed, 208 insertions(+), 85 deletions(-) diff --git a/packages/kbn-legacy-logging/src/utils/get_payload_size.test.ts b/packages/kbn-legacy-logging/src/utils/get_payload_size.test.ts index 3bb97e57ca0a3..01d2cf29758db 100644 --- a/packages/kbn-legacy-logging/src/utils/get_payload_size.test.ts +++ b/packages/kbn-legacy-logging/src/utils/get_payload_size.test.ts @@ -6,9 +6,10 @@ * Side Public License, v 1. */ -import { createGunzip } from 'zlib'; import mockFs from 'mock-fs'; import { createReadStream } from 'fs'; +import { PassThrough } from 'stream'; +import { createGzip, createGunzip } from 'zlib'; import { getResponsePayloadBytes } from './get_payload_size'; @@ -27,38 +28,74 @@ describe('getPayloadSize', () => { }); }); - describe('handles fs streams', () => { + describe('handles streams', () => { afterEach(() => mockFs.restore()); - test('with ascii characters', async () => { - mockFs({ 'test.txt': 'heya' }); - const readStream = createReadStream('test.txt'); - - let data = ''; - for await (const chunk of readStream) { - data += chunk; - } - - const result = getResponsePayloadBytes(readStream); - expect(result).toBe(Buffer.byteLength(data)); - }); - - test('with special characters', async () => { - mockFs({ 'test.txt': '¡hola!' }); - const readStream = createReadStream('test.txt'); - - let data = ''; - for await (const chunk of readStream) { - data += chunk; - } - - const result = getResponsePayloadBytes(readStream); - expect(result).toBe(Buffer.byteLength(data)); + test('ignores streams that are not fs or zlib streams', async () => { + const result = getResponsePayloadBytes(new PassThrough()); + expect(result).toBe(undefined); }); - test('ignores streams that are not instances of ReadStream', async () => { - const result = getResponsePayloadBytes(createGunzip()); - expect(result).toBe(undefined); + describe('fs streams', () => { + test('with ascii characters', async () => { + mockFs({ 'test.txt': 'heya' }); + const readStream = createReadStream('test.txt'); + + let data = ''; + for await (const chunk of readStream) { + data += chunk; + } + + const result = getResponsePayloadBytes(readStream); + expect(result).toBe(Buffer.byteLength(data)); + }); + + test('with special characters', async () => { + mockFs({ 'test.txt': '¡hola!' }); + const readStream = createReadStream('test.txt'); + + let data = ''; + for await (const chunk of readStream) { + data += chunk; + } + + const result = getResponsePayloadBytes(readStream); + expect(result).toBe(Buffer.byteLength(data)); + }); + + describe('zlib streams', () => { + test('with ascii characters', async () => { + mockFs({ 'test.txt': 'heya' }); + const readStream = createReadStream('test.txt'); + const source = readStream.pipe(createGzip()).pipe(createGunzip()); + + let data = ''; + for await (const chunk of source) { + data += chunk; + } + + const result = getResponsePayloadBytes(source); + + expect(data).toBe('heya'); + expect(result).toBe(source.bytesWritten); + }); + + test('with special characters', async () => { + mockFs({ 'test.txt': '¡hola!' }); + const readStream = createReadStream('test.txt'); + const source = readStream.pipe(createGzip()).pipe(createGunzip()); + + let data = ''; + for await (const chunk of source) { + data += chunk; + } + + const result = getResponsePayloadBytes(source); + + expect(data).toBe('¡hola!'); + expect(result).toBe(source.bytesWritten); + }); + }); }); }); @@ -79,8 +116,17 @@ describe('getPayloadSize', () => { expect(result).toBe(JSON.stringify(payload).length); }); + test('when source is array object', () => { + const payload = [{ message: 'hey' }, { message: 'ya' }]; + const result = getResponsePayloadBytes(payload); + expect(result).toBe(JSON.stringify(payload).length); + }); + test('returns undefined when source is not plain object', () => { - const result = getResponsePayloadBytes([1, 2, 3]); + class TestClass { + constructor() {} + } + const result = getResponsePayloadBytes(new TestClass()); expect(result).toBe(undefined); }); }); diff --git a/packages/kbn-legacy-logging/src/utils/get_payload_size.ts b/packages/kbn-legacy-logging/src/utils/get_payload_size.ts index c7aeb0e8cac2b..acc517c74c2d4 100644 --- a/packages/kbn-legacy-logging/src/utils/get_payload_size.ts +++ b/packages/kbn-legacy-logging/src/utils/get_payload_size.ts @@ -8,11 +8,15 @@ import { isPlainObject } from 'lodash'; import { ReadStream } from 'fs'; +import { Zlib } from 'zlib'; import type { ResponseObject } from '@hapi/hapi'; const isBuffer = (obj: unknown): obj is Buffer => Buffer.isBuffer(obj); const isFsReadStream = (obj: unknown): obj is ReadStream => typeof obj === 'object' && obj !== null && 'bytesRead' in obj && obj instanceof ReadStream; +const isZlibStream = (obj: unknown): obj is Zlib => { + return typeof obj === 'object' && obj !== null && 'bytesWritten' in obj; +}; const isString = (obj: unknown): obj is string => typeof obj === 'string'; /** @@ -51,11 +55,15 @@ export function getResponsePayloadBytes( return payload.bytesRead; } + if (isZlibStream(payload)) { + return payload.bytesWritten; + } + if (isString(payload)) { return Buffer.byteLength(payload); } - if (isPlainObject(payload)) { + if (isPlainObject(payload) || Array.isArray(payload)) { return Buffer.byteLength(JSON.stringify(payload)); } diff --git a/src/core/server/http/logging/get_payload_size.test.ts b/src/core/server/http/logging/get_payload_size.test.ts index dba5c7be30f3b..30cb547dd98b7 100644 --- a/src/core/server/http/logging/get_payload_size.test.ts +++ b/src/core/server/http/logging/get_payload_size.test.ts @@ -6,12 +6,13 @@ * Side Public License, v 1. */ -import { createGunzip } from 'zlib'; import type { Request } from '@hapi/hapi'; import Boom from '@hapi/boom'; import mockFs from 'mock-fs'; import { createReadStream } from 'fs'; +import { PassThrough } from 'stream'; +import { createGunzip, createGzip } from 'zlib'; import { loggerMock, MockedLogger } from '../../logging/logger.mock'; @@ -55,59 +56,107 @@ describe('getPayloadSize', () => { }); }); - describe('handles fs streams', () => { + describe('handles streams', () => { afterEach(() => mockFs.restore()); - test('with ascii characters', async () => { - mockFs({ 'test.txt': 'heya' }); - const source = createReadStream('test.txt'); - - let data = ''; - for await (const chunk of source) { - data += chunk; - } - + test('ignores streams that are not fs or zlib streams', async () => { const result = getResponsePayloadBytes( { variety: 'stream', - source, + source: new PassThrough(), } as Response, logger ); - expect(result).toBe(Buffer.byteLength(data)); + expect(result).toBe(undefined); }); - test('with special characters', async () => { - mockFs({ 'test.txt': '¡hola!' }); - const source = createReadStream('test.txt'); + describe('fs streams', () => { + test('with ascii characters', async () => { + mockFs({ 'test.txt': 'heya' }); + const source = createReadStream('test.txt'); - let data = ''; - for await (const chunk of source) { - data += chunk; - } + let data = ''; + for await (const chunk of source) { + data += chunk; + } - const result = getResponsePayloadBytes( - { - variety: 'stream', - source, - } as Response, - logger - ); + const result = getResponsePayloadBytes( + { + variety: 'stream', + source, + } as Response, + logger + ); + + expect(result).toBe(Buffer.byteLength(data)); + }); + + test('with special characters', async () => { + mockFs({ 'test.txt': '¡hola!' }); + const source = createReadStream('test.txt'); + + let data = ''; + for await (const chunk of source) { + data += chunk; + } + + const result = getResponsePayloadBytes( + { + variety: 'stream', + source, + } as Response, + logger + ); - expect(result).toBe(Buffer.byteLength(data)); + expect(result).toBe(Buffer.byteLength(data)); + }); }); - test('ignores streams that are not instances of ReadStream', async () => { - const result = getResponsePayloadBytes( - { - variety: 'stream', - source: createGunzip(), - } as Response, - logger - ); + describe('zlib streams', () => { + test('with ascii characters', async () => { + mockFs({ 'test.txt': 'heya' }); + const readStream = createReadStream('test.txt'); + const source = readStream.pipe(createGzip()).pipe(createGunzip()); - expect(result).toBe(undefined); + let data = ''; + for await (const chunk of source) { + data += chunk; + } + + const result = getResponsePayloadBytes( + { + variety: 'stream', + source, + } as Response, + logger + ); + + expect(data).toBe('heya'); + expect(result).toBe(source.bytesWritten); + }); + + test('with special characters', async () => { + mockFs({ 'test.txt': '¡hola!' }); + const readStream = createReadStream('test.txt'); + const source = readStream.pipe(createGzip()).pipe(createGunzip()); + + let data = ''; + for await (const chunk of source) { + data += chunk; + } + + const result = getResponsePayloadBytes( + { + variety: 'stream', + source, + } as Response, + logger + ); + + expect(data).toBe('¡hola!'); + expect(result).toBe(source.bytesWritten); + }); }); }); @@ -134,7 +183,7 @@ describe('getPayloadSize', () => { expect(result).toBe(7); }); - test('when source is object', () => { + test('when source is plain object', () => { const payload = { message: 'heya' }; const result = getResponsePayloadBytes( { @@ -146,11 +195,26 @@ describe('getPayloadSize', () => { expect(result).toBe(JSON.stringify(payload).length); }); + test('when source is array object', () => { + const payload = [{ message: 'hey' }, { message: 'ya' }]; + const result = getResponsePayloadBytes( + { + variety: 'plain', + source: payload, + } as Response, + logger + ); + expect(result).toBe(JSON.stringify(payload).length); + }); + test('returns undefined when source is not a plain object', () => { + class TestClass { + constructor() {} + } const result = getResponsePayloadBytes( { variety: 'plain', - source: [1, 2, 3], + source: new TestClass(), } as Response, logger ); diff --git a/src/core/server/http/logging/get_payload_size.ts b/src/core/server/http/logging/get_payload_size.ts index 8e6dea13e1fa1..2797b4ba9f490 100644 --- a/src/core/server/http/logging/get_payload_size.ts +++ b/src/core/server/http/logging/get_payload_size.ts @@ -8,25 +8,23 @@ import { isPlainObject } from 'lodash'; import { ReadStream } from 'fs'; +import { Zlib } from 'zlib'; import { isBoom } from '@hapi/boom'; import type { Request } from '@hapi/hapi'; import { Logger } from '../../logging'; type Response = Request['response']; -const isBuffer = (src: unknown, res: Response): src is Buffer => { - return !isBoom(res) && res.variety === 'buffer' && res.source === src; +const isBuffer = (src: unknown, variety: string): src is Buffer => + variety === 'buffer' && Buffer.isBuffer(src); +const isFsReadStream = (src: unknown, variety: string): src is ReadStream => { + return variety === 'stream' && src instanceof ReadStream; }; -const isFsReadStream = (src: unknown, res: Response): src is ReadStream => { - return ( - !isBoom(res) && - res.variety === 'stream' && - res.source === src && - res.source instanceof ReadStream - ); +const isZlibStream = (src: unknown, variety: string): src is Zlib => { + return variety === 'stream' && typeof src === 'object' && src !== null && 'bytesWritten' in src; }; -const isString = (src: unknown, res: Response): src is string => - !isBoom(res) && res.variety === 'plain' && typeof src === 'string'; +const isString = (src: unknown, variety: string): src is string => + variety === 'plain' && typeof src === 'string'; /** * Attempts to determine the size (in bytes) of a Hapi response @@ -57,19 +55,26 @@ export function getResponsePayloadBytes(response: Response, log: Logger): number return Buffer.byteLength(JSON.stringify(response.output.payload)); } - if (isBuffer(response.source, response)) { + if (isBuffer(response.source, response.variety)) { return response.source.byteLength; } - if (isFsReadStream(response.source, response)) { + if (isFsReadStream(response.source, response.variety)) { return response.source.bytesRead; } - if (isString(response.source, response)) { + if (isZlibStream(response.source, response.variety)) { + return response.source.bytesWritten; + } + + if (isString(response.source, response.variety)) { return Buffer.byteLength(response.source); } - if (response.variety === 'plain' && isPlainObject(response.source)) { + if ( + response.variety === 'plain' && + (isPlainObject(response.source) || Array.isArray(response.source)) + ) { return Buffer.byteLength(JSON.stringify(response.source)); } } catch (e) { From d230720e2d0de699927ad48db4bcddbb4dbd7e10 Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Tue, 2 Mar 2021 11:34:13 -0700 Subject: [PATCH 14/33] [Usage Collection] Supports field descriptions as meta data (#92701) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alejandro Fernández Haro Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../__fixture__/all_extracted_collectors.ts | 2 + .../mock_schema_with_descriptions.json | 57 + ...rsed_working_collector_with_description.ts | 109 + .../src/tools/extract_collectors.test.ts | 2 +- .../src/tools/manage_schema.test.ts | 6 + .../working_collector_with_description.ts | 102 + src/plugins/kibana_usage_collection/README.md | 17 +- .../collectors/application_usage/README.md | 6 +- .../collectors/application_usage/schema.ts | 117 +- .../collectors/core/core_usage_collector.ts | 939 ++- .../server/collectors/csp/csp_collector.ts | 3 + .../kibana/kibana_usage_collector.ts | 38 +- .../telemetry_localization_collector.ts | 24 +- .../server/collectors/management/schema.ts | 477 +- .../telemetry_management_collector.ts | 3 +- .../ops_stats/ops_stats_collector.ts | 1 - .../register_ui_counters_collector.ts | 27 +- .../server/collectors/ui_metric/schema.ts | 4 +- src/plugins/telemetry/schema/oss_plugins.json | 6680 +++++++++++++---- src/plugins/usage_collection/README.mdx | 16 +- .../server/collector/collector.test.ts | 39 + .../server/collector/collector.ts | 2 +- .../schema/xpack_plugins.json | 26 +- 23 files changed, 7059 insertions(+), 1638 deletions(-) create mode 100644 packages/kbn-telemetry-tools/src/tools/__fixture__/mock_schema_with_descriptions.json create mode 100644 packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_working_collector_with_description.ts create mode 100644 src/fixtures/telemetry_collectors/working_collector_with_description.ts diff --git a/packages/kbn-telemetry-tools/src/tools/__fixture__/all_extracted_collectors.ts b/packages/kbn-telemetry-tools/src/tools/__fixture__/all_extracted_collectors.ts index 28cfd3560874c..37bdd327f945b 100644 --- a/packages/kbn-telemetry-tools/src/tools/__fixture__/all_extracted_collectors.ts +++ b/packages/kbn-telemetry-tools/src/tools/__fixture__/all_extracted_collectors.ts @@ -13,6 +13,7 @@ import { parsedIndexedInterfaceWithNoMatchingSchema } from './parsed_indexed_int import { parsedNestedCollector } from './parsed_nested_collector'; import { parsedSchemaDefinedWithSpreadsCollector } from './parsed_schema_defined_with_spreads_collector'; import { parsedWorkingCollector } from './parsed_working_collector'; +import { parsedCollectorWithDescription } from './parsed_working_collector_with_description'; import { ParsedUsageCollection } from '../ts_parser'; export const allExtractedCollectors: ParsedUsageCollection[] = [ @@ -22,5 +23,6 @@ export const allExtractedCollectors: ParsedUsageCollection[] = [ parsedIndexedInterfaceWithNoMatchingSchema, parsedNestedCollector, parsedSchemaDefinedWithSpreadsCollector, + parsedCollectorWithDescription, parsedWorkingCollector, ]; diff --git a/packages/kbn-telemetry-tools/src/tools/__fixture__/mock_schema_with_descriptions.json b/packages/kbn-telemetry-tools/src/tools/__fixture__/mock_schema_with_descriptions.json new file mode 100644 index 0000000000000..77321327b3894 --- /dev/null +++ b/packages/kbn-telemetry-tools/src/tools/__fixture__/mock_schema_with_descriptions.json @@ -0,0 +1,57 @@ +{ + "properties": { + "my_working_collector_with_description": { + "properties": { + "flat": { + "type": "keyword", + "_meta": { + "description": "A flat keyword string" + } + }, + "my_index_signature_prop": { + "properties": { + "avg": { + "type": "float" + }, + "count": { + "type": "long" + }, + "max": { + "type": "long" + }, + "min": { + "type": "long" + } + } + }, + "my_str": { + "type": "text" + }, + "my_objects": { + "properties": { + "total": { + "type": "long" + }, + "type": { + "type": "boolean" + } + } + }, + "my_array": { + "type": "array", + "items": { + "properties": { + "total": { + "type": "long" + }, + "type": { + "type": "boolean" + } + } + } + }, + "my_str_array": { "type": "array", "items": { "type": "keyword" } } + } + } + } +} diff --git a/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_working_collector_with_description.ts b/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_working_collector_with_description.ts new file mode 100644 index 0000000000000..a2f9379eec7ac --- /dev/null +++ b/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_working_collector_with_description.ts @@ -0,0 +1,109 @@ +/* + * 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 { SyntaxKind } from 'typescript'; +import { ParsedUsageCollection } from '../ts_parser'; + +export const parsedCollectorWithDescription: ParsedUsageCollection = [ + 'src/fixtures/telemetry_collectors/working_collector_with_description.ts', + { + collectorName: 'my_working_collector_with_description', + schema: { + value: { + flat: { + type: 'keyword', + _meta: { + description: 'A flat keyword string', + }, + }, + my_str: { + type: 'text', + }, + my_index_signature_prop: { + avg: { + type: 'float', + }, + count: { + type: 'long', + }, + max: { + type: 'long', + }, + min: { + type: 'long', + }, + }, + my_objects: { + total: { + type: 'long', + }, + type: { + type: 'boolean', + }, + }, + my_array: { + type: 'array', + items: { + total: { + type: 'long', + }, + type: { type: 'boolean' }, + }, + }, + my_str_array: { type: 'array', items: { type: 'keyword' } }, + }, + }, + fetch: { + typeName: 'Usage', + typeDescriptor: { + flat: { + kind: SyntaxKind.StringKeyword, + type: 'StringKeyword', + }, + my_str: { + kind: SyntaxKind.StringKeyword, + type: 'StringKeyword', + }, + my_index_signature_prop: { + '@@INDEX@@': { + kind: SyntaxKind.NumberKeyword, + type: 'NumberKeyword', + }, + }, + my_objects: { + total: { + kind: SyntaxKind.NumberKeyword, + type: 'NumberKeyword', + }, + type: { + kind: SyntaxKind.BooleanKeyword, + type: 'BooleanKeyword', + }, + }, + my_array: { + items: { + total: { + kind: SyntaxKind.NumberKeyword, + type: 'NumberKeyword', + }, + type: { + kind: SyntaxKind.BooleanKeyword, + type: 'BooleanKeyword', + }, + }, + }, + my_str_array: { + items: { + kind: SyntaxKind.StringKeyword, + type: 'StringKeyword', + }, + }, + }, + }, + }, +]; diff --git a/packages/kbn-telemetry-tools/src/tools/extract_collectors.test.ts b/packages/kbn-telemetry-tools/src/tools/extract_collectors.test.ts index 378518a13c7ac..5106ac7855fc6 100644 --- a/packages/kbn-telemetry-tools/src/tools/extract_collectors.test.ts +++ b/packages/kbn-telemetry-tools/src/tools/extract_collectors.test.ts @@ -24,7 +24,7 @@ describe('extractCollectors', () => { const programPaths = await getProgramPaths(configs[0]); const results = [...extractCollectors(programPaths, tsConfig)]; - expect(results).toHaveLength(8); + expect(results).toHaveLength(9); expect(results).toStrictEqual(allExtractedCollectors); }); }); diff --git a/packages/kbn-telemetry-tools/src/tools/manage_schema.test.ts b/packages/kbn-telemetry-tools/src/tools/manage_schema.test.ts index b39e243d78772..80e58c49928b6 100644 --- a/packages/kbn-telemetry-tools/src/tools/manage_schema.test.ts +++ b/packages/kbn-telemetry-tools/src/tools/manage_schema.test.ts @@ -8,6 +8,7 @@ import { generateMapping } from './manage_schema'; import { parsedWorkingCollector } from './__fixture__/parsed_working_collector'; +import { parsedCollectorWithDescription } from './__fixture__/parsed_working_collector_with_description'; import * as path from 'path'; import { readFile } from 'fs'; import { promisify } from 'util'; @@ -25,4 +26,9 @@ describe('generateMapping', () => { const result = generateMapping([parsedWorkingCollector]); expect(result).toEqual(mockSchema); }); + it('generates a mapping file that includes _meta.description fields', async () => { + const mockSchema = await parseJsonFile('mock_schema_with_descriptions.json'); + const result = generateMapping([parsedCollectorWithDescription]); + expect(result).toEqual(mockSchema); + }); }); diff --git a/src/fixtures/telemetry_collectors/working_collector_with_description.ts b/src/fixtures/telemetry_collectors/working_collector_with_description.ts new file mode 100644 index 0000000000000..433993df06886 --- /dev/null +++ b/src/fixtures/telemetry_collectors/working_collector_with_description.ts @@ -0,0 +1,102 @@ +/* + * 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 { CollectorSet } from '../../plugins/usage_collection/server/collector'; +import { loggerMock } from '../../core/server/logging/logger.mock'; + +const { makeUsageCollector } = new CollectorSet({ + logger: loggerMock.create(), + maximumWaitTimeForAllCollectorsInS: 0, +}); + +interface MyObject { + total: number; + type: boolean; +} + +interface Usage { + flat?: string; + my_str?: string; + my_objects: MyObject; + my_array?: MyObject[]; + my_str_array?: string[]; + my_index_signature_prop?: { + [key: string]: number; + }; +} + +const SOME_NUMBER: number = 123; + +export const myCollector = makeUsageCollector({ + type: 'my_working_collector_with_description', + isReady: () => true, + fetch() { + const testString = '123'; + // query ES and get some data + + // summarize the data into a model + // return the modeled object that includes whatever you want to track + try { + return { + flat: 'hello', + my_str: testString, + my_objects: { + total: SOME_NUMBER, + type: true, + }, + my_array: [ + { + total: SOME_NUMBER, + type: true, + }, + ], + my_str_array: ['hello', 'world'], + }; + } catch (err) { + return { + my_objects: { + total: 0, + type: true, + }, + }; + } + }, + schema: { + flat: { + type: 'keyword', + _meta: { + description: 'A flat keyword string', + }, + }, + my_str: { + type: 'text', + }, + my_objects: { + total: { + type: 'long', + }, + type: { type: 'boolean' }, + }, + my_array: { + type: 'array', + items: { + total: { + type: 'long', + }, + type: { type: 'boolean' }, + }, + }, + my_str_array: { type: 'array', items: { type: 'keyword' } }, + my_index_signature_prop: { + count: { type: 'long' }, + avg: { type: 'float' }, + max: { type: 'long' }, + min: { type: 'long' }, + }, + }, +}); diff --git a/src/plugins/kibana_usage_collection/README.md b/src/plugins/kibana_usage_collection/README.md index 85d362cf0a9b1..9ad2bd987e1f4 100644 --- a/src/plugins/kibana_usage_collection/README.md +++ b/src/plugins/kibana_usage_collection/README.md @@ -3,9 +3,16 @@ This plugin registers the basic usage collectors from Kibana: - [Application Usage](./server/collectors/application_usage/README.md) -- UI Metrics -- Ops stats -- Number of Saved Objects per type -- [User-changed UI Settings](./server/collectors/management/README.md) -- CSP configuration - Core Metrics +- CSP configuration +- Kibana: Number of Saved Objects per type +- Localization data +- [User-changed UI Settings](./server/collectors/management/README.md) +- Ops stats +- UI Counts +- UI Metrics + + + + + diff --git a/src/plugins/kibana_usage_collection/server/collectors/application_usage/README.md b/src/plugins/kibana_usage_collection/server/collectors/application_usage/README.md index c66074b792bd0..1f7344a801227 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/application_usage/README.md +++ b/src/plugins/kibana_usage_collection/server/collectors/application_usage/README.md @@ -10,7 +10,7 @@ To track a sub view inside your application (ie a flyout, a tab, form step, etc) #### For a React Component -For tracking an application view rendered using react the simplest way is to wrap your component with the `TrackApplicationView` Higher order component: +For tracking an application view rendered using react the simplest way is to wrap your component with the `TrackApplicationView` Higher order component exposed from the `usageCollection` plugin. You will need to add the plugin to plugin's `kibana.json` file as an item in the `optionalPlugins` and `requiredBundles` declarations: kibana.json ```json @@ -26,6 +26,7 @@ kibana.json At the application level, the application must be wrapped by the `ApplicationUsageTrackingProvider` provided in the `usageCollection`'s setup contract. +For example: ```typescript jsx class MyPlugin implements Plugin { ... @@ -69,7 +70,6 @@ const MyTrackedComponent = () => { Application Usage will automatically track the active minutes on screen and clicks for both the application and the `MyComponent` component whenever it is mounted on the screen. Application Usage pauses counting screen minutes whenever the user is tabbed to another browser window. The prop `viewId` is used as a unique identifier for your plugin. The Application Id is automatically attached to the tracked usage, based on the ID used when registering your app via `core.application.register`. - ## Application Usage Telemetry Data This collector reports the number of general clicks and minutes on screen for each registered application in Kibana. @@ -126,4 +126,4 @@ In order to keep the count of the events, this collector uses 3 Saved Objects: All the types use the shared fields `appId: 'keyword'`, `viewId: 'keyword'`, `numberOfClicks: 'long'` and `minutesOnScreen: 'float'`, but they are currently not added in the mappings because we don't use them for search purposes, and we need to be thoughtful with the number of mapped fields in the SavedObjects index ([#43673](https://github.com/elastic/kibana/issues/43673)). `application_usage_transactional` and `application_usage_daily` also store `timestamp: { type: 'date' }`. -Rollups uses `appId` in the savedObject id for the default view. For other views `viewId` is concatenated. This keeps backwards compatiblity with previously stored documents on the clusters without requiring any form of migration. \ No newline at end of file +Rollups uses `appId` in the savedObject id for the default view. For other views `viewId` is concatenated. This keeps backwards compatiblity with previously stored documents on the clusters without requiring any form of migration. diff --git a/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts index 136abc9049053..062d751ef454c 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts @@ -10,29 +10,106 @@ import { MakeSchemaFrom } from 'src/plugins/usage_collection/server'; import { ApplicationUsageTelemetryReport } from './telemetry_application_usage_collector'; const commonSchema: MakeSchemaFrom = { - appId: { type: 'keyword' }, - viewId: { type: 'keyword' }, - clicks_total: { type: 'long' }, - clicks_7_days: { type: 'long' }, - clicks_30_days: { type: 'long' }, - clicks_90_days: { type: 'long' }, - minutes_on_screen_total: { type: 'float' }, - minutes_on_screen_7_days: { type: 'float' }, - minutes_on_screen_30_days: { type: 'float' }, - minutes_on_screen_90_days: { type: 'float' }, + appId: { type: 'keyword', _meta: { description: 'The application being tracked' } }, + viewId: { type: 'keyword', _meta: { description: 'Always `main`' } }, + clicks_total: { + type: 'long', + _meta: { + description: 'General number of clicks in the application since we started counting them', + }, + }, + clicks_7_days: { + type: 'long', + _meta: { description: 'General number of clicks in the application over the last 7 days' }, + }, + clicks_30_days: { + type: 'long', + _meta: { description: 'General number of clicks in the application over the last 30 days' }, + }, + clicks_90_days: { + type: 'long', + _meta: { description: 'General number of clicks in the application over the last 90 days' }, + }, + minutes_on_screen_total: { + type: 'float', + _meta: { + description: + 'Minutes the application is active and on-screen since we started counting them.', + }, + }, + minutes_on_screen_7_days: { + type: 'float', + _meta: { description: 'Minutes the application is active and on-screen over the last 7 days' }, + }, + minutes_on_screen_30_days: { + type: 'float', + _meta: { description: 'Minutes the application is active and on-screen over the last 30 days' }, + }, + minutes_on_screen_90_days: { + type: 'float', + _meta: { description: 'Minutes the application is active and on-screen over the last 90 days' }, + }, views: { type: 'array', items: { - appId: { type: 'keyword' }, - viewId: { type: 'keyword' }, - clicks_total: { type: 'long' }, - clicks_7_days: { type: 'long' }, - clicks_30_days: { type: 'long' }, - clicks_90_days: { type: 'long' }, - minutes_on_screen_total: { type: 'float' }, - minutes_on_screen_7_days: { type: 'float' }, - minutes_on_screen_30_days: { type: 'float' }, - minutes_on_screen_90_days: { type: 'float' }, + appId: { type: 'keyword', _meta: { description: 'The application being tracked' } }, + viewId: { type: 'keyword', _meta: { description: 'The application view being tracked' } }, + clicks_total: { + type: 'long', + _meta: { + description: + 'General number of clicks in the application sub view since we started counting them', + }, + }, + clicks_7_days: { + type: 'long', + _meta: { + description: + 'General number of clicks in the active application sub view over the last 7 days', + }, + }, + clicks_30_days: { + type: 'long', + _meta: { + description: + 'General number of clicks in the active application sub view over the last 30 days', + }, + }, + clicks_90_days: { + type: 'long', + _meta: { + description: + 'General number of clicks in the active application sub view over the last 90 days', + }, + }, + minutes_on_screen_total: { + type: 'float', + _meta: { + description: + 'Minutes the application sub view is active and on-screen since we started counting them.', + }, + }, + minutes_on_screen_7_days: { + type: 'float', + _meta: { + description: + 'Minutes the application is active and on-screen active application sub view over the last 7 days', + }, + }, + minutes_on_screen_30_days: { + type: 'float', + _meta: { + description: + 'Minutes the application is active and on-screen active application sub view over the last 30 days', + }, + }, + minutes_on_screen_90_days: { + type: 'float', + _meta: { + description: + 'Minutes the application is active and on-screen active application sub view over the last 90 days', + }, + }, }, }, }; diff --git a/src/plugins/kibana_usage_collection/server/collectors/core/core_usage_collector.ts b/src/plugins/kibana_usage_collection/server/collectors/core/core_usage_collector.ts index 4a1848586114a..70ac2302dc3b4 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/core/core_usage_collector.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/core/core_usage_collector.ts @@ -19,76 +19,276 @@ export function getCoreUsageCollector( schema: { config: { elasticsearch: { - sniffOnStart: { type: 'boolean' }, - sniffIntervalMs: { type: 'long' }, - sniffOnConnectionFault: { type: 'boolean' }, - numberOfHostsConfigured: { type: 'long' }, - requestHeadersWhitelistConfigured: { type: 'boolean' }, - customHeadersConfigured: { type: 'boolean' }, - shardTimeoutMs: { type: 'long' }, - requestTimeoutMs: { type: 'long' }, - pingTimeoutMs: { type: 'long' }, - logQueries: { type: 'boolean' }, + sniffOnStart: { + type: 'boolean', + _meta: { + description: + 'Indicates if an attempt should be made to find other Elasticsearch nodes on startup.', + }, + }, + sniffIntervalMs: { + type: 'long', + _meta: { + description: + 'Time in milliseconds between requests to check Elasticsearch for an updated list of nodes.', + }, + }, + sniffOnConnectionFault: { + type: 'boolean', + _meta: { + description: + 'Indicates if the list of Elasticsearch nodes should be updated immediately following a connection fault.', + }, + }, + numberOfHostsConfigured: { + type: 'long', + _meta: { + description: 'Number of Elasticsearch instances configured to use for queries.', + }, + }, + requestHeadersWhitelistConfigured: { + type: 'boolean', + _meta: { + description: + 'Indicates if Kibana client-side headers to send to Elasticsearch is different to the default value.', + }, + }, + customHeadersConfigured: { + type: 'boolean', + _meta: { description: 'Indicates if any custom headers have been configured.' }, + }, + shardTimeoutMs: { + type: 'long', + _meta: { + description: + 'Time in milliseconds for Elasticsearch to wait for responses from shards.', + }, + }, + requestTimeoutMs: { + type: 'long', + _meta: { + description: + 'Time in milliseconds to wait for responses from the back end or Elasticsearch.', + }, + }, + pingTimeoutMs: { + type: 'long', + _meta: { + description: 'Time in milliseconds to wait for Elasticsearch to respond to pings.', + }, + }, + logQueries: { + type: 'boolean', + _meta: { description: 'Indicates if queries sent to Elasticsearch should be logged.' }, + }, ssl: { - verificationMode: { type: 'keyword' }, - certificateAuthoritiesConfigured: { type: 'boolean' }, - certificateConfigured: { type: 'boolean' }, - keyConfigured: { type: 'boolean' }, - keystoreConfigured: { type: 'boolean' }, - truststoreConfigured: { type: 'boolean' }, - alwaysPresentCertificate: { type: 'boolean' }, + verificationMode: { + type: 'keyword', + _meta: { + description: + 'The verification of the server certificate that Kibana receives when making an outbound SSL or TLS connection to Elasticsearch', + }, + }, + certificateAuthoritiesConfigured: { + type: 'boolean', + _meta: { + description: + 'Indicates if any PEM-encoded X.509 certificate authority certificates are configured.', + }, + }, + certificateConfigured: { + type: 'boolean', + _meta: { description: 'Indicates if a certificate authority is configured.' }, + }, + keyConfigured: { + type: 'boolean', + _meta: { description: 'Indicates if a certificate key is configured.' }, + }, + keystoreConfigured: { + type: 'boolean', + _meta: { description: 'Indicates if a keystore is configured.' }, + }, + truststoreConfigured: { + type: 'boolean', + _meta: { description: 'Indicates if a path to a PKCS#12 trust store is configured.' }, + }, + alwaysPresentCertificate: { + type: 'boolean', + _meta: { + description: + 'Indicates if a client certificate is presented when requested by Elasticsearch.', + }, + }, + }, + apiVersion: { + type: 'keyword', + _meta: { description: 'Version of the Elasticsearch API used.' }, + }, + healthCheckDelayMs: { + type: 'long', + _meta: { + description: + 'The interval in miliseconds between health check requests Kibana sends to the Elasticsearch.', + }, }, - apiVersion: { type: 'keyword' }, - healthCheckDelayMs: { type: 'long' }, }, http: { - basePathConfigured: { type: 'boolean' }, - maxPayloadInBytes: { type: 'long' }, - rewriteBasePath: { type: 'boolean' }, - keepaliveTimeout: { type: 'long' }, - socketTimeout: { type: 'long' }, + basePathConfigured: { + type: 'boolean', + _meta: { description: 'Indicates if a base path has been configured.' }, + }, + maxPayloadInBytes: { + type: 'long', + _meta: { description: 'Maximum payload size in bytes that is allowed.' }, + }, + rewriteBasePath: { + type: 'boolean', + _meta: { description: 'Indicates if the base path should be rewritten.' }, + }, + keepaliveTimeout: { + type: 'long', + _meta: { description: 'How long to keep sockets alive globally in milliseconds.' }, + }, + socketTimeout: { + type: 'long', + _meta: { + description: 'How long to wait before closing inactive sockets in milliseconds.', + }, + }, compression: { - enabled: { type: 'boolean' }, - referrerWhitelistConfigured: { type: 'boolean' }, + enabled: { + type: 'boolean', + _meta: { description: 'Indicates if HTTP response compression is enabled.' }, + }, + referrerWhitelistConfigured: { + type: 'boolean', + _meta: { description: 'Indicates if any responses should be compressed.' }, + }, }, xsrf: { - disableProtection: { type: 'boolean' }, - allowlistConfigured: { type: 'boolean' }, + disableProtection: { + type: 'boolean', + _meta: { description: 'Indicates if protection against xsrf should be disabled.' }, + }, + allowlistConfigured: { + type: 'boolean', + _meta: { description: 'Indicates if any http headers have been whitelisted.' }, + }, }, requestId: { - allowFromAnyIp: { type: 'boolean' }, - ipAllowlistConfigured: { type: 'boolean' }, + allowFromAnyIp: { + type: 'boolean', + _meta: { description: 'Indicates if any http headers have been whitelisted.' }, + }, + ipAllowlistConfigured: { + type: 'boolean', + _meta: { description: 'Indicates if a list of specific IPs has been configured.' }, + }, }, ssl: { - certificateAuthoritiesConfigured: { type: 'boolean' }, - certificateConfigured: { type: 'boolean' }, - cipherSuites: { type: 'array', items: { type: 'keyword' } }, - keyConfigured: { type: 'boolean' }, - keystoreConfigured: { type: 'boolean' }, - truststoreConfigured: { type: 'boolean' }, - redirectHttpFromPortConfigured: { type: 'boolean' }, - supportedProtocols: { type: 'array', items: { type: 'keyword' } }, - clientAuthentication: { type: 'keyword' }, + certificateAuthoritiesConfigured: { + type: 'boolean', + _meta: { + description: 'Indicates if ssl certificate authorities have been configured.', + }, + }, + certificateConfigured: { + type: 'boolean', + _meta: { description: 'Indicates if an ssl certificate is configured.' }, + }, + cipherSuites: { + type: 'array', + items: { + type: 'keyword', + _meta: { description: 'The keyword of the cipher suite used.' }, + }, + }, + keyConfigured: { + type: 'boolean', + _meta: { description: 'Indicates if an ssl key has been configured.' }, + }, + keystoreConfigured: { + type: 'boolean', + _meta: { description: 'Indicates if an ssl keystore has been configured.' }, + }, + truststoreConfigured: { + type: 'boolean', + _meta: { description: 'Indicates if a path to a PKCS#12 trust store is configured.' }, + }, + redirectHttpFromPortConfigured: { + type: 'boolean', + _meta: { + description: + 'Indicates if a port to redirect all http requests has been configured.', + }, + }, + supportedProtocols: { + type: 'array', + items: { + type: 'keyword', + _meta: { description: 'The version of a supported protocol used.' }, + }, + }, + clientAuthentication: { + type: 'keyword', + _meta: { + description: + 'The behavior in Kibana for requesting a certificate from client connections.', + }, + }, }, }, logging: { - appendersTypesUsed: { type: 'array', items: { type: 'keyword' } }, - loggersConfiguredCount: { type: 'long' }, + appendersTypesUsed: { + type: 'array', + items: { + type: 'keyword', + _meta: { description: 'The type of logging appender confgured.' }, + }, + }, + loggersConfiguredCount: { + type: 'long', + _meta: { description: 'The total number of logging appenders configured.' }, + }, }, savedObjects: { - customIndex: { type: 'boolean' }, - maxImportPayloadBytes: { type: 'long' }, - maxImportExportSizeBytes: { type: 'long' }, + customIndex: { + type: 'boolean', + _meta: { + description: + 'Indicates if the saved objects index is different to the standard internal .kibana index.', + }, + }, + maxImportPayloadBytes: { + type: 'long', + _meta: { + description: + 'Maximum size of the payload in bytes of saved objects that can be imported.', + }, + }, + maxImportExportSizeBytes: { + type: 'long', + _meta: { + description: + 'Maximum size in bytes of saved object that can be imported or exported.', + }, + }, }, }, environment: { memory: { - heapSizeLimit: { type: 'long' }, - heapTotalBytes: { type: 'long' }, - heapUsedBytes: { type: 'long' }, + heapSizeLimit: { type: 'long', _meta: { description: 'Host memory heap size limit.' } }, + heapTotalBytes: { + type: 'long', + _meta: { description: 'Total memory heap size of host that is available in bytes.' }, + }, + heapUsedBytes: { + type: 'long', + _meta: { description: 'Total memory heap size of host that is used in bytes.' }, + }, }, }, services: { @@ -96,117 +296,576 @@ export function getCoreUsageCollector( indices: { type: 'array', items: { - docsCount: { type: 'long' }, - docsDeleted: { type: 'long' }, - alias: { type: 'keyword' }, - primaryStoreSizeBytes: { type: 'long' }, - storeSizeBytes: { type: 'long' }, + docsCount: { + type: 'long', + _meta: { + description: + 'The number of documents in the index, including hidden nested documents.', + }, + }, + docsDeleted: { + type: 'long', + _meta: { + description: + 'The number of deleted documents in the index, including hidden nested documents.', + }, + }, + alias: { + type: 'keyword', + _meta: { + description: + 'The alias used to map customized saved object index names to standard index names (.kibana or .kibana_task_manager).', + }, + }, + primaryStoreSizeBytes: { + type: 'long', + _meta: { description: 'The size in bytes of the index, for primaries only.' }, + }, + storeSizeBytes: { + type: 'long', + _meta: { + description: 'The size in bytes of the index, for primaries and replicas.', + }, + }, }, }, }, }, // Saved Objects Client APIs - 'apiCalls.savedObjectsBulkCreate.total': { type: 'long' }, - 'apiCalls.savedObjectsBulkCreate.namespace.default.total': { type: 'long' }, - 'apiCalls.savedObjectsBulkCreate.namespace.default.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsBulkCreate.namespace.default.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsBulkCreate.namespace.custom.total': { type: 'long' }, - 'apiCalls.savedObjectsBulkCreate.namespace.custom.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsBulkCreate.namespace.custom.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsBulkGet.total': { type: 'long' }, - 'apiCalls.savedObjectsBulkGet.namespace.default.total': { type: 'long' }, - 'apiCalls.savedObjectsBulkGet.namespace.default.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsBulkGet.namespace.default.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsBulkGet.namespace.custom.total': { type: 'long' }, - 'apiCalls.savedObjectsBulkGet.namespace.custom.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsBulkGet.namespace.custom.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsBulkUpdate.total': { type: 'long' }, - 'apiCalls.savedObjectsBulkUpdate.namespace.default.total': { type: 'long' }, - 'apiCalls.savedObjectsBulkUpdate.namespace.default.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsBulkUpdate.namespace.default.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsBulkUpdate.namespace.custom.total': { type: 'long' }, - 'apiCalls.savedObjectsBulkUpdate.namespace.custom.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsBulkUpdate.namespace.custom.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsCreate.total': { type: 'long' }, - 'apiCalls.savedObjectsCreate.namespace.default.total': { type: 'long' }, - 'apiCalls.savedObjectsCreate.namespace.default.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsCreate.namespace.default.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsCreate.namespace.custom.total': { type: 'long' }, - 'apiCalls.savedObjectsCreate.namespace.custom.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsCreate.namespace.custom.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsDelete.total': { type: 'long' }, - 'apiCalls.savedObjectsDelete.namespace.default.total': { type: 'long' }, - 'apiCalls.savedObjectsDelete.namespace.default.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsDelete.namespace.default.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsDelete.namespace.custom.total': { type: 'long' }, - 'apiCalls.savedObjectsDelete.namespace.custom.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsDelete.namespace.custom.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsFind.total': { type: 'long' }, - 'apiCalls.savedObjectsFind.namespace.default.total': { type: 'long' }, - 'apiCalls.savedObjectsFind.namespace.default.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsFind.namespace.default.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsFind.namespace.custom.total': { type: 'long' }, - 'apiCalls.savedObjectsFind.namespace.custom.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsFind.namespace.custom.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsGet.total': { type: 'long' }, - 'apiCalls.savedObjectsGet.namespace.default.total': { type: 'long' }, - 'apiCalls.savedObjectsGet.namespace.default.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsGet.namespace.default.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsGet.namespace.custom.total': { type: 'long' }, - 'apiCalls.savedObjectsGet.namespace.custom.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsGet.namespace.custom.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsResolve.total': { type: 'long' }, - 'apiCalls.savedObjectsResolve.namespace.default.total': { type: 'long' }, - 'apiCalls.savedObjectsResolve.namespace.default.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsResolve.namespace.default.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsResolve.namespace.custom.total': { type: 'long' }, - 'apiCalls.savedObjectsResolve.namespace.custom.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsResolve.namespace.custom.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsUpdate.total': { type: 'long' }, - 'apiCalls.savedObjectsUpdate.namespace.default.total': { type: 'long' }, - 'apiCalls.savedObjectsUpdate.namespace.default.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsUpdate.namespace.default.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsUpdate.namespace.custom.total': { type: 'long' }, - 'apiCalls.savedObjectsUpdate.namespace.custom.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsUpdate.namespace.custom.kibanaRequest.no': { type: 'long' }, + 'apiCalls.savedObjectsBulkCreate.total': { + type: 'long', + _meta: { description: 'How many times this API has been called.' }, + }, + 'apiCalls.savedObjectsBulkCreate.namespace.default.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in the Default space.' }, + }, + 'apiCalls.savedObjectsBulkCreate.namespace.default.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsBulkCreate.namespace.default.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsBulkCreate.namespace.custom.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in a custom space.' }, + }, + 'apiCalls.savedObjectsBulkCreate.namespace.custom.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsBulkCreate.namespace.custom.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsBulkGet.total': { + type: 'long', + _meta: { description: 'How many times this API has been called.' }, + }, + 'apiCalls.savedObjectsBulkGet.namespace.default.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in the Default space.' }, + }, + 'apiCalls.savedObjectsBulkGet.namespace.default.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsBulkGet.namespace.default.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsBulkGet.namespace.custom.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in a custom space.' }, + }, + 'apiCalls.savedObjectsBulkGet.namespace.custom.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsBulkGet.namespace.custom.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsBulkUpdate.total': { + type: 'long', + _meta: { description: 'How many times this API has been called.' }, + }, + 'apiCalls.savedObjectsBulkUpdate.namespace.default.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in the Default space.' }, + }, + 'apiCalls.savedObjectsBulkUpdate.namespace.default.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsBulkUpdate.namespace.default.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsBulkUpdate.namespace.custom.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in a custom space.' }, + }, + 'apiCalls.savedObjectsBulkUpdate.namespace.custom.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsBulkUpdate.namespace.custom.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsCreate.total': { + type: 'long', + _meta: { description: 'How many times this API has been called.' }, + }, + 'apiCalls.savedObjectsCreate.namespace.default.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in the Default space.' }, + }, + 'apiCalls.savedObjectsCreate.namespace.default.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsCreate.namespace.default.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsCreate.namespace.custom.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in a custom space.' }, + }, + 'apiCalls.savedObjectsCreate.namespace.custom.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsCreate.namespace.custom.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsDelete.total': { + type: 'long', + _meta: { description: 'How many times this API has been called.' }, + }, + 'apiCalls.savedObjectsDelete.namespace.default.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in the Default space.' }, + }, + 'apiCalls.savedObjectsDelete.namespace.default.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsDelete.namespace.default.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsDelete.namespace.custom.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in a custom space.' }, + }, + 'apiCalls.savedObjectsDelete.namespace.custom.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsDelete.namespace.custom.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsFind.total': { + type: 'long', + _meta: { description: 'How many times this API has been called.' }, + }, + 'apiCalls.savedObjectsFind.namespace.default.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in the Default space.' }, + }, + 'apiCalls.savedObjectsFind.namespace.default.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsFind.namespace.default.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsFind.namespace.custom.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in a custom space.' }, + }, + 'apiCalls.savedObjectsFind.namespace.custom.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsFind.namespace.custom.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsGet.total': { + type: 'long', + _meta: { description: 'How many times this API has been called.' }, + }, + 'apiCalls.savedObjectsGet.namespace.default.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in the Default space.' }, + }, + 'apiCalls.savedObjectsGet.namespace.default.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsGet.namespace.default.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsGet.namespace.custom.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in a custom space.' }, + }, + 'apiCalls.savedObjectsGet.namespace.custom.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsGet.namespace.custom.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsResolve.total': { + type: 'long', + _meta: { description: 'How many times this API has been called.' }, + }, + 'apiCalls.savedObjectsResolve.namespace.default.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in the Default space.' }, + }, + 'apiCalls.savedObjectsResolve.namespace.default.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsResolve.namespace.default.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsResolve.namespace.custom.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in a custom space.' }, + }, + 'apiCalls.savedObjectsResolve.namespace.custom.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsResolve.namespace.custom.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsUpdate.total': { + type: 'long', + _meta: { description: 'How many times this API has been called.' }, + }, + 'apiCalls.savedObjectsUpdate.namespace.default.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in the Default space.' }, + }, + 'apiCalls.savedObjectsUpdate.namespace.default.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsUpdate.namespace.default.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsUpdate.namespace.custom.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in a custom space.' }, + }, + 'apiCalls.savedObjectsUpdate.namespace.custom.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsUpdate.namespace.custom.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in a custom space.', + }, + }, // Saved Objects Management APIs - 'apiCalls.savedObjectsImport.total': { type: 'long' }, - 'apiCalls.savedObjectsImport.namespace.default.total': { type: 'long' }, - 'apiCalls.savedObjectsImport.namespace.default.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsImport.namespace.default.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsImport.namespace.custom.total': { type: 'long' }, - 'apiCalls.savedObjectsImport.namespace.custom.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsImport.namespace.custom.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsImport.createNewCopiesEnabled.yes': { type: 'long' }, - 'apiCalls.savedObjectsImport.createNewCopiesEnabled.no': { type: 'long' }, - 'apiCalls.savedObjectsImport.overwriteEnabled.yes': { type: 'long' }, - 'apiCalls.savedObjectsImport.overwriteEnabled.no': { type: 'long' }, - 'apiCalls.savedObjectsResolveImportErrors.total': { type: 'long' }, - 'apiCalls.savedObjectsResolveImportErrors.namespace.default.total': { type: 'long' }, + 'apiCalls.savedObjectsImport.total': { + type: 'long', + _meta: { description: 'How many times this API has been called.' }, + }, + 'apiCalls.savedObjectsImport.namespace.default.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in the Default space.' }, + }, + 'apiCalls.savedObjectsImport.namespace.default.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsImport.namespace.default.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsImport.namespace.custom.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in a custom space.' }, + }, + 'apiCalls.savedObjectsImport.namespace.custom.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsImport.namespace.custom.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsImport.createNewCopiesEnabled.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called with the `createNewCopiesEnabled` option.', + }, + }, + 'apiCalls.savedObjectsImport.createNewCopiesEnabled.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called without the `createNewCopiesEnabled` option.', + }, + }, + 'apiCalls.savedObjectsImport.overwriteEnabled.yes': { + type: 'long', + _meta: { + description: 'How many times this API has been called with the `overwrite` option.', + }, + }, + 'apiCalls.savedObjectsImport.overwriteEnabled.no': { + type: 'long', + _meta: { + description: 'How many times this API has been called without the `overwrite` option.', + }, + }, + 'apiCalls.savedObjectsResolveImportErrors.total': { + type: 'long', + _meta: { description: 'How many times this API has been called.' }, + }, + 'apiCalls.savedObjectsResolveImportErrors.namespace.default.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in the Default space.' }, + }, 'apiCalls.savedObjectsResolveImportErrors.namespace.default.kibanaRequest.yes': { type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in the Default space.', + }, }, 'apiCalls.savedObjectsResolveImportErrors.namespace.default.kibanaRequest.no': { type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsResolveImportErrors.namespace.custom.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in a custom space.' }, }, - 'apiCalls.savedObjectsResolveImportErrors.namespace.custom.total': { type: 'long' }, 'apiCalls.savedObjectsResolveImportErrors.namespace.custom.kibanaRequest.yes': { type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in a custom space.', + }, }, 'apiCalls.savedObjectsResolveImportErrors.namespace.custom.kibanaRequest.no': { type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsResolveImportErrors.createNewCopiesEnabled.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called with the `createNewCopiesEnabled` option.', + }, + }, + 'apiCalls.savedObjectsResolveImportErrors.createNewCopiesEnabled.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called without the `createNewCopiesEnabled` option.', + }, + }, + 'apiCalls.savedObjectsExport.total': { + type: 'long', + _meta: { description: 'How many times this API has been called.' }, + }, + 'apiCalls.savedObjectsExport.namespace.default.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in the Default space.' }, + }, + 'apiCalls.savedObjectsExport.namespace.default.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsExport.namespace.default.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in the Default space.', + }, + }, + 'apiCalls.savedObjectsExport.namespace.custom.total': { + type: 'long', + _meta: { description: 'How many times this API has been called in a custom space.' }, + }, + 'apiCalls.savedObjectsExport.namespace.custom.kibanaRequest.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by the Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsExport.namespace.custom.kibanaRequest.no': { + type: 'long', + _meta: { + description: + 'How many times this API has been called by a non-Kibana client in a custom space.', + }, + }, + 'apiCalls.savedObjectsExport.allTypesSelected.yes': { + type: 'long', + _meta: { + description: + 'How many times this API has been called with the `createNewCopiesEnabled` option.', + }, + }, + 'apiCalls.savedObjectsExport.allTypesSelected.no': { + type: 'long', + _meta: { + description: 'How many times this API has been called without all types selected.', + }, }, - 'apiCalls.savedObjectsResolveImportErrors.createNewCopiesEnabled.yes': { type: 'long' }, - 'apiCalls.savedObjectsResolveImportErrors.createNewCopiesEnabled.no': { type: 'long' }, - 'apiCalls.savedObjectsExport.total': { type: 'long' }, - 'apiCalls.savedObjectsExport.namespace.default.total': { type: 'long' }, - 'apiCalls.savedObjectsExport.namespace.default.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsExport.namespace.default.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsExport.namespace.custom.total': { type: 'long' }, - 'apiCalls.savedObjectsExport.namespace.custom.kibanaRequest.yes': { type: 'long' }, - 'apiCalls.savedObjectsExport.namespace.custom.kibanaRequest.no': { type: 'long' }, - 'apiCalls.savedObjectsExport.allTypesSelected.yes': { type: 'long' }, - 'apiCalls.savedObjectsExport.allTypesSelected.no': { type: 'long' }, }, fetch() { return getCoreUsageDataService().getCoreUsageData(); diff --git a/src/plugins/kibana_usage_collection/server/collectors/csp/csp_collector.ts b/src/plugins/kibana_usage_collection/server/collectors/csp/csp_collector.ts index 8119fe394b60c..fa0cd55cd3072 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/csp/csp_collector.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/csp/csp_collector.ts @@ -34,12 +34,15 @@ export function createCspCollector(http: HttpServiceSetup): UsageCollectorOption schema: { strict: { type: 'boolean', + _meta: { description: 'Indicates if strict mode should be used.' }, }, warnLegacyBrowsers: { type: 'boolean', + _meta: { description: 'Indicates if legacy browser versions should be warned.' }, }, rulesChangedFromDefault: { type: 'boolean', + _meta: { description: 'Indicates if the rules have been changed from the default.' }, }, }, }; diff --git a/src/plugins/kibana_usage_collection/server/collectors/kibana/kibana_usage_collector.ts b/src/plugins/kibana_usage_collection/server/collectors/kibana/kibana_usage_collector.ts index 8c1fe31e963d0..d9f4718cdb475 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/kibana/kibana_usage_collector.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/kibana/kibana_usage_collector.ts @@ -24,13 +24,37 @@ export function getKibanaUsageCollector( type: 'kibana', isReady: () => true, schema: { - index: { type: 'keyword' }, - dashboard: { total: { type: 'long' } }, - visualization: { total: { type: 'long' } }, - search: { total: { type: 'long' } }, - index_pattern: { total: { type: 'long' } }, - graph_workspace: { total: { type: 'long' } }, - timelion_sheet: { total: { type: 'long' } }, + index: { type: 'keyword', _meta: { description: 'The index storing the saved objects' } }, + dashboard: { + total: { type: 'long', _meta: { description: 'Total number of dashboard saved objects' } }, + }, + visualization: { + total: { + type: 'long', + _meta: { description: 'Total number of visualization saved objects' }, + }, + }, + search: { + total: { type: 'long', _meta: { description: 'Total number of search saved objects' } }, + }, + index_pattern: { + total: { + type: 'long', + _meta: { description: 'Total number of index_pattern saved objects' }, + }, + }, + graph_workspace: { + total: { + type: 'long', + _meta: { description: 'Total number of graph_workspace saved objects' }, + }, + }, + timelion_sheet: { + total: { + type: 'long', + _meta: { description: 'Total number of timelion_sheet saved objects' }, + }, + }, }, async fetch({ esClient }) { const { diff --git a/src/plugins/kibana_usage_collection/server/collectors/localization/telemetry_localization_collector.ts b/src/plugins/kibana_usage_collection/server/collectors/localization/telemetry_localization_collector.ts index 6ad2fd9270bc7..34ab4a5be7d28 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/localization/telemetry_localization_collector.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/localization/telemetry_localization_collector.ts @@ -53,9 +53,27 @@ export function registerLocalizationUsageCollector( isReady: () => true, fetch: createCollectorFetch(i18n), schema: { - locale: { type: 'keyword' }, - integrities: { DYNAMIC_KEY: { type: 'text' } }, - labelsCount: { type: 'long' }, + locale: { + type: 'keyword', + _meta: { + description: 'The default locale set on the Kibana system', + }, + }, + integrities: { + DYNAMIC_KEY: { + type: 'text', + _meta: { + description: + 'Translation file hash. If the hash is different it indicates that a custom translation file is used', + }, + }, + }, + labelsCount: { + type: 'long', + _meta: { + description: 'The number of translated labels', + }, + }, }, }); diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts index d632c3ad61a80..507eb3e545087 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts @@ -11,120 +11,405 @@ import { UsageStats } from './types'; export const stackManagementSchema: MakeSchemaFrom = { // sensitive - 'timelion:quandl.key': { type: 'keyword' }, - 'securitySolution:defaultIndex': { type: 'keyword' }, - 'securitySolution:newsFeedUrl': { type: 'keyword' }, - 'xpackReporting:customPdfLogo': { type: 'keyword' }, - 'notifications:banner': { type: 'keyword' }, - 'timelion:graphite.url': { type: 'keyword' }, - 'xpackDashboardMode:roles': { type: 'keyword' }, - 'securitySolution:ipReputationLinks': { type: 'keyword' }, + 'timelion:quandl.key': { + type: 'keyword', + _meta: { description: 'Default value of the setting was changed.' }, + }, + 'securitySolution:defaultIndex': { + type: 'keyword', + _meta: { description: 'Default value of the setting was changed.' }, + }, + 'securitySolution:newsFeedUrl': { + type: 'keyword', + _meta: { description: 'Default value of the setting was changed.' }, + }, + 'xpackReporting:customPdfLogo': { + type: 'keyword', + _meta: { description: 'Default value of the setting was changed.' }, + }, + 'notifications:banner': { + type: 'keyword', + _meta: { description: 'Default value of the setting was changed.' }, + }, + 'timelion:graphite.url': { + type: 'keyword', + _meta: { description: 'Default value of the setting changed.' }, + }, + 'xpackDashboardMode:roles': { + type: 'keyword', + _meta: { description: 'Default value of the setting was changed.' }, + }, + 'securitySolution:ipReputationLinks': { + type: 'keyword', + _meta: { description: 'Default value of the setting was changed.' }, + }, // non-sensitive - 'visualize:enableLabs': { type: 'boolean' }, - 'visualization:heatmap:maxBuckets': { type: 'long' }, - 'visualization:colorMapping': { type: 'text' }, - 'visualization:regionmap:showWarnings': { type: 'boolean' }, - 'visualization:dimmingOpacity': { type: 'float' }, - 'visualization:tileMap:maxPrecision': { type: 'long' }, - 'csv:separator': { type: 'keyword' }, - 'visualization:tileMap:WMSdefaults': { type: 'text' }, - 'timelion:target_buckets': { type: 'long' }, - 'timelion:max_buckets': { type: 'long' }, - 'timelion:es.timefield': { type: 'keyword' }, - 'timelion:min_interval': { type: 'keyword' }, - 'timelion:default_rows': { type: 'long' }, - 'timelion:default_columns': { type: 'long' }, - 'timelion:es.default_index': { type: 'keyword' }, - 'timelion:showTutorial': { type: 'boolean' }, - 'securitySolution:timeDefaults': { type: 'keyword' }, - 'securitySolution:defaultAnomalyScore': { type: 'long' }, - 'securitySolution:refreshIntervalDefaults': { type: 'keyword' }, - 'securitySolution:enableNewsFeed': { type: 'boolean' }, - 'search:includeFrozen': { type: 'boolean' }, - 'courier:maxConcurrentShardRequests': { type: 'long' }, - 'courier:batchSearches': { type: 'boolean' }, - 'courier:setRequestPreference': { type: 'keyword' }, - 'courier:customRequestPreference': { type: 'keyword' }, - 'courier:ignoreFilterIfFieldNotInIndex': { type: 'boolean' }, - 'rollups:enableIndexPatterns': { type: 'boolean' }, - 'notifications:lifetime:warning': { type: 'long' }, - 'notifications:lifetime:banner': { type: 'long' }, - 'notifications:lifetime:info': { type: 'long' }, - 'notifications:lifetime:error': { type: 'long' }, - 'doc_table:highlight': { type: 'boolean' }, - 'discover:searchOnPageLoad': { type: 'boolean' }, + 'visualize:enableLabs': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'visualization:heatmap:maxBuckets': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'visualization:colorMapping': { + type: 'text', + _meta: { description: 'Non-default value of setting.' }, + }, + 'visualization:regionmap:showWarnings': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'visualization:dimmingOpacity': { + type: 'float', + _meta: { description: 'Non-default value of setting.' }, + }, + 'visualization:tileMap:maxPrecision': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'csv:separator': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'visualization:tileMap:WMSdefaults': { + type: 'text', + _meta: { description: 'Non-default value of setting.' }, + }, + 'timelion:target_buckets': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'timelion:max_buckets': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'timelion:es.timefield': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'timelion:min_interval': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'timelion:default_rows': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'timelion:default_columns': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'timelion:es.default_index': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'timelion:showTutorial': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'securitySolution:timeDefaults': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'securitySolution:defaultAnomalyScore': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'securitySolution:refreshIntervalDefaults': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'securitySolution:enableNewsFeed': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'search:includeFrozen': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'courier:maxConcurrentShardRequests': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'courier:batchSearches': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'courier:setRequestPreference': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'courier:customRequestPreference': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'courier:ignoreFilterIfFieldNotInIndex': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'rollups:enableIndexPatterns': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'notifications:lifetime:warning': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'notifications:lifetime:banner': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'notifications:lifetime:info': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'notifications:lifetime:error': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'doc_table:highlight': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'discover:searchOnPageLoad': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, // eslint-disable-next-line @typescript-eslint/naming-convention - 'doc_table:hideTimeColumn': { type: 'boolean' }, - 'discover:sampleSize': { type: 'long' }, + 'doc_table:hideTimeColumn': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'discover:sampleSize': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, defaultColumns: { type: 'array', items: { type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, }, }, - 'context:defaultSize': { type: 'long' }, - 'discover:aggs:terms:size': { type: 'long' }, + 'context:defaultSize': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'discover:aggs:terms:size': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, 'context:tieBreakerFields': { type: 'array', items: { type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, }, }, - 'discover:sort:defaultOrder': { type: 'keyword' }, - 'context:step': { type: 'long' }, - 'accessibility:disableAnimations': { type: 'boolean' }, - 'ml:fileDataVisualizerMaxFileSize': { type: 'keyword' }, - 'ml:anomalyDetection:results:enableTimeDefaults': { type: 'boolean' }, - 'ml:anomalyDetection:results:timeDefaults': { type: 'keyword' }, - 'truncate:maxHeight': { type: 'long' }, - 'timepicker:timeDefaults': { type: 'keyword' }, - 'timepicker:refreshIntervalDefaults': { type: 'keyword' }, - 'timepicker:quickRanges': { type: 'keyword' }, - 'theme:version': { type: 'keyword' }, - 'theme:darkMode': { type: 'boolean' }, - 'state:storeInSessionStorage': { type: 'boolean' }, - 'savedObjects:perPage': { type: 'long' }, - 'search:queryLanguage': { type: 'keyword' }, - 'shortDots:enable': { type: 'boolean' }, - 'sort:options': { type: 'keyword' }, - 'savedObjects:listingLimit': { type: 'long' }, - 'query:queryString:options': { type: 'keyword' }, - 'metrics:max_buckets': { type: 'long' }, - 'query:allowLeadingWildcards': { type: 'boolean' }, + 'discover:sort:defaultOrder': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'context:step': { type: 'long', _meta: { description: 'Non-default value of setting.' } }, + 'accessibility:disableAnimations': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'ml:fileDataVisualizerMaxFileSize': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'ml:anomalyDetection:results:enableTimeDefaults': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'ml:anomalyDetection:results:timeDefaults': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'truncate:maxHeight': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'timepicker:timeDefaults': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'timepicker:refreshIntervalDefaults': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'timepicker:quickRanges': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'theme:version': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'theme:darkMode': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'state:storeInSessionStorage': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'savedObjects:perPage': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'search:queryLanguage': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'shortDots:enable': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'sort:options': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'savedObjects:listingLimit': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'query:queryString:options': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'metrics:max_buckets': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'query:allowLeadingWildcards': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, metaFields: { type: 'array', items: { type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, }, }, - 'indexPattern:placeholder': { type: 'keyword' }, - 'histogram:barTarget': { type: 'long' }, - 'histogram:maxBars': { type: 'long' }, - 'format:number:defaultLocale': { type: 'keyword' }, - 'format:percent:defaultPattern': { type: 'keyword' }, - 'format:number:defaultPattern': { type: 'keyword' }, - 'history:limit': { type: 'long' }, - 'format:defaultTypeMap': { type: 'keyword' }, - 'format:currency:defaultPattern': { type: 'keyword' }, - defaultIndex: { type: 'keyword' }, - 'format:bytes:defaultPattern': { type: 'keyword' }, - 'filters:pinnedByDefault': { type: 'boolean' }, - 'filterEditor:suggestValues': { type: 'boolean' }, - 'fields:popularLimit': { type: 'long' }, - dateNanosFormat: { type: 'keyword' }, - defaultRoute: { type: 'keyword' }, - 'dateFormat:tz': { type: 'keyword' }, - 'dateFormat:scaled': { type: 'keyword' }, - 'csv:quoteValues': { type: 'boolean' }, - 'dateFormat:dow': { type: 'keyword' }, - dateFormat: { type: 'keyword' }, - 'autocomplete:useTimeRange': { type: 'boolean' }, - 'search:timeout': { type: 'long' }, - 'visualization:visualize:legacyChartsLibrary': { type: 'boolean' }, - 'doc_table:legacy': { type: 'boolean' }, - 'discover:modifyColumnsOnSwitch': { type: 'boolean' }, - 'discover:searchFieldsFromSource': { type: 'boolean' }, - 'securitySolution:rulesTableRefresh': { type: 'text' }, - 'apm:enableSignificantTerms': { type: 'boolean' }, - 'apm:enableServiceOverview': { type: 'boolean' }, + 'indexPattern:placeholder': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'histogram:barTarget': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'histogram:maxBars': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'format:number:defaultLocale': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'format:percent:defaultPattern': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'format:number:defaultPattern': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'history:limit': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'format:defaultTypeMap': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'format:currency:defaultPattern': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + defaultIndex: { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'format:bytes:defaultPattern': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'filters:pinnedByDefault': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'filterEditor:suggestValues': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'fields:popularLimit': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + dateNanosFormat: { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + defaultRoute: { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'dateFormat:tz': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'dateFormat:scaled': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + 'csv:quoteValues': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'dateFormat:dow': { + type: 'keyword', + _meta: { description: 'Non-default value of setting.' }, + }, + dateFormat: { type: 'keyword', _meta: { description: 'Non-default value of setting.' } }, + 'autocomplete:useTimeRange': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'search:timeout': { + type: 'long', + _meta: { description: 'Non-default value of setting.' }, + }, + 'visualization:visualize:legacyChartsLibrary': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'doc_table:legacy': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'discover:modifyColumnsOnSwitch': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'discover:searchFieldsFromSource': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'securitySolution:rulesTableRefresh': { + type: 'text', + _meta: { description: 'Non-default value of setting.' }, + }, + 'apm:enableSignificantTerms': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, + 'apm:enableServiceOverview': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, }; diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/telemetry_management_collector.ts b/src/plugins/kibana_usage_collection/server/collectors/management/telemetry_management_collector.ts index df53c770603cc..cba5140997f3f 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/telemetry_management_collector.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/telemetry_management_collector.ts @@ -8,9 +8,9 @@ import { IUiSettingsClient } from 'kibana/server'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; -import { stackManagementSchema } from './schema'; import { UsageStats } from './types'; import { REDACTED_KEYWORD } from '../../../common/constants'; +import { stackManagementSchema } from './schema'; export function createCollectorFetch(getUiSettingsClient: () => IUiSettingsClient | undefined) { return async function fetchUsageStats(): Promise { @@ -27,7 +27,6 @@ export function createCollectorFetch(getUiSettingsClient: () => IUiSettingsClien obj[key] = sensitive ? REDACTED_KEYWORD : userValue; return obj; }, {}); - return modifiedEntries; }; } diff --git a/src/plugins/kibana_usage_collection/server/collectors/ops_stats/ops_stats_collector.ts b/src/plugins/kibana_usage_collection/server/collectors/ops_stats/ops_stats_collector.ts index 91ab77d202dbd..7959b67b4f468 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/ops_stats/ops_stats_collector.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/ops_stats/ops_stats_collector.ts @@ -12,7 +12,6 @@ import moment from 'moment'; import { OpsMetrics } from 'kibana/server'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { KIBANA_STATS_TYPE } from '../../../common/constants'; - interface OpsStatsMetrics extends Omit { timestamp: string; response_times: { diff --git a/src/plugins/kibana_usage_collection/server/collectors/ui_counters/register_ui_counters_collector.ts b/src/plugins/kibana_usage_collection/server/collectors/ui_counters/register_ui_counters_collector.ts index c754649b34eb1..dc3fac7382094 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/ui_counters/register_ui_counters_collector.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/ui_counters/register_ui_counters_collector.ts @@ -52,12 +52,27 @@ export function registerUiCountersUsageCollector(usageCollection: UsageCollectio dailyEvents: { type: 'array', items: { - appName: { type: 'keyword' }, - eventName: { type: 'keyword' }, - lastUpdatedAt: { type: 'date' }, - fromTimestamp: { type: 'date' }, - counterType: { type: 'keyword' }, - total: { type: 'integer' }, + appName: { + type: 'keyword', + _meta: { description: 'Name of the app reporting ui counts.' }, + }, + eventName: { + type: 'keyword', + _meta: { description: 'Name of the event that happened.' }, + }, + lastUpdatedAt: { + type: 'date', + _meta: { description: 'Time at which the metric was last updated.' }, + }, + fromTimestamp: { + type: 'date', + _meta: { description: 'Time at which the metric was captured.' }, + }, + counterType: { type: 'keyword', _meta: { description: 'The type of counter used.' } }, + total: { + type: 'integer', + _meta: { description: 'The total number of times the event happened.' }, + }, }, }, }, diff --git a/src/plugins/kibana_usage_collection/server/collectors/ui_metric/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/ui_metric/schema.ts index 6affbf4f54fa9..b64c23a2af289 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/ui_metric/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/ui_metric/schema.ts @@ -12,8 +12,8 @@ import { UIMetricUsage } from './telemetry_ui_metric_collector'; const commonSchema: MakeSchemaFrom[string] = { type: 'array', items: { - key: { type: 'keyword' }, - value: { type: 'long' }, + key: { type: 'keyword', _meta: { description: 'The event that is tracked' } }, + value: { type: 'long', _meta: { description: 'The value of the event' } }, }, }; diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index 566d10182b544..1d0639afcd6c6 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -83,68 +83,128 @@ "dashboards": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -154,68 +214,128 @@ "dev_tools": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -225,68 +345,128 @@ "discover": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -296,68 +476,128 @@ "home": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -367,68 +607,128 @@ "kibana": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -438,68 +738,128 @@ "management": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -509,68 +869,128 @@ "short_url_redirect": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -580,68 +1000,128 @@ "timelion": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -651,68 +1131,128 @@ "visualize": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -722,68 +1262,128 @@ "error": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -793,68 +1393,128 @@ "status": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -864,68 +1524,128 @@ "kibanaOverview": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -935,68 +1655,128 @@ "apm": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -1006,68 +1786,128 @@ "canvas": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -1077,68 +1917,128 @@ "dashboard_mode": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -1148,68 +2048,128 @@ "enterpriseSearch": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -1219,68 +2179,128 @@ "appSearch": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -1290,68 +2310,128 @@ "workplaceSearch": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -1361,68 +2441,128 @@ "graph": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -1432,68 +2572,128 @@ "logs": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -1503,68 +2703,128 @@ "metrics": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -1574,68 +2834,128 @@ "infra": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -1645,68 +2965,128 @@ "fleet": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -1716,68 +3096,128 @@ "ingestManager": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -1787,68 +3227,128 @@ "lens": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -1858,68 +3358,128 @@ "maps": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -1929,68 +3489,128 @@ "ml": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -2000,68 +3620,128 @@ "monitoring": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -2071,68 +3751,128 @@ "observability-overview": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -2142,68 +3882,128 @@ "security_account": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -2213,68 +4013,128 @@ "security_access_agreement": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -2284,68 +4144,128 @@ "security_capture_url": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -2355,68 +4275,128 @@ "security_logged_out": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -2426,68 +4406,128 @@ "security_login": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -2497,68 +4537,128 @@ "security_logout": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -2568,68 +4668,128 @@ "security_overwritten_session": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -2639,68 +4799,128 @@ "securitySolution": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -2710,68 +4930,128 @@ "securitySolution:overview": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -2781,68 +5061,128 @@ "securitySolution:detections": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -2852,68 +5192,128 @@ "securitySolution:hosts": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -2923,68 +5323,128 @@ "securitySolution:network": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -2994,68 +5454,128 @@ "securitySolution:timelines": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -3065,68 +5585,128 @@ "securitySolution:case": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -3136,68 +5716,128 @@ "securitySolution:administration": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -3207,68 +5847,128 @@ "siem": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -3278,68 +5978,128 @@ "space_selector": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -3349,68 +6109,128 @@ "uptime": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -3420,68 +6240,128 @@ "ux": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Always `main`" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } }, "views": { "type": "array", "items": { "properties": { "appId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } }, "viewId": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } }, "clicks_total": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } }, "clicks_7_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } }, "clicks_30_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } }, "clicks_90_days": { - "type": "long" + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } }, "minutes_on_screen_total": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } }, "minutes_on_screen_7_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } }, "minutes_on_screen_30_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } }, "minutes_on_screen_90_days": { - "type": "float" + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } } } } @@ -3497,149 +6377,266 @@ "elasticsearch": { "properties": { "sniffOnStart": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if an attempt should be made to find other Elasticsearch nodes on startup." + } }, "sniffIntervalMs": { - "type": "long" + "type": "long", + "_meta": { + "description": "Time in milliseconds between requests to check Elasticsearch for an updated list of nodes." + } }, "sniffOnConnectionFault": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if the list of Elasticsearch nodes should be updated immediately following a connection fault." + } }, "numberOfHostsConfigured": { - "type": "long" + "type": "long", + "_meta": { + "description": "Number of Elasticsearch instances configured to use for queries." + } }, "requestHeadersWhitelistConfigured": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if Kibana client-side headers to send to Elasticsearch is different to the default value." + } }, "customHeadersConfigured": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if any custom headers have been configured." + } }, "shardTimeoutMs": { - "type": "long" + "type": "long", + "_meta": { + "description": "Time in milliseconds for Elasticsearch to wait for responses from shards." + } }, "requestTimeoutMs": { - "type": "long" + "type": "long", + "_meta": { + "description": "Time in milliseconds to wait for responses from the back end or Elasticsearch." + } }, "pingTimeoutMs": { - "type": "long" + "type": "long", + "_meta": { + "description": "Time in milliseconds to wait for Elasticsearch to respond to pings." + } }, "logQueries": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if queries sent to Elasticsearch should be logged." + } }, "ssl": { "properties": { "verificationMode": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The verification of the server certificate that Kibana receives when making an outbound SSL or TLS connection to Elasticsearch" + } }, "certificateAuthoritiesConfigured": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if any PEM-encoded X.509 certificate authority certificates are configured." + } }, "certificateConfigured": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if a certificate authority is configured." + } }, "keyConfigured": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if a certificate key is configured." + } }, "keystoreConfigured": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if a keystore is configured." + } }, "truststoreConfigured": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if a path to a PKCS#12 trust store is configured." + } }, "alwaysPresentCertificate": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if a client certificate is presented when requested by Elasticsearch." + } } } }, "apiVersion": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Version of the Elasticsearch API used." + } }, "healthCheckDelayMs": { - "type": "long" + "type": "long", + "_meta": { + "description": "The interval in miliseconds between health check requests Kibana sends to the Elasticsearch." + } } } }, "http": { "properties": { "basePathConfigured": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if a base path has been configured." + } }, "maxPayloadInBytes": { - "type": "long" + "type": "long", + "_meta": { + "description": "Maximum payload size in bytes that is allowed." + } }, "rewriteBasePath": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if the base path should be rewritten." + } }, "keepaliveTimeout": { - "type": "long" + "type": "long", + "_meta": { + "description": "How long to keep sockets alive globally in milliseconds." + } }, "socketTimeout": { - "type": "long" + "type": "long", + "_meta": { + "description": "How long to wait before closing inactive sockets in milliseconds." + } }, "compression": { "properties": { "enabled": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if HTTP response compression is enabled." + } }, "referrerWhitelistConfigured": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if any responses should be compressed." + } } } }, "xsrf": { "properties": { "disableProtection": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if protection against xsrf should be disabled." + } }, "allowlistConfigured": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if any http headers have been whitelisted." + } } } }, "requestId": { "properties": { "allowFromAnyIp": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if any http headers have been whitelisted." + } }, "ipAllowlistConfigured": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if a list of specific IPs has been configured." + } } } }, "ssl": { "properties": { "certificateAuthoritiesConfigured": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if ssl certificate authorities have been configured." + } }, "certificateConfigured": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if an ssl certificate is configured." + } }, "cipherSuites": { "type": "array", "items": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The keyword of the cipher suite used." + } } }, "keyConfigured": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if an ssl key has been configured." + } }, "keystoreConfigured": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if an ssl keystore has been configured." + } }, "truststoreConfigured": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if a path to a PKCS#12 trust store is configured." + } }, "redirectHttpFromPortConfigured": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if a port to redirect all http requests has been configured." + } }, "supportedProtocols": { "type": "array", "items": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The version of a supported protocol used." + } } }, "clientAuthentication": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The behavior in Kibana for requesting a certificate from client connections." + } } } } @@ -3650,24 +6647,39 @@ "appendersTypesUsed": { "type": "array", "items": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The type of logging appender confgured." + } } }, "loggersConfiguredCount": { - "type": "long" + "type": "long", + "_meta": { + "description": "The total number of logging appenders configured." + } } } }, "savedObjects": { "properties": { "customIndex": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if the saved objects index is different to the standard internal .kibana index." + } }, "maxImportPayloadBytes": { - "type": "long" + "type": "long", + "_meta": { + "description": "Maximum size of the payload in bytes of saved objects that can be imported." + } }, "maxImportExportSizeBytes": { - "type": "long" + "type": "long", + "_meta": { + "description": "Maximum size in bytes of saved object that can be imported or exported." + } } } } @@ -3678,13 +6690,22 @@ "memory": { "properties": { "heapSizeLimit": { - "type": "long" + "type": "long", + "_meta": { + "description": "Host memory heap size limit." + } }, "heapTotalBytes": { - "type": "long" + "type": "long", + "_meta": { + "description": "Total memory heap size of host that is available in bytes." + } }, "heapUsedBytes": { - "type": "long" + "type": "long", + "_meta": { + "description": "Total memory heap size of host that is used in bytes." + } } } } @@ -3699,19 +6720,34 @@ "items": { "properties": { "docsCount": { - "type": "long" + "type": "long", + "_meta": { + "description": "The number of documents in the index, including hidden nested documents." + } }, "docsDeleted": { - "type": "long" + "type": "long", + "_meta": { + "description": "The number of deleted documents in the index, including hidden nested documents." + } }, "alias": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The alias used to map customized saved object index names to standard index names (.kibana or .kibana_task_manager)." + } }, "primaryStoreSizeBytes": { - "type": "long" + "type": "long", + "_meta": { + "description": "The size in bytes of the index, for primaries only." + } }, "storeSizeBytes": { - "type": "long" + "type": "long", + "_meta": { + "description": "The size in bytes of the index, for primaries and replicas." + } } } } @@ -3721,340 +6757,646 @@ } }, "apiCalls.savedObjectsBulkCreate.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called." + } }, "apiCalls.savedObjectsBulkCreate.namespace.default.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in the Default space." + } }, "apiCalls.savedObjectsBulkCreate.namespace.default.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in the Default space." + } }, "apiCalls.savedObjectsBulkCreate.namespace.default.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in the Default space." + } }, "apiCalls.savedObjectsBulkCreate.namespace.custom.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in a custom space." + } }, "apiCalls.savedObjectsBulkCreate.namespace.custom.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in a custom space." + } }, "apiCalls.savedObjectsBulkCreate.namespace.custom.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in a custom space." + } }, "apiCalls.savedObjectsBulkGet.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called." + } }, "apiCalls.savedObjectsBulkGet.namespace.default.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in the Default space." + } }, "apiCalls.savedObjectsBulkGet.namespace.default.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in the Default space." + } }, "apiCalls.savedObjectsBulkGet.namespace.default.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in the Default space." + } }, "apiCalls.savedObjectsBulkGet.namespace.custom.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in a custom space." + } }, "apiCalls.savedObjectsBulkGet.namespace.custom.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in a custom space." + } }, "apiCalls.savedObjectsBulkGet.namespace.custom.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in a custom space." + } }, "apiCalls.savedObjectsBulkUpdate.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called." + } }, "apiCalls.savedObjectsBulkUpdate.namespace.default.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in the Default space." + } }, "apiCalls.savedObjectsBulkUpdate.namespace.default.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in the Default space." + } }, "apiCalls.savedObjectsBulkUpdate.namespace.default.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in the Default space." + } }, "apiCalls.savedObjectsBulkUpdate.namespace.custom.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in a custom space." + } }, "apiCalls.savedObjectsBulkUpdate.namespace.custom.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in a custom space." + } }, "apiCalls.savedObjectsBulkUpdate.namespace.custom.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in a custom space." + } }, "apiCalls.savedObjectsCreate.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called." + } }, "apiCalls.savedObjectsCreate.namespace.default.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in the Default space." + } }, "apiCalls.savedObjectsCreate.namespace.default.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in the Default space." + } }, "apiCalls.savedObjectsCreate.namespace.default.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in the Default space." + } }, "apiCalls.savedObjectsCreate.namespace.custom.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in a custom space." + } }, "apiCalls.savedObjectsCreate.namespace.custom.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in a custom space." + } }, "apiCalls.savedObjectsCreate.namespace.custom.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in a custom space." + } }, "apiCalls.savedObjectsDelete.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called." + } }, "apiCalls.savedObjectsDelete.namespace.default.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in the Default space." + } }, "apiCalls.savedObjectsDelete.namespace.default.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in the Default space." + } }, "apiCalls.savedObjectsDelete.namespace.default.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in the Default space." + } }, "apiCalls.savedObjectsDelete.namespace.custom.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in a custom space." + } }, "apiCalls.savedObjectsDelete.namespace.custom.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in a custom space." + } }, "apiCalls.savedObjectsDelete.namespace.custom.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in a custom space." + } }, "apiCalls.savedObjectsFind.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called." + } }, "apiCalls.savedObjectsFind.namespace.default.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in the Default space." + } }, "apiCalls.savedObjectsFind.namespace.default.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in the Default space." + } }, "apiCalls.savedObjectsFind.namespace.default.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in the Default space." + } }, "apiCalls.savedObjectsFind.namespace.custom.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in a custom space." + } }, "apiCalls.savedObjectsFind.namespace.custom.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in a custom space." + } }, "apiCalls.savedObjectsFind.namespace.custom.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in a custom space." + } }, "apiCalls.savedObjectsGet.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called." + } }, "apiCalls.savedObjectsGet.namespace.default.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in the Default space." + } }, "apiCalls.savedObjectsGet.namespace.default.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in the Default space." + } }, "apiCalls.savedObjectsGet.namespace.default.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in the Default space." + } }, "apiCalls.savedObjectsGet.namespace.custom.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in a custom space." + } }, "apiCalls.savedObjectsGet.namespace.custom.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in a custom space." + } }, "apiCalls.savedObjectsGet.namespace.custom.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in a custom space." + } }, "apiCalls.savedObjectsResolve.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called." + } }, "apiCalls.savedObjectsResolve.namespace.default.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in the Default space." + } }, "apiCalls.savedObjectsResolve.namespace.default.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in the Default space." + } }, "apiCalls.savedObjectsResolve.namespace.default.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in the Default space." + } }, "apiCalls.savedObjectsResolve.namespace.custom.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in a custom space." + } }, "apiCalls.savedObjectsResolve.namespace.custom.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in a custom space." + } }, "apiCalls.savedObjectsResolve.namespace.custom.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in a custom space." + } }, "apiCalls.savedObjectsUpdate.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called." + } }, "apiCalls.savedObjectsUpdate.namespace.default.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in the Default space." + } }, "apiCalls.savedObjectsUpdate.namespace.default.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in the Default space." + } }, "apiCalls.savedObjectsUpdate.namespace.default.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in the Default space." + } }, "apiCalls.savedObjectsUpdate.namespace.custom.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in a custom space." + } }, "apiCalls.savedObjectsUpdate.namespace.custom.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in a custom space." + } }, "apiCalls.savedObjectsUpdate.namespace.custom.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in a custom space." + } }, "apiCalls.savedObjectsImport.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called." + } }, "apiCalls.savedObjectsImport.namespace.default.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in the Default space." + } }, "apiCalls.savedObjectsImport.namespace.default.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in the Default space." + } }, "apiCalls.savedObjectsImport.namespace.default.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in the Default space." + } }, "apiCalls.savedObjectsImport.namespace.custom.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in a custom space." + } }, "apiCalls.savedObjectsImport.namespace.custom.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in a custom space." + } }, "apiCalls.savedObjectsImport.namespace.custom.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in a custom space." + } }, "apiCalls.savedObjectsImport.createNewCopiesEnabled.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called with the `createNewCopiesEnabled` option." + } }, "apiCalls.savedObjectsImport.createNewCopiesEnabled.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called without the `createNewCopiesEnabled` option." + } }, "apiCalls.savedObjectsImport.overwriteEnabled.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called with the `overwrite` option." + } }, "apiCalls.savedObjectsImport.overwriteEnabled.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called without the `overwrite` option." + } }, "apiCalls.savedObjectsResolveImportErrors.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called." + } }, "apiCalls.savedObjectsResolveImportErrors.namespace.default.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in the Default space." + } }, "apiCalls.savedObjectsResolveImportErrors.namespace.default.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in the Default space." + } }, "apiCalls.savedObjectsResolveImportErrors.namespace.default.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in the Default space." + } }, "apiCalls.savedObjectsResolveImportErrors.namespace.custom.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in a custom space." + } }, "apiCalls.savedObjectsResolveImportErrors.namespace.custom.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in a custom space." + } }, "apiCalls.savedObjectsResolveImportErrors.namespace.custom.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in a custom space." + } }, "apiCalls.savedObjectsResolveImportErrors.createNewCopiesEnabled.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called with the `createNewCopiesEnabled` option." + } }, "apiCalls.savedObjectsResolveImportErrors.createNewCopiesEnabled.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called without the `createNewCopiesEnabled` option." + } }, "apiCalls.savedObjectsExport.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called." + } }, "apiCalls.savedObjectsExport.namespace.default.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in the Default space." + } }, "apiCalls.savedObjectsExport.namespace.default.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in the Default space." + } }, "apiCalls.savedObjectsExport.namespace.default.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in the Default space." + } }, "apiCalls.savedObjectsExport.namespace.custom.total": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called in a custom space." + } }, "apiCalls.savedObjectsExport.namespace.custom.kibanaRequest.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by the Kibana client in a custom space." + } }, "apiCalls.savedObjectsExport.namespace.custom.kibanaRequest.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called by a non-Kibana client in a custom space." + } }, "apiCalls.savedObjectsExport.allTypesSelected.yes": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called with the `createNewCopiesEnabled` option." + } }, "apiCalls.savedObjectsExport.allTypesSelected.no": { - "type": "long" + "type": "long", + "_meta": { + "description": "How many times this API has been called without all types selected." + } } } }, "csp": { "properties": { "strict": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if strict mode should be used." + } }, "warnLegacyBrowsers": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if legacy browser versions should be warned." + } }, "rulesChangedFromDefault": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Indicates if the rules have been changed from the default." + } } } }, "kibana": { "properties": { "index": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The index storing the saved objects" + } }, "dashboard": { "properties": { "total": { - "type": "long" + "type": "long", + "_meta": { + "description": "Total number of dashboard saved objects" + } } } }, "visualization": { "properties": { "total": { - "type": "long" + "type": "long", + "_meta": { + "description": "Total number of visualization saved objects" + } } } }, "search": { "properties": { "total": { - "type": "long" + "type": "long", + "_meta": { + "description": "Total number of search saved objects" + } } } }, "index_pattern": { "properties": { "total": { - "type": "long" + "type": "long", + "_meta": { + "description": "Total number of index_pattern saved objects" + } } } }, "graph_workspace": { "properties": { "total": { - "type": "long" + "type": "long", + "_meta": { + "description": "Total number of graph_workspace saved objects" + } } } }, "timelion_sheet": { "properties": { "total": { - "type": "long" + "type": "long", + "_meta": { + "description": "Total number of timelion_sheet saved objects" + } } } } @@ -4063,327 +7405,633 @@ "localization": { "properties": { "locale": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The default locale set on the Kibana system" + } }, "integrities": { "properties": { "DYNAMIC_KEY": { - "type": "text" + "type": "text", + "_meta": { + "description": "Translation file hash. If the hash is different it indicates that a custom translation file is used" + } } } }, "labelsCount": { - "type": "long" + "type": "long", + "_meta": { + "description": "The number of translated labels" + } } } }, "stack_management": { "properties": { "timelion:quandl.key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Default value of the setting was changed." + } }, "securitySolution:defaultIndex": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Default value of the setting was changed." + } }, "securitySolution:newsFeedUrl": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Default value of the setting was changed." + } }, "xpackReporting:customPdfLogo": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Default value of the setting was changed." + } }, "notifications:banner": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Default value of the setting was changed." + } }, "timelion:graphite.url": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Default value of the setting changed." + } }, "xpackDashboardMode:roles": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Default value of the setting was changed." + } }, "securitySolution:ipReputationLinks": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Default value of the setting was changed." + } }, "visualize:enableLabs": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "visualization:heatmap:maxBuckets": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "visualization:colorMapping": { - "type": "text" + "type": "text", + "_meta": { + "description": "Non-default value of setting." + } }, "visualization:regionmap:showWarnings": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "visualization:dimmingOpacity": { - "type": "float" + "type": "float", + "_meta": { + "description": "Non-default value of setting." + } }, "visualization:tileMap:maxPrecision": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "csv:separator": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "visualization:tileMap:WMSdefaults": { - "type": "text" + "type": "text", + "_meta": { + "description": "Non-default value of setting." + } }, "timelion:target_buckets": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "timelion:max_buckets": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "timelion:es.timefield": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "timelion:min_interval": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "timelion:default_rows": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "timelion:default_columns": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "timelion:es.default_index": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "timelion:showTutorial": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "securitySolution:timeDefaults": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "securitySolution:defaultAnomalyScore": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "securitySolution:refreshIntervalDefaults": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "securitySolution:enableNewsFeed": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "search:includeFrozen": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "courier:maxConcurrentShardRequests": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "courier:batchSearches": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "courier:setRequestPreference": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "courier:customRequestPreference": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "courier:ignoreFilterIfFieldNotInIndex": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "rollups:enableIndexPatterns": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "notifications:lifetime:warning": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "notifications:lifetime:banner": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "notifications:lifetime:info": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "notifications:lifetime:error": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "doc_table:highlight": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "discover:searchOnPageLoad": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "doc_table:hideTimeColumn": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "discover:sampleSize": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "defaultColumns": { "type": "array", "items": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } } }, "context:defaultSize": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "discover:aggs:terms:size": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "context:tieBreakerFields": { "type": "array", "items": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } } }, "discover:sort:defaultOrder": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "context:step": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "accessibility:disableAnimations": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "ml:fileDataVisualizerMaxFileSize": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "ml:anomalyDetection:results:enableTimeDefaults": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "ml:anomalyDetection:results:timeDefaults": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "truncate:maxHeight": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "timepicker:timeDefaults": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "timepicker:refreshIntervalDefaults": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "timepicker:quickRanges": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "theme:version": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "theme:darkMode": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "state:storeInSessionStorage": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "savedObjects:perPage": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "search:queryLanguage": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "shortDots:enable": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "sort:options": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "savedObjects:listingLimit": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "query:queryString:options": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "metrics:max_buckets": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "query:allowLeadingWildcards": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "metaFields": { "type": "array", "items": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } } }, "indexPattern:placeholder": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "histogram:barTarget": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "histogram:maxBars": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "format:number:defaultLocale": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "format:percent:defaultPattern": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "format:number:defaultPattern": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "history:limit": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "format:defaultTypeMap": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "format:currency:defaultPattern": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "defaultIndex": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "format:bytes:defaultPattern": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "filters:pinnedByDefault": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "filterEditor:suggestValues": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "fields:popularLimit": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "dateNanosFormat": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "defaultRoute": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "dateFormat:tz": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "dateFormat:scaled": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "csv:quoteValues": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "dateFormat:dow": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "dateFormat": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Non-default value of setting." + } }, "autocomplete:useTimeRange": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "search:timeout": { - "type": "long" + "type": "long", + "_meta": { + "description": "Non-default value of setting." + } }, "visualization:visualize:legacyChartsLibrary": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "doc_table:legacy": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "discover:modifyColumnsOnSwitch": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "discover:searchFieldsFromSource": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "securitySolution:rulesTableRefresh": { - "type": "text" + "type": "text", + "_meta": { + "description": "Non-default value of setting." + } }, "apm:enableSignificantTerms": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } }, "apm:enableServiceOverview": { - "type": "boolean" + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } } } }, @@ -4394,22 +8042,40 @@ "items": { "properties": { "appName": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Name of the app reporting ui counts." + } }, "eventName": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Name of the event that happened." + } }, "lastUpdatedAt": { - "type": "date" + "type": "date", + "_meta": { + "description": "Time at which the metric was last updated." + } }, "fromTimestamp": { - "type": "date" + "type": "date", + "_meta": { + "description": "Time at which the metric was captured." + } }, "counterType": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The type of counter used." + } }, "total": { - "type": "integer" + "type": "integer", + "_meta": { + "description": "The total number of times the event happened." + } } } } @@ -4423,10 +8089,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4436,10 +8108,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4449,10 +8127,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4462,10 +8146,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4475,10 +8165,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4488,10 +8184,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4501,10 +8203,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4514,10 +8222,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4527,10 +8241,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4540,10 +8260,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4553,10 +8279,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4566,10 +8298,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4579,10 +8317,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4592,10 +8336,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4605,10 +8355,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4618,10 +8374,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4631,10 +8393,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4644,10 +8412,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4657,10 +8431,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4670,10 +8450,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4683,10 +8469,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4696,10 +8488,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4709,10 +8507,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4722,10 +8526,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4735,10 +8545,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4748,10 +8564,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4761,10 +8583,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4774,10 +8602,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4787,10 +8621,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4800,10 +8640,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4813,10 +8659,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4826,10 +8678,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4839,10 +8697,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4852,10 +8716,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4865,10 +8735,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4878,10 +8754,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4891,10 +8773,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4904,10 +8792,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4917,10 +8811,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4930,10 +8830,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4943,10 +8849,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4956,10 +8868,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4969,10 +8887,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4982,10 +8906,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -4995,10 +8925,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -5008,10 +8944,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -5021,10 +8963,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -5034,10 +8982,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -5047,10 +9001,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -5060,10 +9020,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -5073,10 +9039,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -5086,10 +9058,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -5099,10 +9077,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -5112,10 +9096,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -5125,10 +9115,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -5138,10 +9134,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } @@ -5151,10 +9153,16 @@ "items": { "properties": { "key": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The event that is tracked" + } }, "value": { - "type": "long" + "type": "long", + "_meta": { + "description": "The value of the event" + } } } } diff --git a/src/plugins/usage_collection/README.mdx b/src/plugins/usage_collection/README.mdx index 07ead377bf396..9516ff656f460 100644 --- a/src/plugins/usage_collection/README.mdx +++ b/src/plugins/usage_collection/README.mdx @@ -205,11 +205,23 @@ In the case of using a custom ES or SavedObjects client, it is up to the plugin ##### Schema Field -The `schema` field is a proscribed data model assists with detecting changes in usage collector payloads. To define the collector schema add a schema field that specifies every possible field reported (including optional fields) when registering the collector. Whenever the `schema` field is set or changed please run `node scripts/telemetry_check.js --fix` to update the stored schema json files. +The `schema` field is a proscribed data model assists with detecting changes in usage collector payloads. To define the collector schema add a schema field that specifies every possible field reported (including optional fields) when registering the collector. The schema supports descriptions as simple strings that allow developers to document what the data represents. The `_meta` field only supports a description property. +``` +schema: { + my_greeting: { + type: 'keyword', + _meta: { + description: 'The greeting keyword', + } + } +} +``` + +Whenever the `schema` field is set or changed please run `node scripts/telemetry_check.js --fix` to update the stored schema json files. ###### Allowed Schema Types -The `AllowedSchemaTypes` is the list of allowed schema types for the usage fields getting reported: +The `AllowedSchemaTypes` is the list of allowed schema types for the usage fields getting reported by the `fetch` method: ``` 'long', 'integer', 'short', 'byte', 'double', 'float', 'keyword', 'text', 'boolean', 'date' diff --git a/src/plugins/usage_collection/server/collector/collector.test.ts b/src/plugins/usage_collection/server/collector/collector.test.ts index 49c2ac18c7c52..fa3966f4f2d3c 100644 --- a/src/plugins/usage_collection/server/collector/collector.test.ts +++ b/src/plugins/usage_collection/server/collector/collector.test.ts @@ -167,5 +167,44 @@ describe('collector', () => { }); expect(collector).toBeDefined(); }); + + test('TS allows _meta.descriptions in schema', () => { + const collector = new Collector(logger, { + type: 'my_test_collector_with_description', + isReady: () => false, + fetch: () => ({ testPass: 100 }), + schema: { + testPass: { type: 'long' }, + _meta: { description: 'Count of testPass as number' }, + }, + }); + expect(collector).toBeDefined(); + }); + + test('schema allows _meta as a data field', () => { + const collector = new Collector(logger, { + type: 'my_test_collector_with_meta_field', + isReady: () => false, + fetch: () => ({ testPass: 100, _meta: 'metaData' }), + schema: { + testPass: { type: 'long' }, + _meta: { type: 'keyword' }, + }, + }); + expect(collector).toBeDefined(); + }); + + test('schema allows _meta as a data field that has a description', () => { + const collector = new Collector(logger, { + type: 'my_test_collector_with_meta_field', + isReady: () => false, + fetch: () => ({ testPass: 100, _meta: 'metaData' }), + schema: { + testPass: { type: 'long' }, + _meta: { type: 'keyword', _meta: { description: '_meta data as a keyword' } }, + }, + }); + expect(collector).toBeDefined(); + }); }); }); diff --git a/src/plugins/usage_collection/server/collector/collector.ts b/src/plugins/usage_collection/server/collector/collector.ts index 5f189479decfe..8e114df440cbe 100644 --- a/src/plugins/usage_collection/server/collector/collector.ts +++ b/src/plugins/usage_collection/server/collector/collector.ts @@ -45,7 +45,7 @@ export type PossibleSchemaTypes = U extends string export type RecursiveMakeSchemaFrom = U extends object ? MakeSchemaFrom - : { type: PossibleSchemaTypes }; + : { type: PossibleSchemaTypes; _meta?: { description: string } }; // Using Required to enforce all optional keys in the object export type MakeSchemaFrom = { diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 527fb0fc040ae..4a0ab555f8f40 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -1667,6 +1667,19 @@ } } }, + "search-session": { + "properties": { + "transientCount": { + "type": "long" + }, + "persistedCount": { + "type": "long" + }, + "totalCount": { + "type": "long" + } + } + }, "discoverEnhanced": { "properties": { "exploreDataInChartActionEnabled": { @@ -3194,19 +3207,6 @@ } } }, - "search-session": { - "properties": { - "transientCount": { - "type": "long" - }, - "persistedCount": { - "type": "long" - }, - "totalCount": { - "type": "long" - } - } - }, "security_solution": { "properties": { "detections": { From d30be3f1003c6a7d2592ad63fb6258d67c6acff0 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Tue, 2 Mar 2021 21:56:42 +0300 Subject: [PATCH 15/33] [code coverage] run more functional tests (#93249) --- x-pack/scripts/functional_tests.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/scripts/functional_tests.js b/x-pack/scripts/functional_tests.js index d821f5417a4bd..1be511b0cbb5b 100644 --- a/x-pack/scripts/functional_tests.js +++ b/x-pack/scripts/functional_tests.js @@ -18,6 +18,10 @@ const alwaysImportedTests = [ require.resolve('../test/functional_embedded/config.ts'), require.resolve('../test/functional_cors/config.ts'), require.resolve('../test/functional_enterprise_search/without_host_configured.config.ts'), + require.resolve('../test/functional_vis_wizard/config.ts'), + require.resolve('../test/saved_object_tagging/functional/config.ts'), + require.resolve('../test/usage_collection/config.ts'), + require.resolve('../test/fleet_functional/config.ts'), ]; const onlyNotInCoverageTests = [ require.resolve('../test/api_integration/config_security_basic.ts'), @@ -69,13 +73,9 @@ const onlyNotInCoverageTests = [ require.resolve('../test/reporting_api_integration/reporting_without_security.config.ts'), require.resolve('../test/security_solution_endpoint_api_int/config.ts'), require.resolve('../test/fleet_api_integration/config.ts'), - require.resolve('../test/functional_vis_wizard/config.ts'), require.resolve('../test/send_search_to_background_integration/config.ts'), - require.resolve('../test/saved_object_tagging/functional/config.ts'), require.resolve('../test/saved_object_tagging/api_integration/security_and_spaces/config.ts'), require.resolve('../test/saved_object_tagging/api_integration/tagging_api/config.ts'), - require.resolve('../test/usage_collection/config.ts'), - require.resolve('../test/fleet_functional/config.ts'), ]; require('../../src/setup_node_env'); From 8bcec147274f17cf5dc24d3d45906f31c68a0e39 Mon Sep 17 00:00:00 2001 From: Stacey Gammon Date: Tue, 2 Mar 2021 14:00:32 -0500 Subject: [PATCH 16/33] update plugin list (#93259) --- docs/developer/plugin-list.asciidoc | 2 ++ .../src/plugin_list/generate_plugin_list.ts | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index a2068b5b53b6d..7cedd56badb71 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -29,6 +29,8 @@ as uiSettings within the code. |{kib-repo}blob/{branch}/src/plugins/apm_oss/README.asciidoc[apmOss] +|undefined + |{kib-repo}blob/{branch}/src/plugins/bfetch/README.md[bfetch] |bfetch allows to batch HTTP requests and streams responses back. diff --git a/packages/kbn-dev-utils/src/plugin_list/generate_plugin_list.ts b/packages/kbn-dev-utils/src/plugin_list/generate_plugin_list.ts index faf6dd289cc28..127e2a9904a4f 100644 --- a/packages/kbn-dev-utils/src/plugin_list/generate_plugin_list.ts +++ b/packages/kbn-dev-utils/src/plugin_list/generate_plugin_list.ts @@ -28,10 +28,11 @@ function* printPlugins(plugins: Plugins, includes: string[]) { yield `|{kib-repo}blob/{branch}/${path}[${plugin.id}]`; } - if (!plugin.relativeReadmePath || plugin.readmeSnippet) { - yield plugin.readmeSnippet ? `|${plugin.readmeSnippet}` : '|WARNING: Missing README.'; - yield ''; - } + yield plugin.relativeReadmePath === undefined + ? '|WARNING: Missing README.' + : `|${plugin.readmeSnippet}`; + + yield ''; } } From 3f5473ef7d5e1357a66769ccc308b1e66e3a7377 Mon Sep 17 00:00:00 2001 From: Oliver Gupte Date: Tue, 2 Mar 2021 14:20:30 -0500 Subject: [PATCH 17/33] [APM] Fixes duplicate ML job creation for existing environments (#85023) (#93098) * [APM] Fixes duplicate ML job creation for existing environments (#85023) * Removes commented out test code. * Adds API integration tests * clean up code for readability --- .../create_anomaly_detection_jobs.ts | 31 +++++++++++++++++-- .../routes/settings/anomaly_detection.ts | 1 + .../settings/anomaly_detection/write_user.ts | 22 ++++++++++++- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/apm/server/lib/anomaly_detection/create_anomaly_detection_jobs.ts b/x-pack/plugins/apm/server/lib/anomaly_detection/create_anomaly_detection_jobs.ts index dd36e7cbeb24e..d93514c42bbdd 100644 --- a/x-pack/plugins/apm/server/lib/anomaly_detection/create_anomaly_detection_jobs.ts +++ b/x-pack/plugins/apm/server/lib/anomaly_detection/create_anomaly_detection_jobs.ts @@ -19,6 +19,7 @@ import { } from '../../../common/elasticsearch_fieldnames'; import { APM_ML_JOB_GROUP, ML_MODULE_ID_APM_TRANSACTION } from './constants'; import { withApmSpan } from '../../utils/with_apm_span'; +import { getAnomalyDetectionJobs } from './get_anomaly_detection_jobs'; export async function createAnomalyDetectionJobs( setup: Setup, @@ -38,14 +39,19 @@ export async function createAnomalyDetectionJobs( throw Boom.forbidden(ML_ERRORS.ML_NOT_AVAILABLE_IN_SPACE); } + const uniqueMlJobEnvs = await getUniqueMlJobEnvs(setup, environments, logger); + if (uniqueMlJobEnvs.length === 0) { + return []; + } + return withApmSpan('create_anomaly_detection_jobs', async () => { logger.info( - `Creating ML anomaly detection jobs for environments: [${environments}].` + `Creating ML anomaly detection jobs for environments: [${uniqueMlJobEnvs}].` ); const indexPatternName = indices['apm_oss.transactionIndices']; const responses = await Promise.all( - environments.map((environment) => + uniqueMlJobEnvs.map((environment) => createAnomalyDetectionJob({ ml, environment, indexPatternName }) ) ); @@ -105,3 +111,24 @@ async function createAnomalyDetectionJob({ }); }); } + +async function getUniqueMlJobEnvs( + setup: Setup, + environments: string[], + logger: Logger +) { + // skip creation of duplicate ML jobs + const jobs = await getAnomalyDetectionJobs(setup, logger); + const existingMlJobEnvs = jobs.map(({ environment }) => environment); + const requestedExistingMlJobEnvs = environments.filter((env) => + existingMlJobEnvs.includes(env) + ); + + if (requestedExistingMlJobEnvs.length) { + logger.warn( + `Skipping creation of existing ML jobs for environments: [${requestedExistingMlJobEnvs}]}` + ); + } + + return environments.filter((env) => !existingMlJobEnvs.includes(env)); +} diff --git a/x-pack/plugins/apm/server/routes/settings/anomaly_detection.ts b/x-pack/plugins/apm/server/routes/settings/anomaly_detection.ts index 25afb11f26459..e5922d9ed3e94 100644 --- a/x-pack/plugins/apm/server/routes/settings/anomaly_detection.ts +++ b/x-pack/plugins/apm/server/routes/settings/anomaly_detection.ts @@ -66,6 +66,7 @@ export const createAnomalyDetectionJobsRoute = createRoute({ } await createAnomalyDetectionJobs(setup, environments, context.logger); + notifyFeatureUsage({ licensingPlugin: context.licensing, featureName: 'ml', diff --git a/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/write_user.ts b/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/write_user.ts index a17804c46d21a..83ff51ec1b4c2 100644 --- a/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/write_user.ts +++ b/x-pack/test/apm_api_integration/tests/settings/anomaly_detection/write_user.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { countBy } from 'lodash'; import { registry } from '../../../common/registry'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; @@ -49,7 +50,26 @@ export default function apiTest({ getService }: FtrProviderContext) { const { body } = await getJobs(); expect(body.hasLegacyJobs).to.be(false); - expect(body.jobs.map((job: any) => job.environment)).to.eql(['production', 'staging']); + expect(countBy(body.jobs, 'environment')).to.eql({ + production: 1, + staging: 1, + }); + }); + + describe('with existing ML jobs', () => { + before(async () => { + await createJobs(['production', 'staging']); + }); + it('skips duplicate job creation', async () => { + await createJobs(['production', 'test']); + + const { body } = await getJobs(); + expect(countBy(body.jobs, 'environment')).to.eql({ + production: 1, + staging: 1, + test: 1, + }); + }); }); }); }); From fd3b3eb8cdcff005f7c20dbb3a23de77853c199a Mon Sep 17 00:00:00 2001 From: Constance Date: Tue, 2 Mar 2021 11:25:01 -0800 Subject: [PATCH 18/33] [App Search] Refactor AppLogic to initialize data via props rather than action (#92841) * [Misc cleanup] Move Access type to common - it was being duplicated in server/check_access and InitialAppData + add mock access data to DEFAULT_INITIAL_APP_DATA + update server/ tests to account for access in DEFAULT_INITIAL_APP_DATA * Update AppSearchConfigured to pass props to AppLogic vs calling initializeAppData + update tests to rerender a wrapper rather than doing {...DEFAULT_INITIAL_APP_DATA} repeatedly * Update AppLogic to set values from props rather than a listener - main goal of this PR is to prevent the flash of state between mount and initializeX being called - note: I recommend turning off whitespace changes in the test file * Update AppLogic typing so that app data is always expected - which it should be in any case in a production environment - note: I could have changed InitialAppData to remove the ? optional notation, but decided on this route instead since InitialAppData affects more than just App Search (e.g. server, WS), and I didn't want this to have potential far-reaching side effects * Update type scenarios where AppLogic values were previously thought potentially undefined - which is mostly just configuredLimits it looks like * [PR feedback] Type name --- .../common/__mocks__/initial_app_data.ts | 4 + .../enterprise_search/common/types/index.ts | 10 +- .../applications/app_search/app_logic.test.ts | 96 +++++++++---------- .../applications/app_search/app_logic.ts | 38 ++------ .../paste_json_text.tsx | 7 +- .../upload_json_file.tsx | 7 +- .../meta_engine_creation.tsx | 2 +- .../applications/app_search/index.test.tsx | 51 ++++------ .../public/applications/app_search/index.tsx | 20 ++-- .../server/lib/check_access.ts | 7 +- .../lib/enterprise_search_config_api.test.ts | 2 +- .../lib/enterprise_search_config_api.ts | 3 - .../enterprise_search/config_data.test.ts | 6 +- 13 files changed, 106 insertions(+), 147 deletions(-) diff --git a/x-pack/plugins/enterprise_search/common/__mocks__/initial_app_data.ts b/x-pack/plugins/enterprise_search/common/__mocks__/initial_app_data.ts index ef5d3954d3ef9..7ea4289b21967 100644 --- a/x-pack/plugins/enterprise_search/common/__mocks__/initial_app_data.ts +++ b/x-pack/plugins/enterprise_search/common/__mocks__/initial_app_data.ts @@ -23,6 +23,10 @@ export const DEFAULT_INITIAL_APP_DATA = { }, }, }, + access: { + hasAppSearchAccess: true, + hasWorkplaceSearchAccess: true, + }, appSearch: { accountId: 'some-id-string', onboardingComplete: true, diff --git a/x-pack/plugins/enterprise_search/common/types/index.ts b/x-pack/plugins/enterprise_search/common/types/index.ts index 12260772b5e73..68904483720f2 100644 --- a/x-pack/plugins/enterprise_search/common/types/index.ts +++ b/x-pack/plugins/enterprise_search/common/types/index.ts @@ -19,10 +19,7 @@ export interface InitialAppData { ilmEnabled?: boolean; isFederatedAuth?: boolean; configuredLimits?: ConfiguredLimits; - access?: { - hasAppSearchAccess: boolean; - hasWorkplaceSearchAccess: boolean; - }; + access?: ProductAccess; appSearch?: AppSearchAccount; workplaceSearch?: WorkplaceSearchInitialData; } @@ -32,6 +29,11 @@ export interface ConfiguredLimits { workplaceSearch: WorkplaceSearchConfiguredLimits; } +export interface ProductAccess { + hasAppSearchAccess: boolean; + hasWorkplaceSearchAccess: boolean; +} + export interface MetaPage { current: number; size: number; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.test.ts index e5b0a702897bf..920dfbf5f25de 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.test.ts @@ -6,74 +6,68 @@ */ import { DEFAULT_INITIAL_APP_DATA } from '../../../common/__mocks__'; -import { LogicMounter } from '../__mocks__'; + +import { resetContext } from 'kea'; import { AppLogic } from './app_logic'; describe('AppLogic', () => { - const { mount } = new LogicMounter(AppLogic); - - beforeEach(() => { - mount(); - }); - - const DEFAULT_VALUES = { - hasInitialized: false, - account: {}, - configuredLimits: {}, - ilmEnabled: false, - myRole: {}, + const mount = (props = {}) => { + AppLogic({ ...DEFAULT_INITIAL_APP_DATA, ...props }); + AppLogic.mount(); }; - it('has expected default values', () => { - expect(AppLogic.values).toEqual(DEFAULT_VALUES); + beforeEach(() => { + jest.clearAllMocks(); + resetContext({}); }); - describe('initializeAppData()', () => { - it('sets values based on passed props', () => { - AppLogic.actions.initializeAppData(DEFAULT_INITIAL_APP_DATA); + it('sets values from props', () => { + mount(); - expect(AppLogic.values).toEqual({ - hasInitialized: true, - ilmEnabled: true, - configuredLimits: { - engine: { - maxDocumentByteSize: 102400, - maxEnginesPerMetaEngine: 15, - }, - }, - account: { - accountId: 'some-id-string', - onboardingComplete: true, - role: DEFAULT_INITIAL_APP_DATA.appSearch.role, + expect(AppLogic.values).toEqual({ + ilmEnabled: true, + configuredLimits: { + engine: { + maxDocumentByteSize: 102400, + maxEnginesPerMetaEngine: 15, }, - myRole: expect.objectContaining({ - id: 'account_id:somestring|user_oid:somestring', - roleType: 'owner', - availableRoleTypes: ['owner', 'admin'], - credentialTypes: ['admin', 'private', 'search'], - canAccessAllEngines: true, - canViewAccountCredentials: true, - // Truncated for brevity - see utils/role/index.test.ts for full output - }), - }); + }, + account: { + accountId: 'some-id-string', + onboardingComplete: true, + role: DEFAULT_INITIAL_APP_DATA.appSearch.role, + }, + myRole: expect.objectContaining({ + id: 'account_id:somestring|user_oid:somestring', + roleType: 'owner', + availableRoleTypes: ['owner', 'admin'], + credentialTypes: ['admin', 'private', 'search'], + canAccessAllEngines: true, + canViewAccountCredentials: true, + // Truncated for brevity - see utils/role/index.test.ts for full output + }), }); + }); - it('gracefully handles missing initial data', () => { - AppLogic.actions.initializeAppData({}); + describe('actions', () => { + describe('setOnboardingComplete()', () => { + it('sets true', () => { + mount({ appSearch: { onboardingComplete: false } }); - expect(AppLogic.values).toEqual({ - ...DEFAULT_VALUES, - hasInitialized: true, + AppLogic.actions.setOnboardingComplete(); + expect(AppLogic.values.account.onboardingComplete).toEqual(true); }); }); }); - describe('setOnboardingComplete()', () => { - it('sets true', () => { - expect(AppLogic.values.account.onboardingComplete).toBeFalsy(); - AppLogic.actions.setOnboardingComplete(); - expect(AppLogic.values.account.onboardingComplete).toEqual(true); + describe('selectors', () => { + describe('myRole', () => { + it('falls back to an empty object if role is missing', () => { + mount({ appSearch: {} }); + + expect(AppLogic.values.myRole).toEqual({}); + }); }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.ts index c33a0e89d2aee..44416b596e6ef 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.ts @@ -14,53 +14,33 @@ import { ConfiguredLimits, Account, Role } from './types'; import { getRoleAbilities } from './utils/role'; interface AppValues { - hasInitialized: boolean; ilmEnabled: boolean; - configuredLimits: Partial; - account: Partial; - myRole: Partial; + configuredLimits: ConfiguredLimits; + account: Account; + myRole: Role; } interface AppActions { - initializeAppData(props: InitialAppData): Required; setOnboardingComplete(): boolean; } -export const AppLogic = kea>({ +export const AppLogic = kea>>({ path: ['enterprise_search', 'app_search', 'app_logic'], actions: { - initializeAppData: (props) => props, setOnboardingComplete: () => true, }, - reducers: { - hasInitialized: [ - false, - { - initializeAppData: () => true, - }, - ], + reducers: ({ props }) => ({ account: [ - {}, + props.appSearch, { - initializeAppData: (_, { appSearch: account }) => account || {}, setOnboardingComplete: (account) => ({ ...account, onboardingComplete: true, }), }, ], - configuredLimits: [ - {}, - { - initializeAppData: (_, { configuredLimits }) => configuredLimits?.appSearch || {}, - }, - ], - ilmEnabled: [ - false, - { - initializeAppData: (_, { ilmEnabled }) => !!ilmEnabled, - }, - ], - }, + configuredLimits: [props.configuredLimits.appSearch, {}], + ilmEnabled: [props.ilmEnabled, {}], + }), selectors: { myRole: [ (selectors) => [selectors.account], diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/paste_json_text.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/paste_json_text.tsx index 2d4a6de26333f..a52a55569e4a2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/paste_json_text.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/paste_json_text.tsx @@ -55,8 +55,11 @@ export const FlyoutHeader: React.FC = () => { }; export const FlyoutBody: React.FC = () => { - const { configuredLimits } = useValues(AppLogic); - const maxDocumentByteSize = configuredLimits?.engine?.maxDocumentByteSize; + const { + configuredLimits: { + engine: { maxDocumentByteSize }, + }, + } = useValues(AppLogic); const { textInput, errors } = useValues(DocumentCreationLogic); const { setTextInput } = useActions(DocumentCreationLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/upload_json_file.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/upload_json_file.tsx index 5d50ae55fcd10..5fb439715a60c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/upload_json_file.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/upload_json_file.tsx @@ -54,8 +54,11 @@ export const FlyoutHeader: React.FC = () => { }; export const FlyoutBody: React.FC = () => { - const { configuredLimits } = useValues(AppLogic); - const maxDocumentByteSize = configuredLimits?.engine?.maxDocumentByteSize; + const { + configuredLimits: { + engine: { maxDocumentByteSize }, + }, + } = useValues(AppLogic); const { isUploading, errors } = useValues(DocumentCreationLogic); const { setFileInput } = useActions(DocumentCreationLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.tsx index 3757bbb533e57..d701ee37a1658 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.tsx @@ -56,7 +56,7 @@ const comboBoxOptionToEngineName = (option: EuiComboBoxOptionOption): st export const MetaEngineCreation: React.FC = () => { const { configuredLimits: { - engine: { maxEnginesPerMetaEngine } = { maxEnginesPerMetaEngine: Infinity }, + engine: { maxEnginesPerMetaEngine }, }, } = useValues(AppLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx index a1c845a10a47c..6827f4f5e827d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx @@ -5,18 +5,21 @@ * 2.0. */ -import '../__mocks__/shallow_useeffect.mock'; +import { DEFAULT_INITIAL_APP_DATA } from '../../../common/__mocks__'; import '../__mocks__/enterprise_search_url.mock'; -import { setMockValues, setMockActions } from '../__mocks__'; +import { setMockValues, rerender } from '../__mocks__'; import React from 'react'; import { Redirect } from 'react-router-dom'; -import { shallow } from 'enzyme'; +import { shallow, ShallowWrapper } from 'enzyme'; import { Layout, SideNav, SideNavLink } from '../shared/layout'; +jest.mock('./app_logic', () => ({ AppLogic: jest.fn() })); +import { AppLogic } from './app_logic'; + import { EngineRouter } from './components/engine'; import { EngineCreation } from './components/engine_creation'; import { EnginesOverview } from './components/engines'; @@ -52,52 +55,34 @@ describe('AppSearchUnconfigured', () => { }); describe('AppSearchConfigured', () => { - beforeEach(() => { - // Mock resets + let wrapper: ShallowWrapper; + + beforeAll(() => { setMockValues({ myRole: {} }); - setMockActions({ initializeAppData: () => {} }); + wrapper = shallow(); }); it('renders with layout', () => { - const wrapper = shallow(); - expect(wrapper.find(Layout)).toHaveLength(2); expect(wrapper.find(Layout).last().prop('readOnlyMode')).toBeFalsy(); expect(wrapper.find(EnginesOverview)).toHaveLength(1); expect(wrapper.find(EngineRouter)).toHaveLength(1); }); - it('initializes app data with passed props', () => { - const initializeAppData = jest.fn(); - setMockActions({ initializeAppData }); - - shallow(); - - expect(initializeAppData).toHaveBeenCalledWith({ ilmEnabled: true }); - }); - - it('does not re-initialize app data', () => { - const initializeAppData = jest.fn(); - setMockActions({ initializeAppData }); - setMockValues({ myRole: {}, hasInitialized: true }); - - shallow(); - - expect(initializeAppData).not.toHaveBeenCalled(); + it('mounts AppLogic with passed initial data props', () => { + expect(AppLogic).toHaveBeenCalledWith(DEFAULT_INITIAL_APP_DATA); }); it('renders ErrorConnecting', () => { setMockValues({ myRole: {}, errorConnecting: true }); - - const wrapper = shallow(); + rerender(wrapper); expect(wrapper.find(ErrorConnecting)).toHaveLength(1); }); it('passes readOnlyMode state', () => { setMockValues({ myRole: {}, readOnlyMode: true }); - - const wrapper = shallow(); + rerender(wrapper); expect(wrapper.find(Layout).first().prop('readOnlyMode')).toEqual(true); }); @@ -106,14 +91,14 @@ describe('AppSearchConfigured', () => { describe('canManageEngines', () => { it('renders EngineCreation when user canManageEngines is true', () => { setMockValues({ myRole: { canManageEngines: true } }); - const wrapper = shallow(); + rerender(wrapper); expect(wrapper.find(EngineCreation)).toHaveLength(1); }); it('does not render EngineCreation when user canManageEngines is false', () => { setMockValues({ myRole: { canManageEngines: false } }); - const wrapper = shallow(); + rerender(wrapper); expect(wrapper.find(EngineCreation)).toHaveLength(0); }); @@ -122,14 +107,14 @@ describe('AppSearchConfigured', () => { describe('canManageMetaEngines', () => { it('renders MetaEngineCreation when user canManageMetaEngines is true', () => { setMockValues({ myRole: { canManageMetaEngines: true } }); - const wrapper = shallow(); + rerender(wrapper); expect(wrapper.find(MetaEngineCreation)).toHaveLength(1); }); it('does not render MetaEngineCreation when user canManageMetaEngines is false', () => { setMockValues({ myRole: { canManageMetaEngines: false } }); - const wrapper = shallow(); + rerender(wrapper); expect(wrapper.find(MetaEngineCreation)).toHaveLength(0); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx index ec64cb2f10eb0..88db4004ea9e2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx @@ -5,10 +5,10 @@ * 2.0. */ -import React, { useEffect } from 'react'; +import React from 'react'; import { Route, Redirect, Switch } from 'react-router-dom'; -import { useActions, useValues } from 'kea'; +import { useValues } from 'kea'; import { APP_SEARCH_PLUGIN } from '../../../common/constants'; import { InitialAppData } from '../../../common/types'; @@ -44,7 +44,11 @@ import { export const AppSearch: React.FC = (props) => { const { config } = useValues(KibanaLogic); - return !config.host ? : ; + return !config.host ? ( + + ) : ( + )} /> + ); }; export const AppSearchUnconfigured: React.FC = () => ( @@ -58,18 +62,12 @@ export const AppSearchUnconfigured: React.FC = () => ( ); -export const AppSearchConfigured: React.FC = (props) => { - const { initializeAppData } = useActions(AppLogic); +export const AppSearchConfigured: React.FC> = (props) => { const { - hasInitialized, myRole: { canManageEngines, canManageMetaEngines }, - } = useValues(AppLogic); + } = useValues(AppLogic(props)); const { errorConnecting, readOnlyMode } = useValues(HttpLogic); - useEffect(() => { - if (!hasInitialized) initializeAppData(props); - }, [hasInitialized]); - return ( diff --git a/x-pack/plugins/enterprise_search/server/lib/check_access.ts b/x-pack/plugins/enterprise_search/server/lib/check_access.ts index 0a5e0c9e2b832..a88eb49d7b02a 100644 --- a/x-pack/plugins/enterprise_search/server/lib/check_access.ts +++ b/x-pack/plugins/enterprise_search/server/lib/check_access.ts @@ -9,6 +9,7 @@ import { KibanaRequest, Logger } from 'src/core/server'; import { SecurityPluginSetup } from '../../../security/server'; import { SpacesPluginStart } from '../../../spaces/server'; +import { ProductAccess } from '../../common/types'; import { ConfigType } from '../index'; import { callEnterpriseSearchConfigAPI } from './enterprise_search_config_api'; @@ -20,10 +21,6 @@ interface CheckAccess { config: ConfigType; log: Logger; } -export interface Access { - hasAppSearchAccess: boolean; - hasWorkplaceSearchAccess: boolean; -} const ALLOW_ALL_PLUGINS = { hasAppSearchAccess: true, @@ -45,7 +42,7 @@ export const checkAccess = async ({ spaces, request, log, -}: CheckAccess): Promise => { +}: CheckAccess): Promise => { const isRbacEnabled = security?.authz.mode.useRbacForRequest(request) ?? false; // We can only retrieve the active space when either: diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts index 6c6744ef3e32b..de13077cd1b09 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts @@ -108,12 +108,12 @@ describe('callEnterpriseSearchConfigAPI', () => { }); expect(await callEnterpriseSearchConfigAPI(mockDependencies)).toEqual({ + ...DEFAULT_INITIAL_APP_DATA, access: { hasAppSearchAccess: true, hasWorkplaceSearchAccess: false, }, publicUrl: 'http://some.vanity.url', - ...DEFAULT_INITIAL_APP_DATA, }); }); diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts index 0ed4ad257f30b..ebe718dfebd30 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts @@ -14,15 +14,12 @@ import { stripTrailingSlash } from '../../common/strip_slashes'; import { InitialAppData } from '../../common/types'; import { ConfigType } from '../index'; -import { Access } from './check_access'; - interface Params { request: KibanaRequest; config: ConfigType; log: Logger; } interface Return extends InitialAppData { - access?: Access; publicUrl?: string; } diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/config_data.test.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/config_data.test.ts index 1545547c1dd4e..b3d2733e233b3 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/config_data.test.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/config_data.test.ts @@ -33,12 +33,8 @@ describe('Enterprise Search Config Data API', () => { describe('GET /api/enterprise_search/config_data', () => { it('returns an initial set of config data from Enterprise Search', async () => { const mockData = { - access: { - hasAppSearchAccess: true, - hasWorkplaceSearchAccess: true, - }, - publicUrl: 'http://localhost:3002', ...DEFAULT_INITIAL_APP_DATA, + publicUrl: 'http://localhost:3002', }; (callEnterpriseSearchConfigAPI as jest.Mock).mockImplementationOnce(() => { From 3c4595de5e5f7b3db3c82e75ab2abbca1316a306 Mon Sep 17 00:00:00 2001 From: Gabriel Landau <42078554+gabriellandau@users.noreply.github.com> Date: Tue, 2 Mar 2021 11:44:42 -0800 Subject: [PATCH 19/33] [7.12][Security] Shellcode telemetry update for schema adjustment (#93143) * Shellcode telemetry update for schema adjustment * Lint * Lint Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../server/lib/telemetry/sender.ts | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts b/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts index 6ce42eabeca5e..e169c036419c5 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/sender.ts @@ -395,27 +395,45 @@ const allowlistEventFields: AllowlistFields = { Ext: { call_stack: true, start_address: true, + start_address_allocation_offset: true, + start_address_bytes: true, + start_address_bytes_disasm: true, + start_address_bytes_disasm_hash: true, start_address_details: { - address_offset: true, allocation_base: true, allocation_protection: true, allocation_size: true, allocation_type: true, - base_address: true, - bytes_start_address: true, - compressed_bytes: true, - dest_bytes: true, - dest_bytes_disasm: true, - dest_bytes_disasm_hash: true, - pe: { + bytes_address: true, + bytes_allocation_offset: true, + bytes_compressed: true, + mapped_pe: { Ext: { + code_signature: { + status: true, + subject_name: true, + trusted: true, + }, legal_copyright: true, product_version: true, + }, + company: true, + description: true, + file_version: true, + imphash: true, + original_file_name: true, + product: true, + }, + mapped_pe_path: true, + memory_pe: { + Ext: { code_signature: { status: true, subject_name: true, trusted: true, }, + legal_copyright: true, + product_version: true, }, company: true, description: true, @@ -424,7 +442,8 @@ const allowlistEventFields: AllowlistFields = { original_file_name: true, product: true, }, - pe_detected: true, + memory_pe_detected: true, + region_base: true, region_protection: true, region_size: true, region_state: true, From 9e354bdf284403f4606afa4b22277009bf1e1631 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Mar 2021 13:54:45 -0600 Subject: [PATCH 20/33] Update dependency @elastic/charts to v25.1.0 (master) (#93151) * Update dependency @elastic/charts to v25.1.0 Co-authored-by: Renovate Bot --- package.json | 2 +- .../service_profiling/service_profiling_flamegraph.tsx | 1 - yarn.lock | 8 ++++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 3dde0c6a17fb5..d1d2bc5672427 100644 --- a/package.json +++ b/package.json @@ -347,7 +347,7 @@ "@cypress/webpack-preprocessor": "^5.5.0", "@elastic/apm-rum": "^5.6.1", "@elastic/apm-rum-react": "^1.2.5", - "@elastic/charts": "25.0.1", + "@elastic/charts": "25.1.0", "@elastic/eslint-config-kibana": "link:packages/elastic-eslint-config-kibana", "@elastic/eslint-plugin-eui": "0.0.2", "@elastic/github-checks-reporter": "0.0.20b3", diff --git a/x-pack/plugins/apm/public/components/app/service_profiling/service_profiling_flamegraph.tsx b/x-pack/plugins/apm/public/components/app/service_profiling/service_profiling_flamegraph.tsx index fa1da99dbf072..1adf58d0394c6 100644 --- a/x-pack/plugins/apm/public/components/app/service_profiling/service_profiling_flamegraph.tsx +++ b/x-pack/plugins/apm/public/components/app/service_profiling/service_profiling_flamegraph.tsx @@ -323,7 +323,6 @@ export function ServiceProfilingFlamegraph({ config={{ fillLabel: { fontFamily: theme.eui.euiCodeFontFamily, - // @ts-expect-error (coming soon in Elastic charts) clipText: true, }, drilldown: true, diff --git a/yarn.lock b/yarn.lock index 6c706cffebaaf..52945b884ab23 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2146,10 +2146,10 @@ dependencies: object-hash "^1.3.0" -"@elastic/charts@25.0.1": - version "25.0.1" - resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-25.0.1.tgz#7c61fc22887b7b1feba3e52fc1b44f21a9c1d0bc" - integrity sha512-UYGO9Yg2+cdJOOs9DjlYeB2Oy/3UMXTtF6/yWZt2iXh7mmW9jI5DqfjgG/9BFSCwQZHUKBZ58d5ZCQfe72maGA== +"@elastic/charts@25.1.0": + version "25.1.0" + resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-25.1.0.tgz#8859e07c9822696b3f9b12ae46a18e3316f623fd" + integrity sha512-4IFmyhg3dG7VjP0C9DbMBBAxAtai/HPdG/4Z5UMdGYGoZiJwS+fo50irQtvD3H5Lm6OSS8Xk9hmCVPx8KmdiUg== dependencies: "@popperjs/core" "^2.4.0" chroma-js "^2.1.0" From aa6591afe9db002ce57c8086c6b3512271805221 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 2 Mar 2021 13:07:19 -0700 Subject: [PATCH 21/33] Update KQL field autocompletion to suggest fields that match search (#92559) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../providers/kql_query_suggestion/field.test.ts | 11 +++++++++++ .../providers/kql_query_suggestion/field.tsx | 3 +-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/field.test.ts b/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/field.test.ts index bea695779fda6..afc55d13af9d9 100644 --- a/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/field.test.ts +++ b/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/field.test.ts @@ -78,6 +78,17 @@ describe('Kuery field suggestions', () => { expect(suggestions.find(({ text }) => text === 'machine.os ')).toBeDefined(); }); + test('should field names that match the search', async () => { + const prefix = 'machi'; + const suffix = 'ne.os'; + const suggestions = await getSuggestions( + querySuggestionsArgs, + mockKueryNode({ prefix, suffix }) + ); + + expect(suggestions.find(({ text }) => text === 'machine.os ')).toBeDefined(); + }); + test('should return field names that start with the query first', async () => { const prefix = 'e'; const suffix = ''; diff --git a/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/field.tsx b/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/field.tsx index ef0f27ee93bb7..ac6f7de888320 100644 --- a/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/field.tsx +++ b/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/field.tsx @@ -58,8 +58,7 @@ export const setupGetFieldSuggestions: KqlQuerySuggestionProvider Date: Tue, 2 Mar 2021 14:08:03 -0600 Subject: [PATCH 22/33] [Fleet] Fix default integration name when adding 10+ names (#93278) --- .../create_package_policy_page/step_define_package_policy.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx index c66a28944ea71..64837b208ae45 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_define_package_policy.tsx @@ -47,7 +47,7 @@ export const StepDefinePackagePolicy: React.FunctionComponent<{ const pkgPoliciesWithMatchingNames = (agentPolicy.package_policies as PackagePolicy[]) .filter((ds) => Boolean(ds.name.match(pkgPoliciesNamePattern))) .map((ds) => parseInt(ds.name.match(pkgPoliciesNamePattern)![1], 10)) - .sort(); + .sort((a, b) => a - b); updatePackagePolicy({ // FIXME: Improve package policies name uniqueness - https://github.com/elastic/kibana/issues/72948 From 6be9adac0d7c17a6c97e9cc5eaf2c3ed99afa8a4 Mon Sep 17 00:00:00 2001 From: Zacqary Adam Xeper Date: Tue, 2 Mar 2021 14:08:55 -0600 Subject: [PATCH 23/33] [Alerts] Add spaces as optional dep to triggers_actions_ui (#93267) --- x-pack/plugins/triggers_actions_ui/kibana.json | 2 +- x-pack/plugins/triggers_actions_ui/public/application/app.tsx | 3 +++ x-pack/plugins/triggers_actions_ui/public/plugin.ts | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/triggers_actions_ui/kibana.json b/x-pack/plugins/triggers_actions_ui/kibana.json index 0487c58e66269..2938d94bf426a 100644 --- a/x-pack/plugins/triggers_actions_ui/kibana.json +++ b/x-pack/plugins/triggers_actions_ui/kibana.json @@ -3,7 +3,7 @@ "version": "kibana", "server": true, "ui": true, - "optionalPlugins": ["alerts", "features", "home"], + "optionalPlugins": ["alerts", "features", "home", "spaces"], "requiredPlugins": ["management", "charts", "data", "kibanaReact", "kibanaUtils", "savedObjects"], "configPath": ["xpack", "trigger_actions_ui"], "extraPublicDirs": ["public/common", "public/common/constants"], diff --git a/x-pack/plugins/triggers_actions_ui/public/application/app.tsx b/x-pack/plugins/triggers_actions_ui/public/application/app.tsx index 0a59cff98ce26..0afb81031e3bc 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/app.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/app.tsx @@ -17,6 +17,8 @@ import { ActionTypeRegistryContract, AlertTypeRegistryContract } from '../types' import { ChartsPluginStart } from '../../../../../src/plugins/charts/public'; import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; import { PluginStartContract as AlertingStart } from '../../../alerts/public'; +import type { SpacesPluginStart } from '../../../spaces/public'; + import { suspendedComponentWithProps } from './lib/suspended_component_with_props'; import { Storage } from '../../../../../src/plugins/kibana_utils/public'; import { EuiThemeProvider } from '../../../../../src/plugins/kibana_react/common'; @@ -33,6 +35,7 @@ export interface TriggersAndActionsUiServices extends CoreStart { data: DataPublicPluginStart; charts: ChartsPluginStart; alerts?: AlertingStart; + spaces?: SpacesPluginStart; storage?: Storage; setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void; actionTypeRegistry: ActionTypeRegistryContract; diff --git a/x-pack/plugins/triggers_actions_ui/public/plugin.ts b/x-pack/plugins/triggers_actions_ui/public/plugin.ts index e4477c6a8e60e..7c3c273c1f384 100644 --- a/x-pack/plugins/triggers_actions_ui/public/plugin.ts +++ b/x-pack/plugins/triggers_actions_ui/public/plugin.ts @@ -25,6 +25,7 @@ import { ChartsPluginStart } from '../../../../src/plugins/charts/public'; import { PluginStartContract as AlertingStart } from '../../alerts/public'; import { DataPublicPluginStart } from '../../../../src/plugins/data/public'; import { Storage } from '../../../../src/plugins/kibana_utils/public'; +import type { SpacesPluginStart } from '../../spaces/public'; import { getAddConnectorFlyoutLazy } from './common/get_add_connector_flyout'; import { getEditConnectorFlyoutLazy } from './common/get_edit_connector_flyout'; @@ -68,6 +69,7 @@ interface PluginsStart { data: DataPublicPluginStart; charts: ChartsPluginStart; alerts?: AlertingStart; + spaces?: SpacesPluginStart; navigateToApp: CoreStart['application']['navigateToApp']; features: FeaturesPluginStart; } @@ -142,6 +144,7 @@ export class Plugin data: pluginsStart.data, charts: pluginsStart.charts, alerts: pluginsStart.alerts, + spaces: pluginsStart.spaces, element: params.element, storage: new Storage(window.localStorage), setBreadcrumbs: params.setBreadcrumbs, From 319ad55cd742858e2d6d4c14a5b6abfe8f9b855e Mon Sep 17 00:00:00 2001 From: ymao1 Date: Tue, 2 Mar 2021 15:24:06 -0500 Subject: [PATCH 24/33] Different screenshot (#92970) --- .../alert-flyout-alert-type-selection.png | Bin 255161 -> 166951 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/user/alerting/images/alert-flyout-alert-type-selection.png b/docs/user/alerting/images/alert-flyout-alert-type-selection.png index 4e5c49975160f3e810c22b0140512b04880aff18..6ebbe4213ba7d30b06bd3f36c372d88129272f6b 100644 GIT binary patch literal 166951 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�)OJ%dwZ8CKmec^u6&_{G_|;P?r`Rc2s~@QB11_ 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 Date: Tue, 2 Mar 2021 15:40:10 -0500 Subject: [PATCH 25/33] ensure regex works for filter with optional multiple spaces (#93071) --- .../components/exploration_query_bar/exploration_query_bar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_query_bar/exploration_query_bar.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_query_bar/exploration_query_bar.tsx index dd451958e2646..3ef6dbc292c08 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_query_bar/exploration_query_bar.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_query_bar/exploration_query_bar.tsx @@ -60,7 +60,7 @@ export const ExplorationQueryBar: FC = ({ const searchChangeHandler = (q: Query) => setSearchInput(q); - const regex = useMemo(() => new RegExp(`${filters?.columnId}\s?:\s?(true|false)`, 'g'), [ + const regex = useMemo(() => new RegExp(`${filters?.columnId}\\s*:\\s*(true|false)`, 'g'), [ filters?.columnId, ]); From a102fa9a70dce6a4d9c6392498b5737ebc10530e Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 2 Mar 2021 13:43:10 -0800 Subject: [PATCH 26/33] [Alerting][Docs] Moved alerting links from hard-coded to documentation link service. (#92953) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Alerting][Docs] Moved alerting links from hard-coded to documentation link service * fixed due to comments * Update x-pack/plugins/triggers_actions_ui/public/application/components/health_check.tsx Co-authored-by: Mike Côté * fixed jest tests * fixed due to comments Co-authored-by: Mike Côté --- .../public/doc_links/doc_links_service.ts | 10 ++-- .../alert_types/es_query/expression.test.tsx | 5 ++ .../alert_types/es_query/expression.tsx | 5 +- .../public/alert_types/es_query/index.ts | 4 +- .../public/alert_types/threshold/index.ts | 4 +- .../email/email_connector.tsx | 5 +- .../es_index/es_index_connector.tsx | 5 +- .../es_index/es_index_params.tsx | 5 +- .../pagerduty/pagerduty_connectors.tsx | 5 +- .../servicenow/servicenow_connectors.tsx | 5 +- .../slack/slack_connectors.tsx | 5 +- .../teams/teams_connectors.tsx | 5 +- .../application/components/health_check.tsx | 50 ++++--------------- .../public/application/home.tsx | 2 +- .../action_connector_form.tsx | 5 +- .../connector_edit_flyout.tsx | 5 +- 16 files changed, 33 insertions(+), 92 deletions(-) diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index 7792e25e54d01..e985b5cd61e79 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -187,15 +187,17 @@ export class DocLinksService { guide: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/managing-alerts-and-actions.html`, actionTypes: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/action-types.html`, emailAction: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/email-action-type.html`, + emailActionConfig: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/email-action-type.html#configuring-email`, generalSettings: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/alert-action-settings-kb.html#general-alert-action-settings`, indexAction: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/index-action-type.html`, - indexThreshold: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/alert-types.html#alert-type-index-threshold`, + esQuery: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/alert-type-es-query.html`, + indexThreshold: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/alert-type-index-threshold.html#index-action-configuration`, pagerDutyAction: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/pagerduty-action-type.html`, preconfiguredConnectors: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/pre-configured-action-types-and-connectors.html`, - serviceNowAction: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/servicenow-action-type.html`, + serviceNowAction: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/servicenow-action-type.html#configuring-servicenow`, setupPrerequisites: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/alerting-getting-started.html#alerting-setup-prerequisites`, - slackAction: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/slack-action-type.html`, - teamsAction: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/teams-action-type.html`, + slackAction: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/slack-action-type.html#configuring-slack`, + teamsAction: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/teams-action-type.html#configuring-teams`, }, maps: { guide: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/maps.html`, diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.test.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.test.tsx index f475d97e2f39d..51c2f0471d486 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.test.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.test.tsx @@ -116,6 +116,11 @@ describe('EsQueryAlertTypeExpression', () => { docLinks: { ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '', + links: { + query: { + queryDsl: 'query-dsl.html', + }, + }, }, }, }); diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.tsx index 37c64688ec49a..6adcada9b273a 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.tsx @@ -287,10 +287,7 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< isInvalid={errors.esQuery.length > 0} error={errors.esQuery} helpText={ - + { defaultMessage: 'Alert on matches against an ES query.', }), iconClass: 'logoElastic', - documentationUrl(docLinks) { - return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${docLinks.DOC_LINK_VERSION}/alert-types.html#alert-type-es-query`; - }, + documentationUrl: (docLinks) => docLinks.links.alerting.esQuery, alertParamsExpression: lazy(() => import('./expression')), validate: validateExpression, defaultActionMessage: i18n.translate( diff --git a/x-pack/plugins/stack_alerts/public/alert_types/threshold/index.ts b/x-pack/plugins/stack_alerts/public/alert_types/threshold/index.ts index 95ecd121cf5a2..1b229bb4a9d0a 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/threshold/index.ts +++ b/x-pack/plugins/stack_alerts/public/alert_types/threshold/index.ts @@ -18,9 +18,7 @@ export function getAlertType(): AlertTypeModel { defaultMessage: 'Alert when an aggregated query meets the threshold.', }), iconClass: 'alert', - documentationUrl(docLinks) { - return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${docLinks.DOC_LINK_VERSION}/alert-types.html#alert-type-index-threshold`; - }, + documentationUrl: (docLinks) => docLinks.links.alerting.indexThreshold, alertParamsExpression: lazy(() => import('./expression')), validate: validateExpression, defaultActionMessage: i18n.translate( diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email_connector.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email_connector.tsx index 2f518780c9f6b..df6822c85340a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email_connector.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email_connector.tsx @@ -55,10 +55,7 @@ export const EmailActionConnectorFields: React.FunctionComponent< } )} helpText={ - + - + + + + + + = ({ }; interface PromptErrorProps { - docLinks: Pick; + docLinks: DocLinksStart; className?: string; } -const EncryptionError = ({ - // eslint-disable-next-line @typescript-eslint/naming-convention - docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION }, - className, -}: PromptErrorProps) => ( +const EncryptionError = ({ docLinks, className }: PromptErrorProps) => ( + {i18n.translate( 'xpack.triggersActionsUI.components.healthCheck.encryptionErrorAction', { @@ -151,11 +143,7 @@ const EncryptionError = ({ /> ); -const TlsError = ({ - // eslint-disable-next-line @typescript-eslint/naming-convention - docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION }, - className, -}: PromptErrorProps) => ( +const TlsError = ({ docLinks, className }: PromptErrorProps) => ( + {i18n.translate('xpack.triggersActionsUI.components.healthCheck.tlsErrorAction', { defaultMessage: 'Learn how to enable TLS.', })} @@ -191,11 +175,7 @@ const TlsError = ({ /> ); -const AlertsError = ({ - // eslint-disable-next-line @typescript-eslint/naming-convention - docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION }, - className, -}: PromptErrorProps) => ( +const AlertsError = ({ docLinks, className }: PromptErrorProps) => ( + {i18n.translate('xpack.triggersActionsUI.components.healthCheck.alertsErrorAction', { defaultMessage: 'Learn how to enable Alerts and Actions.', })} @@ -230,11 +206,7 @@ const AlertsError = ({ /> ); -const TlsAndEncryptionError = ({ - // eslint-disable-next-line @typescript-eslint/naming-convention - docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION }, - className, -}: PromptErrorProps) => ( +const TlsAndEncryptionError = ({ docLinks, className }: PromptErrorProps) => ( + {i18n.translate( 'xpack.triggersActionsUI.components.healthCheck.tlsAndEncryptionErrorAction', { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/home.tsx b/x-pack/plugins/triggers_actions_ui/public/application/home.tsx index 1e7fa3c51e689..c251a1d597f27 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/home.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/home.tsx @@ -99,7 +99,7 @@ export const TriggersActionsUIHome: React.FunctionComponent + - + Date: Tue, 2 Mar 2021 16:46:09 -0500 Subject: [PATCH 27/33] [Maps] Abort ES-search when tile request is cancelled (#92069) --- x-pack/plugins/maps/server/mvt/get_tile.ts | 18 ++++++++++++++++-- x-pack/plugins/maps/server/mvt/mvt_routes.ts | 15 +++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/maps/server/mvt/get_tile.ts b/x-pack/plugins/maps/server/mvt/get_tile.ts index 50c2014275a0f..3274261cdba56 100644 --- a/x-pack/plugins/maps/server/mvt/get_tile.ts +++ b/x-pack/plugins/maps/server/mvt/get_tile.ts @@ -28,6 +28,10 @@ import { flattenHit } from './util'; import { ESBounds, tileToESBbox } from '../../common/geo_tile_utils'; import { getCentroidFeatures } from '../../common/get_centroid_features'; +function isAbortError(error: Error) { + return error.message === 'Request aborted' || error.message === 'Aborted'; +} + export async function getGridTile({ logger, context, @@ -40,6 +44,7 @@ export async function getGridTile({ requestType = RENDER_AS.POINT, geoFieldType = ES_GEO_FIELD_TYPE.GEO_POINT, searchSessionId, + abortSignal, }: { x: number; y: number; @@ -52,6 +57,7 @@ export async function getGridTile({ requestType: RENDER_AS; geoFieldType: ES_GEO_FIELD_TYPE; searchSessionId?: string; + abortSignal: AbortSignal; }): Promise { try { const tileBounds: ESBounds = tileToESBbox(x, y, z); @@ -72,6 +78,7 @@ export async function getGridTile({ }, { sessionId: searchSessionId, + abortSignal, } ) .toPromise(); @@ -83,7 +90,9 @@ export async function getGridTile({ return createMvtTile(featureCollection, z, x, y); } catch (e) { - logger.warn(`Cannot generate grid-tile for ${z}/${x}/${y}: ${e.message}`); + if (!isAbortError(e)) { + logger.warn(`Cannot generate grid-tile for ${z}/${x}/${y}: ${e.message}`); + } return null; } } @@ -99,6 +108,7 @@ export async function getTile({ requestBody = {}, geoFieldType, searchSessionId, + abortSignal, }: { x: number; y: number; @@ -110,6 +120,7 @@ export async function getTile({ requestBody: any; geoFieldType: ES_GEO_FIELD_TYPE; searchSessionId?: string; + abortSignal: AbortSignal; }): Promise { let features: Feature[]; try { @@ -119,6 +130,7 @@ export async function getTile({ const searchOptions = { sessionId: searchSessionId, + abortSignal, }; const countResponse = await context @@ -214,7 +226,9 @@ export async function getTile({ return createMvtTile(featureCollection, z, x, y); } catch (e) { - logger.warn(`Cannot generate tile for ${z}/${x}/${y}: ${e.message}`); + if (!isAbortError(e)) { + logger.warn(`Cannot generate tile for ${z}/${x}/${y}: ${e.message}`); + } return null; } } diff --git a/x-pack/plugins/maps/server/mvt/mvt_routes.ts b/x-pack/plugins/maps/server/mvt/mvt_routes.ts index 3e16176579586..1423e4ef5a20d 100644 --- a/x-pack/plugins/maps/server/mvt/mvt_routes.ts +++ b/x-pack/plugins/maps/server/mvt/mvt_routes.ts @@ -10,6 +10,8 @@ import { schema } from '@kbn/config-schema'; import { KibanaRequest, KibanaResponseFactory, Logger } from 'src/core/server'; import { IRouter } from 'src/core/server'; import type { DataRequestHandlerContext } from 'src/plugins/data/server'; +// @ts-ignore not typed +import { AbortController } from 'abortcontroller-polyfill/dist/cjs-ponyfill'; import { MVT_GETTILE_API_PATH, API_ROOT_PATH, @@ -50,6 +52,12 @@ export function initMVTRoutes({ response: KibanaResponseFactory ) => { const { query } = request; + + const abortController = new AbortController(); + request.events.aborted$.subscribe(() => { + abortController.abort(); + }); + const requestBodyDSL = rison.decode(query.requestBody as string); const tile = await getTile({ @@ -63,6 +71,7 @@ export function initMVTRoutes({ requestBody: requestBodyDSL as any, geoFieldType: query.geoFieldType as ES_GEO_FIELD_TYPE, searchSessionId: query.searchSessionId, + abortSignal: abortController.signal, }); return sendResponse(response, tile); @@ -92,6 +101,11 @@ export function initMVTRoutes({ response: KibanaResponseFactory ) => { const { query } = request; + const abortController = new AbortController(); + request.events.aborted$.subscribe(() => { + abortController.abort(); + }); + const requestBodyDSL = rison.decode(query.requestBody as string); const tile = await getGridTile({ @@ -106,6 +120,7 @@ export function initMVTRoutes({ requestType: query.requestType as RENDER_AS, geoFieldType: query.geoFieldType as ES_GEO_FIELD_TYPE, searchSessionId: query.searchSessionId, + abortSignal: abortController.signal, }); return sendResponse(response, tile); From 819cb485dcb51a4a68bf1b23a8d442e770c984c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ece=20=C3=96zalp?= Date: Tue, 2 Mar 2021 16:47:09 -0500 Subject: [PATCH 28/33] Add searchDuration to EQL and Threshold rules (#93149) Closes #82861. --- .../signals/signal_rule_alert_type.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts index f81f4c5a2c537..45d3986a1c115 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -12,6 +12,7 @@ import isEmpty from 'lodash/isEmpty'; import { chain, tryCatch } from 'fp-ts/lib/TaskEither'; import { flow } from 'fp-ts/lib/function'; +import { performance } from 'perf_hooks'; import { toError, toPromise } from '../../../../common/fp_utils'; import { @@ -50,6 +51,7 @@ import { hasTimestampFields, hasReadIndexPrivileges, getRuleRangeTuples, + makeFloatString, } from './utils'; import { signalParamsSchema } from './signal_params_schema'; import { siemRuleActionGroups } from './siem_rule_action_groups'; @@ -402,7 +404,11 @@ export const signalRulesAlertType = ({ lists: exceptionItems ?? [], }); - const { searchResult: thresholdResults, searchErrors } = await findThresholdSignals({ + const { + searchResult: thresholdResults, + searchErrors, + searchDuration: thresholdSearchDuration, + } = await findThresholdSignals({ inputIndexPattern: inputIndex, from, to, @@ -457,6 +463,7 @@ export const signalRulesAlertType = ({ createdSignalsCount: createdItemsCount, createdSignals: createdItems, bulkCreateTimes: bulkCreateDuration ? [bulkCreateDuration] : [], + searchAfterTimes: [thresholdSearchDuration], }), ]); } else if (isThreatMatchRule(type)) { @@ -590,10 +597,14 @@ export const signalRulesAlertType = ({ exceptionItems ?? [], eventCategoryOverride ); + const eqlSignalSearchStart = performance.now(); const response: EqlSignalSearchResponse = await services.callCluster( 'transport.request', request ); + const eqlSignalSearchEnd = performance.now(); + const eqlSearchDuration = makeFloatString(eqlSignalSearchEnd - eqlSignalSearchStart); + result.searchAfterTimes = [eqlSearchDuration]; let newSignals: WrappedSignalHit[] | undefined; if (response.hits.sequences !== undefined) { newSignals = response.hits.sequences.reduce( @@ -634,7 +645,6 @@ export const signalRulesAlertType = ({ const fromInMs = parseScheduleDates(`now-${interval}`)?.format('x'); const toInMs = parseScheduleDates('now')?.format('x'); - const resultsLink = getNotificationResultsLink({ from: fromInMs, to: toInMs, From 21338080db6d3bf8d202ceed6381f65d7e2bb524 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Tue, 2 Mar 2021 16:48:02 -0500 Subject: [PATCH 29/33] [Maps] Update Map extent queries to use bounding box logic for both point and shape queries (#93156) --- .../elasticsearch_geo_utils.d.ts | 3 +- .../elasticsearch_geo_utils.js | 26 +-- .../elasticsearch_geo_utils.test.js | 202 +++++++----------- .../classes/sources/es_source/es_source.ts | 8 +- 4 files changed, 84 insertions(+), 155 deletions(-) diff --git a/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.d.ts b/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.d.ts index d7d76ab8acd37..2a3741146d454 100644 --- a/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.d.ts +++ b/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.d.ts @@ -47,8 +47,7 @@ export interface ESPolygonFilter { export function createExtentFilter( mapExtent: MapExtent, - geoFieldName: string, - geoFieldType: ES_GEO_FIELD_TYPE + geoFieldName: string ): ESPolygonFilter | ESGeoBoundingBoxFilter; export function makeESBbox({ maxLat, maxLon, minLat, minLon }: MapExtent): ESBBox; diff --git a/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.js b/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.js index c6b1c712925f0..47de8850c0e96 100644 --- a/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.js +++ b/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.js @@ -280,8 +280,8 @@ export function makeESBbox({ maxLat, maxLon, minLat, minLon }) { return esBbox; } -function createGeoBoundBoxFilter({ maxLat, maxLon, minLat, minLon }, geoFieldName) { - const boundingBox = makeESBbox({ maxLat, maxLon, minLat, minLon }); +export function createExtentFilter(mapExtent, geoFieldName) { + const boundingBox = makeESBbox(mapExtent); return { geo_bounding_box: { [geoFieldName]: boundingBox, @@ -289,28 +289,6 @@ function createGeoBoundBoxFilter({ maxLat, maxLon, minLat, minLon }, geoFieldNam }; } -export function createExtentFilter(mapExtent, geoFieldName, geoFieldType) { - ensureGeoField(geoFieldType); - - // Extent filters are used to dynamically filter data for the current map view port. - // Continue to use geo_bounding_box queries for extent filters - // 1) geo_bounding_box queries are faster than polygon queries - // 2) geo_shape benefits of pre-indexed shapes and - // compatability across multi-indices with geo_point and geo_shape do not apply to this use case. - if (geoFieldType === ES_GEO_FIELD_TYPE.GEO_POINT) { - return createGeoBoundBoxFilter(mapExtent, geoFieldName); - } - - return { - geo_shape: { - [geoFieldName]: { - shape: formatEnvelopeAsPolygon(mapExtent), - relation: ES_SPATIAL_RELATIONS.INTERSECTS, - }, - }, - }; -} - export function createSpatialFilterWithGeometry({ preIndexedShape, geometry, diff --git a/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.test.js b/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.test.js index aed9ccbb96c3b..9983bb9b84588 100644 --- a/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.test.js +++ b/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.test.js @@ -389,143 +389,99 @@ describe('geoShapeToGeometry', () => { }); describe('createExtentFilter', () => { - describe('geo_point field', () => { - it('should return elasticsearch geo_bounding_box filter for geo_point field', () => { - const mapExtent = { - maxLat: 39, - maxLon: -83, - minLat: 35, - minLon: -89, - }; - const filter = createExtentFilter(mapExtent, geoFieldName, 'geo_point'); - expect(filter).toEqual({ - geo_bounding_box: { - location: { - top_left: [-89, 39], - bottom_right: [-83, 35], - }, - }, - }); - }); - - it('should clamp longitudes to -180 to 180 and latitudes to -90 to 90', () => { - const mapExtent = { - maxLat: 120, - maxLon: 200, - minLat: -100, - minLon: -190, - }; - const filter = createExtentFilter(mapExtent, geoFieldName, 'geo_point'); - expect(filter).toEqual({ - geo_bounding_box: { - location: { - top_left: [-180, 89], - bottom_right: [180, -89], - }, + it('should return elasticsearch geo_bounding_box filter', () => { + const mapExtent = { + maxLat: 39, + maxLon: -83, + minLat: 35, + minLon: -89, + }; + const filter = createExtentFilter(mapExtent, geoFieldName); + expect(filter).toEqual({ + geo_bounding_box: { + location: { + top_left: [-89, 39], + bottom_right: [-83, 35], }, - }); + }, }); + }); - it('should make left longitude greater then right longitude when area crosses 180 meridian east to west', () => { - const mapExtent = { - maxLat: 39, - maxLon: 200, - minLat: 35, - minLon: 100, - }; - const filter = createExtentFilter(mapExtent, geoFieldName, 'geo_point'); - const leftLon = filter.geo_bounding_box.location.top_left[0]; - const rightLon = filter.geo_bounding_box.location.bottom_right[0]; - expect(leftLon).toBeGreaterThan(rightLon); - expect(filter).toEqual({ - geo_bounding_box: { - location: { - top_left: [100, 39], - bottom_right: [-160, 35], - }, + it('should clamp longitudes to -180 to 180 and latitudes to -90 to 90', () => { + const mapExtent = { + maxLat: 120, + maxLon: 200, + minLat: -100, + minLon: -190, + }; + const filter = createExtentFilter(mapExtent, geoFieldName); + expect(filter).toEqual({ + geo_bounding_box: { + location: { + top_left: [-180, 89], + bottom_right: [180, -89], }, - }); + }, }); + }); - it('should make left longitude greater then right longitude when area crosses 180 meridian west to east', () => { - const mapExtent = { - maxLat: 39, - maxLon: -100, - minLat: 35, - minLon: -200, - }; - const filter = createExtentFilter(mapExtent, geoFieldName, 'geo_point'); - const leftLon = filter.geo_bounding_box.location.top_left[0]; - const rightLon = filter.geo_bounding_box.location.bottom_right[0]; - expect(leftLon).toBeGreaterThan(rightLon); - expect(filter).toEqual({ - geo_bounding_box: { - location: { - top_left: [160, 39], - bottom_right: [-100, 35], - }, + it('should make left longitude greater then right longitude when area crosses 180 meridian east to west', () => { + const mapExtent = { + maxLat: 39, + maxLon: 200, + minLat: 35, + minLon: 100, + }; + const filter = createExtentFilter(mapExtent, geoFieldName); + const leftLon = filter.geo_bounding_box.location.top_left[0]; + const rightLon = filter.geo_bounding_box.location.bottom_right[0]; + expect(leftLon).toBeGreaterThan(rightLon); + expect(filter).toEqual({ + geo_bounding_box: { + location: { + top_left: [100, 39], + bottom_right: [-160, 35], }, - }); + }, }); }); - describe('geo_shape field', () => { - it('should return elasticsearch geo_shape filter', () => { - const mapExtent = { - maxLat: 39, - maxLon: -83, - minLat: 35, - minLon: -89, - }; - const filter = createExtentFilter(mapExtent, geoFieldName, 'geo_shape'); - expect(filter).toEqual({ - geo_shape: { - location: { - relation: 'INTERSECTS', - shape: { - coordinates: [ - [ - [-89, 39], - [-89, 35], - [-83, 35], - [-83, 39], - [-89, 39], - ], - ], - type: 'Polygon', - }, - }, + it('should make left longitude greater then right longitude when area crosses 180 meridian west to east', () => { + const mapExtent = { + maxLat: 39, + maxLon: -100, + minLat: 35, + minLon: -200, + }; + const filter = createExtentFilter(mapExtent, geoFieldName); + const leftLon = filter.geo_bounding_box.location.top_left[0]; + const rightLon = filter.geo_bounding_box.location.bottom_right[0]; + expect(leftLon).toBeGreaterThan(rightLon); + expect(filter).toEqual({ + geo_bounding_box: { + location: { + top_left: [160, 39], + bottom_right: [-100, 35], }, - }); + }, }); + }); - it('should clamp longitudes to -180 to 180 when lonitude wraps globe', () => { - const mapExtent = { - maxLat: 39, - maxLon: 209, - minLat: 35, - minLon: -191, - }; - const filter = createExtentFilter(mapExtent, geoFieldName, 'geo_shape'); - expect(filter).toEqual({ - geo_shape: { - location: { - relation: 'INTERSECTS', - shape: { - coordinates: [ - [ - [-180, 39], - [-180, 35], - [180, 35], - [180, 39], - [-180, 39], - ], - ], - type: 'Polygon', - }, - }, + it('should clamp longitudes to -180 to 180 when longitude wraps globe', () => { + const mapExtent = { + maxLat: 39, + maxLon: 209, + minLat: 35, + minLon: -191, + }; + const filter = createExtentFilter(mapExtent, geoFieldName); + expect(filter).toEqual({ + geo_bounding_box: { + location: { + top_left: [-180, 39], + bottom_right: [180, 35], }, - }); + }, }); }); }); diff --git a/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts b/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts index f6f0a234bcd67..6b99f1f8860c0 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_source/es_source.ts @@ -34,7 +34,7 @@ import { import { IVectorStyle } from '../../styles/vector/vector_style'; import { IDynamicStyleProperty } from '../../styles/vector/properties/dynamic_style_property'; import { IField } from '../../fields/field'; -import { ES_GEO_FIELD_TYPE, FieldFormatter } from '../../../../common/constants'; +import { FieldFormatter } from '../../../../common/constants'; import { Adapters, RequestResponder, @@ -236,11 +236,7 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource typeof searchFilters.geogridPrecision === 'number' ? expandToTileBoundaries(searchFilters.buffer, searchFilters.geogridPrecision) : searchFilters.buffer; - const extentFilter = createExtentFilter( - buffer, - geoField.name, - geoField.type as ES_GEO_FIELD_TYPE - ); + const extentFilter = createExtentFilter(buffer, geoField.name); // @ts-expect-error allFilters.push(extentFilter); From 9d1df3f6f4efecc517c23e9f09a52aa8dd8687f8 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 2 Mar 2021 21:56:02 +0000 Subject: [PATCH 30/33] chore(NA): do not include fs within a storybook build (#93294) --- packages/kbn-storybook/lib/default_config.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/kbn-storybook/lib/default_config.ts b/packages/kbn-storybook/lib/default_config.ts index 1b049761a3a98..e194c9789daab 100644 --- a/packages/kbn-storybook/lib/default_config.ts +++ b/packages/kbn-storybook/lib/default_config.ts @@ -19,6 +19,9 @@ export const defaultConfig: StorybookConfig = { config.parallelism = 4; config.cache = true; } + + config.node = { fs: 'empty' }; + return config; }, }; From 42188134642a6c35373b95923bc4333668ad12cf Mon Sep 17 00:00:00 2001 From: Bhavya RM Date: Tue, 2 Mar 2021 17:21:28 -0500 Subject: [PATCH 31/33] removing the linked issue in comments from PR (#93303) --- test/functional/apps/management/_import_objects.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/test/functional/apps/management/_import_objects.ts b/test/functional/apps/management/_import_objects.ts index ca8d8c392ce49..a3daaf8629493 100644 --- a/test/functional/apps/management/_import_objects.ts +++ b/test/functional/apps/management/_import_objects.ts @@ -23,7 +23,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const log = getService('log'); - // FLAKY: https://github.com/elastic/kibana/issues/89478 describe('import objects', function describeIndexTests() { describe('.ndjson file', () => { beforeEach(async function () { From 3b6643144d6e7228bf176c87341131ec4e6ab416 Mon Sep 17 00:00:00 2001 From: Spencer Date: Tue, 2 Mar 2021 16:03:00 -0700 Subject: [PATCH 32/33] [jenkins] convert baseline capture job to use tasks (#93288) Co-authored-by: spalger --- .ci/Jenkinsfile_baseline_capture | 62 ++++++++++++---------- src/dev/ci_setup/bootstrap_validations.sh | 64 +++++++++++++++++++++++ src/dev/ci_setup/setup.sh | 62 ++-------------------- 3 files changed, 103 insertions(+), 85 deletions(-) create mode 100644 src/dev/ci_setup/bootstrap_validations.sh diff --git a/.ci/Jenkinsfile_baseline_capture b/.ci/Jenkinsfile_baseline_capture index 6993dc9e087f9..672f5127a9796 100644 --- a/.ci/Jenkinsfile_baseline_capture +++ b/.ci/Jenkinsfile_baseline_capture @@ -3,40 +3,48 @@ library 'kibana-pipeline-library' kibanaLibrary.load() -kibanaPipeline(timeoutMinutes: 120) { +kibanaPipeline(timeoutMinutes: 210) { githubCommitStatus.trackBuild(params.commit, 'kibana-ci-baseline') { ciStats.trackBuild { - catchError { - withEnv([ - 'CI_PARALLEL_PROCESS_NUMBER=1' - ]) { - parallel([ - 'oss-baseline': { - workers.ci(name: 'oss-baseline', size: 'l', ramDisk: true, runErrorReporter: false, bootstrapped: false) { - // bootstrap ourselves, but with the env needed to upload the ts refs cache - withGcpServiceAccount.fromVaultSecret('secret/kibana-issues/dev/ci-artifacts-key', 'value') { - withEnv([ - 'BUILD_TS_REFS_CACHE_ENABLE=true', - 'BUILD_TS_REFS_CACHE_CAPTURE=true' - ]) { - kibanaPipeline.doSetup() - } - } + catchErrors { + slackNotifications.onFailure( + title: "*<${env.BUILD_URL}|[${params.branch}] Baseline Capture Failure>*", + message: "[${params.branch}/${params.commit}] Baseline Capture Failure", + ) { + retryable.enable(2) - kibanaPipeline.functionalTestProcess('oss-baseline', './test/scripts/jenkins_baseline.sh')() + catchErrors { + workers.ci( + name: 'baseline-worker', + size: 'xl', + ramDisk: true, + runErrorReporter: false, + bootstrapped: false + ) { + withGcpServiceAccount.fromVaultSecret('secret/kibana-issues/dev/ci-artifacts-key', 'value') { + withEnv([ + 'BUILD_TS_REFS_CACHE_ENABLE=true', + 'BUILD_TS_REFS_CACHE_CAPTURE=true', + 'DISABLE_BOOTSTRAP_VALIDATIONS=true', + ]) { + kibanaPipeline.doSetup() + } } - }, - 'xpack-baseline': { - workers.ci(name: 'xpack-baseline', size: 'l', ramDisk: true, runErrorReporter: false) { - kibanaPipeline.functionalTestProcess('xpack-baseline', './test/scripts/jenkins_xpack_baseline.sh')() + + kibanaPipeline.withCiTaskQueue([parallel: 2]) { + catchErrors { + tasks([ + kibanaPipeline.functionalTestProcess('oss-baseline', './test/scripts/jenkins_baseline.sh'), + kibanaPipeline.functionalTestProcess('xpack-baseline', './test/scripts/jenkins_xpack_baseline.sh'), + ]) + } } - }, - ]) + } + } } } - - kibanaPipeline.sendMail() - slackNotifications.onFailure() } + + kibanaPipeline.sendMail() } } diff --git a/src/dev/ci_setup/bootstrap_validations.sh b/src/dev/ci_setup/bootstrap_validations.sh new file mode 100644 index 0000000000000..939269952dea1 --- /dev/null +++ b/src/dev/ci_setup/bootstrap_validations.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +set -e + +### +### verify no git modifications caused by bootstrap +### +if [[ $DISABLE_BOOTSTRAP_VALIDATIONS != "true" ]]; then + GIT_CHANGES="$(git ls-files --modified)" + if [ "$GIT_CHANGES" ]; then + echo -e "\n${RED}ERROR: 'yarn kbn bootstrap' caused changes to the following files:${C_RESET}\n" + echo -e "$GIT_CHANGES\n" + exit 1 + fi +fi + + +### +### rebuild kbn-pm distributable to ensure it's not out of date +### +echo " -- building kbn-pm distributable" +yarn kbn run build -i @kbn/pm + +### +### verify no git modifications +### +GIT_CHANGES="$(git ls-files --modified)" +if [ "$GIT_CHANGES" ]; then + echo -e "\n${RED}ERROR: 'yarn kbn run build -i @kbn/pm' caused changes to the following files:${C_RESET}\n" + echo -e "$GIT_CHANGES\n" + exit 1 +fi + +### +### rebuild plugin list to ensure it's not out of date +### +echo " -- building plugin list docs" +node scripts/build_plugin_list_docs + +### +### verify no git modifications +### +GIT_CHANGES="$(git ls-files --modified)" +if [ "$GIT_CHANGES" ]; then + echo -e "\n${RED}ERROR: 'node scripts/build_plugin_list_docs' caused changes to the following files:${C_RESET}\n" + echo -e "$GIT_CHANGES\n" + exit 1 +fi + +### +### rebuild plugin api docs to ensure it's not out of date +### +echo " -- building api docs" +node scripts/build_api_docs + +### +### verify no api changes +### +GIT_CHANGES="$(git ls-files --modified)" +if [ "$GIT_CHANGES" ]; then + echo -e "\n${RED}ERROR: 'node scripts/build_api_docs' caused changes to the following files:${C_RESET}\n" + echo -e "$GIT_CHANGES\n" + exit 1 +fi diff --git a/src/dev/ci_setup/setup.sh b/src/dev/ci_setup/setup.sh index b685b32038f8e..3c08b336f1628 100755 --- a/src/dev/ci_setup/setup.sh +++ b/src/dev/ci_setup/setup.sh @@ -40,66 +40,12 @@ if [[ "$BUILD_TS_REFS_CACHE_CAPTURE" == "true" ]]; then cd "$KIBANA_DIR" fi +if [[ "$DISABLE_BOOTSTRAP_VALIDATIONS" != "true" ]]; then + source "$KIBANA_DIR/src/dev/ci_setup/bootstrap_validations.sh" +fi + ### ### Download es snapshots ### echo " -- downloading es snapshot" node scripts/es snapshot --download-only; - -### -### verify no git modifications -### -GIT_CHANGES="$(git ls-files --modified)" -if [ "$GIT_CHANGES" ]; then - echo -e "\n${RED}ERROR: 'yarn kbn bootstrap' caused changes to the following files:${C_RESET}\n" - echo -e "$GIT_CHANGES\n" - exit 1 -fi - -### -### rebuild kbn-pm distributable to ensure it's not out of date -### -echo " -- building kbn-pm distributable" -yarn kbn run build -i @kbn/pm - -### -### verify no git modifications -### -GIT_CHANGES="$(git ls-files --modified)" -if [ "$GIT_CHANGES" ]; then - echo -e "\n${RED}ERROR: 'yarn kbn run build -i @kbn/pm' caused changes to the following files:${C_RESET}\n" - echo -e "$GIT_CHANGES\n" - exit 1 -fi - -### -### rebuild plugin list to ensure it's not out of date -### -echo " -- building plugin list docs" -node scripts/build_plugin_list_docs - -### -### verify no git modifications -### -GIT_CHANGES="$(git ls-files --modified)" -if [ "$GIT_CHANGES" ]; then - echo -e "\n${RED}ERROR: 'node scripts/build_plugin_list_docs' caused changes to the following files:${C_RESET}\n" - echo -e "$GIT_CHANGES\n" - exit 1 -fi - -### -### rebuild plugin api docs to ensure it's not out of date -### -echo " -- building api docs" -node scripts/build_api_docs - -### -### verify no api changes -### -GIT_CHANGES="$(git ls-files --modified)" -if [ "$GIT_CHANGES" ]; then - echo -e "\n${RED}ERROR: 'node scripts/build_api_docs' caused changes to the following files:${C_RESET}\n" - echo -e "$GIT_CHANGES\n" - exit 1 -fi \ No newline at end of file From fda67adb9f8606e5f8ce8e314ad79e7c1b61c0d1 Mon Sep 17 00:00:00 2001 From: ymao1 Date: Tue, 2 Mar 2021 18:08:58 -0500 Subject: [PATCH 33/33] [Alerting][Docs] Adding template for documenting alert and action types (#92830) * Alert type template * Action type template * Cleanup * Cleanup * Removing callout list * Cleanup * Apply suggestions from code review Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> * Adding title to actions page * PR fixes * PR fixes * PR fixes * PR fixes Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> --- docs/action-type-template.asciidoc | 73 ++++++++ docs/alert-type-template.asciidoc | 39 +++++ .../user/alerting/action-types/email.asciidoc | 59 +++---- .../user/alerting/action-types/index.asciidoc | 31 ++-- docs/user/alerting/action-types/jira.asciidoc | 39 ++--- .../alerting/action-types/pagerduty.asciidoc | 156 ++++++------------ .../alerting/action-types/resilient.asciidoc | 39 ++--- .../alerting/action-types/server-log.asciidoc | 7 +- .../alerting/action-types/servicenow.asciidoc | 35 ++-- .../user/alerting/action-types/slack.asciidoc | 22 +-- .../user/alerting/action-types/teams.asciidoc | 21 +-- .../alerting/action-types/webhook.asciidoc | 48 ++---- docs/user/alerting/alert-types.asciidoc | 5 +- docs/user/alerting/defining-alerts.asciidoc | 9 +- .../images/slack-copy-webhook-url.png | Bin 42332 -> 21738 bytes .../alerting/stack-alerts/es-query.asciidoc | 33 ++-- .../stack-alerts/index-threshold.asciidoc | 74 ++++----- x-pack/plugins/actions/README.md | 4 +- x-pack/plugins/alerts/README.md | 18 +- 19 files changed, 335 insertions(+), 377 deletions(-) create mode 100644 docs/action-type-template.asciidoc create mode 100644 docs/alert-type-template.asciidoc diff --git a/docs/action-type-template.asciidoc b/docs/action-type-template.asciidoc new file mode 100644 index 0000000000000..5b61c259563ad --- /dev/null +++ b/docs/action-type-template.asciidoc @@ -0,0 +1,73 @@ +[[-action-type]] +=== action +++++ + +++++ + +Include a short description of the action type. + +[float] +[[-connector-configuration]] +==== Connector configuration + + connectors have the following configuration properties. + +//// +List of user-facing connector configurations. This should align with the fields available in the Create connector flyout form for this action type. +//// + +Property1:: A short description of this property. +Property2:: A short description of this property with format hints. This can be specified in `this specific format`. + +[float] +[[Preconfigured--configuration]] +==== Preconfigured action type + +//// +Example preconfigured format for this action type +//// + +[source,text] +-- + my-: + name: preconfigured--action-type + actionTypeId: . + config: + property1: value1 + property2: value2 + secrets: + property3: value3 +-- + +[float] +[[-connector-config-properties]] +//// +List of properties from the ConfigSchema and SecretsSchema for this action type. +//// +Config defines information for the action type. + +`property1`:: A short description of this property. +`property2`:: A short descriptionn of this property. + +Secrets defines sensitive information for the action type. + +`property3`:: A short descriptionn of this property. + +[float] +[[-action-configuration]] +==== Action configuration + + actions have the following configuration properties. + +//// +List of user-facing action configurations. This should align with the fields available in the Action section of the Create/Update alert flyout. +//// + +Property1:: A short description of this property. +Property2:: A short description of this property with format hints. This can be specified in `this specific format`. + +//// +Optional - additional configuration details here +[[configuring-]] +==== Configure +//// diff --git a/docs/alert-type-template.asciidoc b/docs/alert-type-template.asciidoc new file mode 100644 index 0000000000000..292ed00d05496 --- /dev/null +++ b/docs/alert-type-template.asciidoc @@ -0,0 +1,39 @@ +[[alert-type-]] +=== + +Include a short description of the alert type. + +[float] +==== Create the alert + +Fill in the <>, then select **. + +[float] +==== Define the conditions + +Define properties to detect the condition. + +//// +Optional, include a screenshot +[role="screenshot"] +image::user/alerting/images/alert-types--conditions.png[Conditions for alert type] +//// + +Condition1:: This is a condition the user must define. +Condition2:: This is another condition the user must define. + +[float] +==== Add action variables + +<> to run when the alert condition is met. The following variables are specific to the alert. You can also specify <>. + +`context.variableA`:: A short description of the context variable defined by the alert type. +`context.variableB`:: A short description of the context variable defined by the alert type with an example. Example: `this is what variableB outputs`. + +//// +Optional, include a step-by-step example for creating this alert +[float] +==== Example + +In this section, you will use the {kib} <> to setup and tune the conditions on an alert. For this example, we want to detect when . +//// \ No newline at end of file diff --git a/docs/user/alerting/action-types/email.asciidoc b/docs/user/alerting/action-types/email.asciidoc index 0c238da1b39e3..3813eccd048d9 100644 --- a/docs/user/alerting/action-types/email.asciidoc +++ b/docs/user/alerting/action-types/email.asciidoc @@ -1,6 +1,9 @@ [role="xpack"] [[email-action-type]] === Email action +++++ +Email +++++ The email action type uses the SMTP protocol to send mail message, using an integration of https://nodemailer.com/[Nodemailer]. Email message text is sent as both plain text and html text. @@ -10,14 +13,15 @@ NOTE: For emails to have a footer with a link back to {kib}, set the <"` format. See the https://nodemailer.com/message/addresses/[Nodemailer address documentation] for more information. Host:: Host name of the service provider. If you are using the <> setting, make sure this hostname is added to the allowed hosts. Port:: The port to connect to on the service provider. Secure:: If true, the connection will use TLS when connecting to the service provider. Refer to the https://nodemailer.com/smtp/#tls-options[Nodemailer TLS documentation] for more information. If not true, the connection will initially connect over TCP, then attempt to switch to TLS via the SMTP STARTTLS command. -User:: Username for login type authentication. +Require authentication:: If true, a username and password for login type authentication must be provided. +Username:: Username for login type authentication. Password:: Password for login type authentication. [float] @@ -39,56 +43,33 @@ Password:: Password for login type authentication. password: passwordkeystorevalue -- -[[email-connector-config-properties]] -**`config`** defines the action type specific to the configuration and contains the following properties: +Config defines information for the action type. -[cols="2*<"] -|=== +`service`:: The name of a https://nodemailer.com/smtp/well-known/[well-known email service provider]. If `service` is provided, `host`, `port`, and `secure` properties are ignored. For more information on the `gmail` service value, see the https://nodemailer.com/usage/using-gmail/[Nodemailer Gmail documentation]. +`from`:: An email address that corresponds to *Sender*. +`host`:: A string that corresponds to *Host*. +`port`:: A number that corresponds to *Port*. +`secure`:: A boolean that corresponds to *Secure*. +`hasAuth`:: A boolean that corresponds to *Requires authentication*. If `true`, this connector will require values for `user` and `password` inside the secrets configuration. Defaults to `true`. -| `service` -| The name of a https://nodemailer.com/smtp/well-known/[well-known email service provider]. If `service` is provided, `host`, `port`, and `secure` properties are ignored. For more information on the `gmail` service value, see the (https://nodemailer.com/usage/using-gmail/)[Nodemailer Gmail documentation]. +Secrets defines sensitive information for the action type. -| `from` -| An email address that corresponds to *Sender*. +`user`:: A string that corresponds to *Username*. Required if `hasAuth` is set to `true`. +`password`:: A string that corresponds to *Password*. Should be stored in the <>. Required if `hasAuth` is set to `true`. -| `host` -| A string that corresponds to *Host*. - -| `port` -| A number that corresponds to *Port*. - -| `secure` -| A boolean that corresponds to *Secure*. - -| `hasAuth` -| If `true`, this connector will require values for `user` and `password` inside the secrets configuration. Defaults to `true`. - -|=== - -**`secrets`** defines sensitive information for the action type and contains the following properties: - -[cols="2*<"] -|=== - -| `user` -| A string that corresponds to *User*. Required if `hasAuth` is set to `true`. - -| `password` -| A string that corresponds to *Password*. Should be stored in the <>. Required if `hasAuth` is set to `true`. - -|=== +[float] [[email-action-configuration]] ==== Action configuration -Email actions have the following configuration properties: +Email actions have the following configuration properties. -To, CC, BCC:: Each is a list of addresses. Addresses can be specified in `user@host-name` format, or in `name ` format. One of To, CC, or BCC must contain an entry. +To, CC, BCC:: Each item is a list of addresses. Addresses can be specified in `user@host-name` format, or in `name ` format. One of To, CC, or BCC must contain an entry. Subject:: The subject line of the email. Message:: The message text of the email. Markdown format is supported. [[configuring-email]] -==== Configuring email accounts +==== Configuring email accounts for well-known services The email action can send email using many popular SMTP email services. diff --git a/docs/user/alerting/action-types/index.asciidoc b/docs/user/alerting/action-types/index.asciidoc index 7ecc1cdb4f74e..a57048243d757 100644 --- a/docs/user/alerting/action-types/index.asciidoc +++ b/docs/user/alerting/action-types/index.asciidoc @@ -1,6 +1,9 @@ [role="xpack"] [[index-action-type]] === Index action +++++ +Index +++++ The index action type will index a document into {es}. See also the {ref}/indices-create-index.html[create index API]. @@ -8,7 +11,7 @@ The index action type will index a document into {es}. See also the {ref}/indice [[index-connector-configuration]] ==== Connector configuration -Index connectors have the following configuration properties: +Index connectors have the following configuration properties. Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. Index:: The {es} index to be written to. @@ -30,32 +33,24 @@ Execution time field:: This field will be automatically set to the time the ale executionTimeField: somedate -- -[[index-connector-config-properties]] -**`config`** defines the action type specific to the configuration and contains the following properties: - -[cols="2*<"] -|=== - -|`index` -| A string that corresponds to *Index*. - -|`refresh` -| A boolean that corresponds to *Refresh*. Defaults to `false`. - -|`executionTimeField` -| A string that corresponds to *Execution time field*. - -|=== +Config defines information for the action type. +`index`:: A string that corresponds to *Index*. +`refresh`:: A boolean that corresponds to *Refresh*. Defaults to `false`. +`executionTimeField`:: A string that corresponds to *Execution time field*. [float] [[index-action-configuration]] ==== Action configuration -Index actions have the following properties: +Index actions have the following properties. Document:: The document to index in JSON format. +[float] +[[index-action-example]] +==== Example + Example of the index document for Index Threshold alert: [source,text] diff --git a/docs/user/alerting/action-types/jira.asciidoc b/docs/user/alerting/action-types/jira.asciidoc index d37f565c1739b..a1941b4b30283 100644 --- a/docs/user/alerting/action-types/jira.asciidoc +++ b/docs/user/alerting/action-types/jira.asciidoc @@ -1,6 +1,9 @@ [role="xpack"] [[jira-action-type]] === Jira action +++++ +Jira +++++ The Jira action type uses the https://developer.atlassian.com/cloud/jira/platform/rest/v2/[REST API v2] to create Jira issues. @@ -8,7 +11,7 @@ The Jira action type uses the https://developer.atlassian.com/cloud/jira/platfor [[jira-connector-configuration]] ==== Connector configuration -Jira connectors have the following configuration properties: +Jira connectors have the following configuration properties. Name:: The name of the connector. The name is used to identify a connector in the **Stack Management** UI connector listing, and in the connector list when configuring an action. URL:: Jira instance URL. @@ -33,37 +36,21 @@ API token (or password):: Jira API authentication token (or password) for HTTP apiToken: tokenkeystorevalue -- -[[jira-connector-config-properties]] -**`config`** defines the action type specific to the configuration and contains the following properties: +Config defines information for the action type. -[cols="2*<"] -|=== +`apiUrl`:: An address that corresponds to *URL*. +`projectKey`:: A key that corresponds to *Project Key*. -| `apiUrl` -| An address that corresponds to *URL*. +Secrets defines sensitive information for the action type. -| `projectKey` -| A key that corresponds to *Project Key*. - -|=== - -**`secrets`** defines sensitive information for the action type and contains the following properties: - -[cols="2*<"] -|=== - -| `email` -| A string that corresponds to *Email*. - -| `apiToken` -| A string that corresponds to *API Token*. Should be stored in the <>. - -|=== +`email`:: A string that corresponds to *Email*. +`apiToken`:: A string that corresponds to *API Token*. Should be stored in the <>. +[float] [[jira-action-configuration]] ==== Action configuration -Jira actions have the following configuration properties: +Jira actions have the following configuration properties. Issue type:: The type of the issue. Priority:: The priority of the incident. @@ -74,6 +61,6 @@ Parent:: The ID or key of the parent issue. Only for `Subtask` issue types. Additional comments:: Additional information for the client, such as how to troubleshoot the issue. [[configuring-jira]] -==== Configuring and testing Jira +==== Configure Jira Jira offers free https://www.atlassian.com/software/jira/free[Instances], which you can use to test incidents. diff --git a/docs/user/alerting/action-types/pagerduty.asciidoc b/docs/user/alerting/action-types/pagerduty.asciidoc index cadf8e0b16a44..f74b5773b3719 100644 --- a/docs/user/alerting/action-types/pagerduty.asciidoc +++ b/docs/user/alerting/action-types/pagerduty.asciidoc @@ -1,49 +1,72 @@ [role="xpack"] [[pagerduty-action-type]] === PagerDuty action +++++ +PagerDuty +++++ The PagerDuty action type uses the https://v2.developer.pagerduty.com/docs/events-api-v2[v2 Events API] to trigger, acknowledge, and resolve PagerDuty alerts. -* <> -* <> -* <> - [float] -[[pagerduty-benefits]] -==== PagerDuty + Elastic integration benefits +[[pagerduty-connector-configuration]] +==== Connector configuration -By integrating PagerDuty with alerts, you can: +PagerDuty connectors have the following configuration properties. -* Route your alerts to the right PagerDuty responder within your team, based on your structure, escalation policies, and workflows. -* Automatically generate incidents of different types and severity based on each alert’s context. -* Tailor the incident data to match your needs by easily passing the alerting context from Kibana to PagerDuty. +Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. +API URL:: An optional PagerDuty event URL. Defaults to `https://events.pagerduty.com/v2/enqueue`. If you are using the <> setting, make sure the hostname is added to the allowed hosts. +Integration Key:: A 32 character PagerDuty Integration Key for an integration on a service, also referred to as the routing key. [float] -[[pagerduty-how-it-works]] -===== How it works +[[Preconfigured-pagerduty-configuration]] +==== Preconfigured action type + +[source,text] +-- + my-pagerduty: + name: preconfigured-pagerduty-action-type + actionTypeId: .pagerduty + config: + apiUrl: https://test.host + secrets: + routingKey: testroutingkey +-- + +Config defines information for the action type. + +`apiURL`:: A URL string that corresponds to *API URL*. -{kib} allows you to create alerts to notify you of a significant move -in your dataset. -You can create alerts for all your Observability, Security, and Elastic Stack use cases. -Alerts will trigger a new incident on the corresponding PagerDuty service. +Secrets defines sensitive information for the action type. + +`routingKey`:: A string that corresponds to *Integration Key*. [float] -===== Requirements +[[pagerduty-action-configuration]] +==== Action configuration -In the `kibana.yml` configuration file, you must add the <>. -This is required to encrypt parameters that must be secured, for example PagerDuty’s integration key. +PagerDuty actions have the following properties. -If you have security enabled: +Severity:: The perceived severity of on the affected system. This can be one of `Critical`, `Error`, `Warning` or `Info`(default). +Event action:: One of `Trigger` (default), `Resolve`, or `Acknowledge`. See https://v2.developer.pagerduty.com/docs/events-api-v2#event-action[event action] for more details. +Dedup Key:: All actions sharing this key will be associated with the same PagerDuty alert. This value is used to correlate trigger and resolution. This value is *optional*, and if not set, defaults to `:`. The maximum length is *255* characters. See https://v2.developer.pagerduty.com/docs/events-api-v2#alert-de-duplication[alert deduplication] for details. +Timestamp:: An *optional* https://v2.developer.pagerduty.com/v2/docs/types#datetime[ISO-8601 format date-time], indicating the time the event was detected or generated. +Component:: An *optional* value indicating the component of the source machine that is responsible for the event, for example `mysql` or `eth0`. +Group:: An *optional* value indicating the logical grouping of components of a service, for example `app-stack`. +Source:: An *optional* value indicating the affected system, preferably a hostname or fully qualified domain name. Defaults to the {kib} saved object id of the action. +Summary:: An *optional* text summary of the event, defaults to `No summary provided`. The maximum length is 1024 characters. +Class:: An *optional* value indicating the class/type of the event, for example `ping failure` or `cpu load`. -* You must have -application privileges to access Metrics, APM, Uptime, or Security. -* If you are using a self-managed deployment with security, you must have -Transport Security Layer (TLS) enabled for communication <>. -Alerts uses API keys to secure background alert checks and actions, -and API keys require {ref}/configuring-tls.html#tls-http[TLS on the HTTP interface]. +For more details on these properties, see https://v2.developer.pagerduty.com/v2/docs/send-an-event-events-api-v2[PagerDuty v2 event parameters]. -Although not a requirement, to harden the integrations security you might want to -review the <> that are available to you. +[float] +[[pagerduty-benefits]] +==== Configure PagerDuty + +By integrating PagerDuty with alerts, you can: + +* Route your alerts to the right PagerDuty responder within your team, based on your structure, escalation policies, and workflows. +* Automatically generate incidents of different types and severity based on each alert’s context. +* Tailor the incident data to match your needs by easily passing the alerting context from Kibana to PagerDuty. [float] [[pagerduty-support]] @@ -111,80 +134,3 @@ To see the available context variables, click on the *Add alert variable* icon n to each corresponding field. For more details on these parameters, see the <> and the PagerDuty https://v2.developer.pagerduty.com/v2/docs/send-an-event-events-api-v2[API v2 documentation]. - - -[float] -[[pagerduty-uninstall]] -===== How to uninstall -To remove a PagerDuty connector from an alert, simply remove it -from the *Actions* section of that alert, using the remove (x) icon. -This will disable the integration for the particular alert. - -To delete the connector entirely, open the main menu, then click *Stack Management > Alerts and Actions*. -Select the *Connectors* tab, and then click on the delete icon. -This is an irreversible action and impacts all alerts that use this connector. - - -[float] -[[pagerduty-connector-configuration]] -==== Connector configuration - -PagerDuty connectors have the following configuration properties: - -Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. -API URL:: An optional PagerDuty event URL. Defaults to `https://events.pagerduty.com/v2/enqueue`. If you are using the <> setting, make sure the hostname is added to the allowed hosts. -Integration Key:: A 32 character PagerDuty Integration Key for an integration on a service, also referred to as the routing key. - -[float] -[[Preconfigured-pagerduty-configuration]] -==== Preconfigured action type - -[source,text] --- - my-pagerduty: - name: preconfigured-pagerduty-action-type - actionTypeId: .pagerduty - config: - apiUrl: https://test.host - secrets: - routingKey: testroutingkey --- - -[[pagerduty-connector-config-properties]] -**`config`** defines the action type specific to the configuration and contains the following properties: - -[cols="2*<"] -|=== - -|`apiURL` -| A URL string that corresponds to *API URL*. - -|=== - -**`secrets`** defines sensitive information for the action type and contains the following properties: - -[cols="2*<"] -|=== - -|`routingKey` -| A string that corresponds to *Integration Key*. - -|=== - -[float] -[[pagerduty-action-configuration]] -==== Action configuration - -PagerDuty actions have the following properties: - -Severity:: The perceived severity of on the affected system. This can be one of `Critical`, `Error`, `Warning` or `Info`(default). -Event action:: One of `Trigger` (default), `Resolve`, or `Acknowledge`. See https://v2.developer.pagerduty.com/docs/events-api-v2#event-action[event action] for more details. -Dedup Key:: All actions sharing this key will be associated with the same PagerDuty alert. This value is used to correlate trigger and resolution. This value is *optional*, and if not set, defaults to `:`. The maximum length is *255* characters. See https://v2.developer.pagerduty.com/docs/events-api-v2#alert-de-duplication[alert deduplication] for details. -Timestamp:: An *optional* https://v2.developer.pagerduty.com/v2/docs/types#datetime[ISO-8601 format date-time], indicating the time the event was detected or generated. -Component:: An *optional* value indicating the component of the source machine that is responsible for the event, for example `mysql` or `eth0`. -Group:: An *optional* value indicating the logical grouping of components of a service, for example `app-stack`. -Source:: An *optional* value indicating the affected system, preferably a hostname or fully qualified domain name. Defaults to the {kib} saved object id of the action. -Summary:: An *optional* text summary of the event, defaults to `No summary provided`. The maximum length is 1024 characters. -Class:: An *optional* value indicating the class/type of the event, for example `ping failure` or `cpu load`. - -For more details on these properties, see https://v2.developer.pagerduty.com/v2/docs/send-an-event-events-api-v2[PagerDuty v2 event parameters]. diff --git a/docs/user/alerting/action-types/resilient.asciidoc b/docs/user/alerting/action-types/resilient.asciidoc index feca42a542a2f..296156875ceb6 100644 --- a/docs/user/alerting/action-types/resilient.asciidoc +++ b/docs/user/alerting/action-types/resilient.asciidoc @@ -1,6 +1,9 @@ [role="xpack"] [[resilient-action-type]] === IBM Resilient action +++++ +IBM Resilient +++++ The IBM Resilient action type uses the https://developer.ibm.com/security/resilient/rest/[RESILIENT REST v2] to create IBM Resilient incidents. @@ -8,7 +11,7 @@ The IBM Resilient action type uses the https://developer.ibm.com/security/resili [[resilient-connector-configuration]] ==== Connector configuration -IBM Resilient connectors have the following configuration properties: +IBM Resilient connectors have the following configuration properties. Name:: The name of the connector. The name is used to identify a connector in the **Stack Management** UI connector listing, and in the connector list when configuring an action. URL:: IBM Resilient instance URL. @@ -33,37 +36,21 @@ API key secret:: The authentication key secret for HTTP Basic authentication. apiKeySecret: tokenkeystorevalue -- -[[resilient-connector-config-properties]] -**`config`** defines the action type specific to the configuration and contains the following properties: +Config defines information for the action type. -[cols="2*<"] -|=== +`apiUrl`:: An address that corresponds to *URL*. +`orgId`:: An ID that corresponds to *Organization ID*. -| `apiUrl` -| An address that corresponds to *URL*. +Secrets defines sensitive information for the action type. -| `orgId` -| An ID that corresponds to *Organization ID*. - -|=== - -**`secrets`** defines sensitive information for the action type and contains the following properties: - -[cols="2*<"] -|=== - -| `apiKeyId` -| A string that corresponds to *API key ID*. - -| `apiKeySecret` -| A string that corresponds to *API Key secret*. Should be stored in the <>. - -|=== +`apiKeyId`:: A string that corresponds to *API key ID*. +`apiKeySecret`:: A string that corresponds to *API Key secret*. Should be stored in the <>. +[float] [[resilient-action-configuration]] ==== Action configuration -IBM Resilient actions have the following configuration properties: +IBM Resilient actions have the following configuration properties. Incident types:: The type of the incident. Severity code:: The severity of the incident. @@ -72,6 +59,6 @@ Description:: The details about the incident. Additional comments:: Additional information for the client, such as how to troubleshoot the issue. [[configuring-resilient]] -==== Configuring and testing IBM Resilient +==== Configure IBM Resilient IBM Resilient offers https://www.ibm.com/security/intelligent-orchestration/resilient[Instances], which you can use to test incidents. diff --git a/docs/user/alerting/action-types/server-log.asciidoc b/docs/user/alerting/action-types/server-log.asciidoc index 276f64e7786bd..7849a70a239c3 100644 --- a/docs/user/alerting/action-types/server-log.asciidoc +++ b/docs/user/alerting/action-types/server-log.asciidoc @@ -1,6 +1,9 @@ [role="xpack"] [[server-log-action-type]] === Server log action +++++ +Server log +++++ This action type writes an entry to the {kib} server log. @@ -8,7 +11,7 @@ This action type writes an entry to the {kib} server log. [[server-log-connector-configuration]] ==== Connector configuration -Server log connectors have the following configuration properties: +Server log connectors have the following configuration properties. Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. @@ -27,7 +30,7 @@ Name:: The name of the connector. The name is used to identify a connector [[server-log-action-configuration]] ==== Action configuration -Server log actions have the following properties: +Server log actions have the following properties. Message:: The message to log. Level:: The log level of the message: `trace`, `debug`, `info`, `warn`, `error` or `fatal`. Defaults to `info`. diff --git a/docs/user/alerting/action-types/servicenow.asciidoc b/docs/user/alerting/action-types/servicenow.asciidoc index 4a11a2e28712a..f002c39416f1a 100644 --- a/docs/user/alerting/action-types/servicenow.asciidoc +++ b/docs/user/alerting/action-types/servicenow.asciidoc @@ -1,6 +1,9 @@ [role="xpack"] [[servicenow-action-type]] === ServiceNow action +++++ +ServiceNow +++++ The ServiceNow action type uses the https://developer.servicenow.com/app.do#!/rest_api_doc?v=orlando&id=c_TableAPI[V2 Table API] to create ServiceNow incidents. @@ -8,7 +11,7 @@ The ServiceNow action type uses the https://developer.servicenow.com/app.do#!/re [[servicenow-connector-configuration]] ==== Connector configuration -ServiceNow connectors have the following configuration properties: +ServiceNow connectors have the following configuration properties. Name:: The name of the connector. The name is used to identify a connector in the **Stack Management** UI connector listing, and in the connector list when configuring an action. URL:: ServiceNow instance URL. @@ -31,34 +34,20 @@ Password:: Password for HTTP Basic authentication. password: passwordkeystorevalue -- -[[servicenow-connector-config-properties]] -**`config`** defines the action type specific to the configuration and contains the following properties: +Config defines information for the action type. -[cols="2*<"] -|=== +`apiUrl`:: An address that corresponds to *URL*. -| `apiUrl` -| An address that corresponds to *URL*. +Secrets defines sensitive information for the action type. -|=== - -**`secrets`** defines sensitive information for the action type and contains the following properties: - -[cols="2*<"] -|=== - -| `username` -| A string that corresponds to *Username*. - -| `password` -| A string that corresponds to *Password*. Should be stored in the <>. - -|=== +`username`:: A string that corresponds to *Username*. +`password`:: A string that corresponds to *Password*. Should be stored in the <>. +[float] [[servicenow-action-configuration]] ==== Action configuration -ServiceNow actions have the following configuration properties: +ServiceNow actions have the following configuration properties. Urgency:: The extent to which the incident resolution can delay. Severity:: The severity of the incident. @@ -68,6 +57,6 @@ Description:: The details about the incident. Additional comments:: Additional information for the client, such as how to troubleshoot the issue. [[configuring-servicenow]] -==== Configuring and testing ServiceNow +==== Configure ServiceNow ServiceNow offers free https://developer.servicenow.com/dev.do#!/guides/madrid/now-platform/pdi-guide/obtaining-a-pdi[Personal Developer Instances], which you can use to test incidents. diff --git a/docs/user/alerting/action-types/slack.asciidoc b/docs/user/alerting/action-types/slack.asciidoc index 6258969753356..6f7d1b3e11d31 100644 --- a/docs/user/alerting/action-types/slack.asciidoc +++ b/docs/user/alerting/action-types/slack.asciidoc @@ -1,6 +1,9 @@ [role="xpack"] [[slack-action-type]] === Slack action +++++ +Slack +++++ The Slack action type uses https://api.slack.com/incoming-webhooks[Slack Incoming Webhooks]. @@ -8,7 +11,7 @@ The Slack action type uses https://api.slack.com/incoming-webhooks[Slack Incomin [[slack-connector-configuration]] ==== Connector configuration -Slack connectors have the following configuration properties: +Slack connectors have the following configuration properties. Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. Webhook URL:: The URL of the incoming webhook. See https://api.slack.com/messaging/webhooks#getting_started[Slack Incoming Webhooks] for instructions on generating this URL. If you are using the <> setting, make sure the hostname is added to the allowed hosts. @@ -26,29 +29,20 @@ Webhook URL:: The URL of the incoming webhook. See https://api.slack.com/messa webhookUrl: 'https://hooks.slack.com/services/abcd/efgh/ijklmnopqrstuvwxyz' -- -**`secrets`** defines sensitive information for the action type and contains the following properties: +Secrets defines sensitive information for the action type. -[cols="2*<"] -|=== - -| `webhookUrl` -| A string that corresponds to *Webhook URL*. - -|=== +`webhookUrl`:: A string that corresponds to *Webhook URL*. [float] [[slack-action-configuration]] ==== Action configuration -Slack actions have the following properties: +Slack actions have the following properties. Message:: The message text, converted to the `text` field in the Webhook JSON payload. Currently only the text field is supported. Markdown, images, and other advanced formatting are not yet supported. [[configuring-slack]] -==== Configuring Slack Accounts - -You configure the accounts Slack action type can use to communicate with Slack in the -connector form. +==== Configure a Slack account You need a https://api.slack.com/incoming-webhooks[Slack webhook URL] to configure a Slack account. To create a webhook diff --git a/docs/user/alerting/action-types/teams.asciidoc b/docs/user/alerting/action-types/teams.asciidoc index 7f4a29dc86fc5..294b5474e390a 100644 --- a/docs/user/alerting/action-types/teams.asciidoc +++ b/docs/user/alerting/action-types/teams.asciidoc @@ -1,6 +1,9 @@ [role="xpack"] [[teams-action-type]] === Microsoft Teams action +++++ +Microsoft Teams +++++ The Microsoft Teams action type uses https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook[Incoming Webhooks]. @@ -8,7 +11,7 @@ The Microsoft Teams action type uses https://docs.microsoft.com/en-us/microsoftt [[teams-connector-configuration]] ==== Connector configuration -Microsoft Teams connectors have the following configuration properties: +Microsoft Teams connectors have the following configuration properties. Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. Webhook URL:: The URL of the incoming webhook. See https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook#add-an-incoming-webhook-to-a-teams-channel[Add Incoming Webhooks] for instructions on generating this URL. If you are using the <> setting, make sure the hostname is added to the allowed hosts. @@ -26,28 +29,20 @@ Webhook URL:: The URL of the incoming webhook. See https://docs.microsoft.com/ webhookUrl: 'https://outlook.office.com/webhook/abcd@0123456/IncomingWebhook/abcdefgh/ijklmnopqrstuvwxyz' -- -[[teams-connector-config-properties]] -**`secrets`** defines sensitive information for the action type and contains the following properties: - -[cols="2*<"] -|=== - -| `webhookUrl` -| A string that corresponds to *Webhook URL*. - -|=== +Secrets defines sensitive information for the action type. +`webhookUrl`:: A string that corresponds to *Webhook URL*. [float] [[teams-action-configuration]] ==== Action configuration -Microsoft Teams actions have the following properties: +Microsoft Teams actions have the following properties. Message:: The message text, converted to the `text` field in the Webhook JSON payload. Currently only the text field is supported. Markdown, images, and other advanced formatting are not yet supported. [[configuring-teams]] -==== Configuring Microsoft Teams Accounts +==== Configure a Microsoft Teams account You need a https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook[Microsoft Teams webhook URL] to configure a Microsoft Teams action. To create a webhook diff --git a/docs/user/alerting/action-types/webhook.asciidoc b/docs/user/alerting/action-types/webhook.asciidoc index efe1077707ef0..381d6e72bf9c0 100644 --- a/docs/user/alerting/action-types/webhook.asciidoc +++ b/docs/user/alerting/action-types/webhook.asciidoc @@ -1,6 +1,9 @@ [role="xpack"] [[webhook-action-type]] === Webhook action +++++ +Webhook +++++ The Webhook action type uses https://github.com/axios/axios[axios] to send a POST or PUT request to a web service. @@ -8,13 +11,14 @@ The Webhook action type uses https://github.com/axios/axios[axios] to send a POS [[webhook-connector-configuration]] ==== Connector configuration -Webhook connectors have the following configuration properties: +Webhook connectors have the following configuration properties. Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. URL:: The request URL. If you are using the <> setting, make sure the hostname is added to the allowed hosts. Method:: HTTP request method, either `POST`(default) or `PUT`. Headers:: A set of key-value pairs sent as headers with the request -User:: Username for HTTP basic authentication. +Require authentication:: If true, a username and password for login type authentication must be provided. +Username:: Username for HTTP basic authentication. Password:: Password for HTTP basic authentication. [float] @@ -36,45 +40,23 @@ Password:: Password for HTTP basic authentication. password: passwordkeystorevalue -- -[[webhook-connector-config-properties]] -**`config`** defines the action type specific to the configuration and contains the following properties: +Config defines information for the action type. -[cols="2*<"] -|=== +`url`:: A URL string that corresponds to *URL*. +`method`:: A string that corresponds to *Method*. +`headers`:: A record that corresponds to *Headers*. +`hasAuth`:: A boolean that corresponds to *Requires authentication*. If `true`, this connector will require values for `user` and `password` inside the secrets configuration. Defaults to `true`. -|`url` -| A URL string that corresponds to *URL*. - -|`method` -| A string that corresponds to *Method*. - -|`headers` -|A record that corresponds to *Headers*. - -| `hasAuth` -| If `true`, this connector will require values for `user` and `password` inside the secrets configuration. Defaults to `true`. - -|=== - -**`secrets`** defines sensitive information for the action type and contains the following properties: - -[cols="2*<"] -|=== - -|`user` -|A string that corresponds to *User*. Required if `hasAuth` is set to `true`. - -|`password` -|A string that corresponds to *Password*. Should be stored in the <>. Required if `hasAuth` is set to `true`. - -|=== +Secrets defines sensitive information for the action type. +`user`:: A string that corresponds to *User*. Required if `hasAuth` is set to `true`. +`password`:: A string that corresponds to *Password*. Should be stored in the <>. Required if `hasAuth` is set to `true`. [float] [[webhook-action-configuration]] ==== Action configuration -Webhook actions have the following properties: +Webhook actions have the following properties. Body:: A JSON payload sent to the request URL. For example: + diff --git a/docs/user/alerting/alert-types.asciidoc b/docs/user/alerting/alert-types.asciidoc index 5afce8fa6cd93..9eac084bd03c4 100644 --- a/docs/user/alerting/alert-types.asciidoc +++ b/docs/user/alerting/alert-types.asciidoc @@ -10,14 +10,13 @@ Kibana provides two types of alerts: [float] ==== Standard stack alerts -Users require the `all` privilege to access to the *Stack Alerts* feature and create and edit alerts. . -See <> for more information. - {kib} provides two stack alerts: * <> * <> +Users require the `all` privilege to access the *Stack Alerts* feature and create and edit alerts. +See <> for more information. [float] ==== Domain-specific alerts diff --git a/docs/user/alerting/defining-alerts.asciidoc b/docs/user/alerting/defining-alerts.asciidoc index 8c8e25cea407a..27f3a6c7309cb 100644 --- a/docs/user/alerting/defining-alerts.asciidoc +++ b/docs/user/alerting/defining-alerts.asciidoc @@ -5,9 +5,9 @@ {kib} alerts can be created in a variety of apps including <>, <>, <>, <>, <> and from <> UI. While alerting details may differ from app to app, they share a common interface for defining and configuring alerts that this section describes in more detail. [float] -=== Alert flyout +=== Create an alert -When an alert is created in an app, the app will display a flyout panel with three main sections to configure: +When you create an alert, you must define the alert details, conditions, and actions. . <> . <> @@ -19,7 +19,7 @@ image::images/alert-flyout-sections.png[The three sections of an alert definitio [[defining-alerts-general-details]] === General alert details -All alerts share the following four properties in common: +All alerts share the following four properties. [role="screenshot"] image::images/alert-flyout-general-details.png[alt='All alerts have name, tags, check every, and notify properties in common'] @@ -69,6 +69,7 @@ Each action type exposes different properties. For example an email action allow image::images/alert-flyout-action-details.png[UI for defining an email action] [float] +[[defining-alerts-actions-variables]] ==== Action variables Using the https://mustache.github.io/[Mustache] template syntax `{{variable name}}`, you can pass alert values at the time a condition is detected to an action. You can access the list of available variables using the "add variable" button. Although available variables differ by alert type, all alert types pass the following variables: @@ -105,6 +106,6 @@ Actions are not required on alerts. You can run an alert without actions to unde ============================================== [float] -=== Managing alerts +=== Manage alerts To modify an alert after it was created, including muting or disabling it, use the <>. diff --git a/docs/user/alerting/images/slack-copy-webhook-url.png b/docs/user/alerting/images/slack-copy-webhook-url.png index 0acc9488e22a335e31a9e429bcc033425f11baac..805f5719980dabed80af6a8fbaebf194b52305c7 100644 GIT binary patch literal 21738 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 CHZpVo literal 42332 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

xC)M&#l`e)|gwE**g_!EThN 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. Fill in the <>, then select *ES query*. - -[role="screenshot"] -image::user/alerting/images/alert-types-es-query-select.png[Choosing an ES query alert type] +Fill in the <>, then select *ES query*. [float] -==== Defining the conditions +==== Define the conditions -The ES query alert has 5 clauses that define the condition to detect. +Define properties to detect the condition. [role="screenshot"] -image::user/alerting/images/alert-types-es-query-conditions.png[Four clauses define the condition to detect] +image::user/alerting/images/alert-types-es-query-conditions.png[Five clauses define the condition to detect] Index:: This clause requires an *index or index pattern* and a *time field* that will be used for the *time window*. Size:: This clause specifies the number of documents to pass to the configured actions when the the threshold condition is met. @@ -29,9 +25,9 @@ Threshold:: This clause defines a threshold value and a comparison operator (`i Time window:: This clause determines how far back to search for documents, using the *time field* set in the *index* clause. Generally this value should be set to a value higher than the *check every* value in the <>, to avoid gaps in detection. [float] -==== Action variables +==== Add action variables -When the ES query alert condition is met, the following variables are available to use inside each action: +<> to run when the alert condition is met. The following variables are specific to the ES query alert. You can also specify <>. `context.title`:: A preconstructed title for the alert. Example: `alert term match alert query matched`. `context.message`:: A preconstructed message for the alert. Example: + @@ -45,22 +41,23 @@ When the ES query alert condition is met, the following variables are available `context.value`:: The value of the alert that met the condition. `context.conditions`:: A description of the condition. Example: `count greater than 4`. `context.hits`:: The most recent ES documents that matched the query. Using the https://mustache.github.io/[Mustache] template array syntax, you can iterate over these hits to get values from the ES documents into your actions. - ++ [role="screenshot"] image::images/alert-types-es-query-example-action-variable.png[Iterate over hits using Mustache template syntax] + [float] -==== Testing your query +==== Test your query Use the *Test query* feature to verify that your query DSL is valid. -When your query is valid:: Valid queries will be executed against the configured *index* using the configured *time window*. The number of documents that +* Valid queries are executed against the configured *index* using the configured *time window*. The number of documents that match the query will be displayed. - ++ [role="screenshot"] image::user/alerting/images/alert-types-es-query-valid.png[Test ES query returns number of matches when valid] -When your query is invalid:: An error message is shown if the query is invalid. - +* An error message is shown if the query is invalid. ++ [role="screenshot"] image::user/alerting/images/alert-types-es-query-invalid.png[Test ES query shows error when invalid] \ No newline at end of file diff --git a/docs/user/alerting/stack-alerts/index-threshold.asciidoc b/docs/user/alerting/stack-alerts/index-threshold.asciidoc index 6b45f69401c4a..89ca8e3087f12 100644 --- a/docs/user/alerting/stack-alerts/index-threshold.asciidoc +++ b/docs/user/alerting/stack-alerts/index-threshold.asciidoc @@ -2,20 +2,17 @@ [[alert-type-index-threshold]] === Index threshold -The index threshold alert type is designed to run an {es} query over indices, aggregating field values from documents, comparing them to threshold values, and scheduling actions to run when the thresholds are met. +The index threshold alert type runs an {es} query. It aggregates field values from documents, compares them to threshold values, and schedules actions to run when the thresholds are met. [float] -==== Creating the alert +==== Create the alert -An index threshold alert can be created from the *Create* button in the <>. Fill in the <>, then select *Index Threshold*. - -[role="screenshot"] -image::user/alerting/images/alert-types-index-threshold-select.png[Choosing an index threshold alert type] +Fill in the <>, then select *Index Threshold*. [float] -==== Defining the conditions +==== Define the conditions -The index threshold has 5 clauses that define the condition to detect. +Define properties to detect the condition. [role="screenshot"] image::user/alerting/images/alert-types-index-threshold-conditions.png[Five clauses define the condition to detect] @@ -32,9 +29,9 @@ If data is available and all clauses have been defined, a preview chart will ren image::user/alerting/images/alert-types-index-threshold-preview.png[Five clauses define the condition to detect] [float] -==== Action variables +==== Add action variables -When the index threshold alert condition is met, the following variables are available to use inside each action: +<> to run when the alert condition is met. The following variables are specific to the index threshold alert. You can also specify <>. `context.title`:: A preconstructed title for the alert. Example: `alert kibana sites - high egress met threshold`. `context.message`:: A preconstructed message for the alert. Example: + @@ -51,68 +48,53 @@ When the index threshold alert condition is met, the following variables are ava [float] ==== Example -In this section, you will use the {kib} <> to setup and tune the conditions on an index threshold alert. For this example, we want to detect when any of our top three sites have served more than 420,000 bytes over a 24 hour period. +In this example, you will use the {kib} <> to set up and tune the conditions on an index threshold alert. For this example, you want to detect when any of the top four sites serve more than 420,000 bytes over a 24 hour period. -From the <>, create a new alert, and fill in the <>. This alert will be checked every 4 hours, and will not execute actions more than once per day. Choose the index threshold alert type. +. Open the main menu, then click **Stack Management > Alerts and Actions**. +. Create a new alert that is checked every four hours and executes actions when the alert status changes. ++ [role="screenshot"] image::user/alerting/images/alert-types-index-threshold-select.png[Choosing an index threshold alert type] -Click on each clause to open a control that helps you set the value: - -[float] -==== Index clause -The index clause control will list and allow you to search for available indices. Choose *kibana_sample_data_logs* +. Select the **Index threshold** alert type. +. Click *Index*, and set *Indices to query* to *kibana_sample_data_logs*. ++ [role="screenshot"] image::user/alerting/images/alert-types-index-threshold-example-index.png[Choosing an index] -Once an index is selected, the list of time fields for that index will be available to select. Choose *@timestamp*. - +. Set the *Time field* to *@timestamp*. ++ [role="screenshot"] image::user/alerting/images/alert-types-index-threshold-example-timefield.png[Choosing a time field] -[float] -==== When clause - -We want to detect the number of bytes served during the time window, so we select `sum` as the aggregation, and `bytes` as the field to aggregate. - +. To detect the number of bytes served during the time window, click *When* and select `sum` as the aggregation, and bytes as the field to aggregate. ++ [role="screenshot"] image::user/alerting/images/alert-types-index-threshold-example-aggregation.png[Choosing the aggregation] -[float] -==== Over/Grouped over clause - -We want to alert on the three sites that have the most traffic, so we'll group the sum of bytes by the `host.keyword` field and take the top 3 values. - +. To detect the four sites that have the most traffic, click *Over* and select `top`, enter `4`, and select `host.keyword` as the field. ++ [role="screenshot"] image::user/alerting/images/alert-types-index-threshold-example-grouping.png[Choosing the groups] -[float] -==== Threshold clause - -We want to alert when any site exceeds 420,000 bytes over a 24 hour period, so we'll set the threshold to 420,000 and use the `is above` comparison. - +. To alert when any of the top four sites exceeds 420,000 bytes over a 24 hour period, select `is above` and enter `420000`. ++ [role="screenshot"] image::user/alerting/images/alert-types-index-threshold-example-threshold.png[Setting the threshold] -[float] -==== Time window clause - -Finally, set the time window to 24 hours to complete the alert configuration. - +. Finally, click *For the last*, enter `24` and select `hours` to complete the alert configuration. ++ [role="screenshot"] image::user/alerting/images/alert-types-index-threshold-example-window.png[Setting the time window] -The preview chart will render showing the 24 hour sum of bytes at 4 hours intervals (the *check every* interval) for the past 120 hours (the last 30 intervals). - +. The preview chart will render showing the 24 hour sum of bytes at 4 hours intervals (the *check every* interval) for the past 120 hours (the last 30 intervals). ++ [role="screenshot"] image::user/alerting/images/alert-types-index-threshold-example-preview.png[Setting the time window] -[float] -==== Comparing time windows - -You can interactively change the time window and observe the effect it has on the chart. Compare a 24 window to a 12 hour window. Notice the variability in the sum of bytes, due to different traffic levels during the day compared to at night. This variability would result in noisy alerts, so the 24 hour window is better. The preview chart can help you find the right values for your alert. - +. Change the time window and observe the effect it has on the chart. Compare a 24 window to a 12 hour window. Notice the variability in the sum of bytes, due to different traffic levels during the day compared to at night. This variability would result in noisy alerts, so the 24 hour window is better. The preview chart can help you find the right values for your alert. ++ [role="screenshot"] image::user/alerting/images/alert-types-index-threshold-example-comparison.png[Comparing two time windows] \ No newline at end of file diff --git a/x-pack/plugins/actions/README.md b/x-pack/plugins/actions/README.md index f1be1ec12b79c..3ec8545017ca1 100644 --- a/x-pack/plugins/actions/README.md +++ b/x-pack/plugins/actions/README.md @@ -434,7 +434,9 @@ Actions that take URLs or hostnames should check that those values are allowed. ## documentation -You should also create some asciidoc for the new action type. An entry should be made in the action type index - [`docs/user/alerting/action-types.asciidoc`](../../../docs/user/alerting/action-types.asciidoc) which points to a new document for the action type that should be in the directory [`docs/user/alerting/action-types`](../../../docs/user/alerting/action-types). +You should create asciidoc for the new action type. Add an entry to the action type index - [`docs/user/alerting/action-types.asciidoc`](../../../docs/user/alerting/action-types.asciidoc), which points to a new document for the action type that should be in the directory [`docs/user/alerting/action-types`](../../../docs/user/alerting/action-types). + +We suggest following the template provided in `docs/action-type-template.asciidoc`. The [Email action type](https://www.elastic.co/guide/en/kibana/master/email-action-type.html) is an example of documentation created following the template. ## tests diff --git a/x-pack/plugins/alerts/README.md b/x-pack/plugins/alerts/README.md index 07bad42a3bfa3..057d86e4c0f31 100644 --- a/x-pack/plugins/alerts/README.md +++ b/x-pack/plugins/alerts/README.md @@ -19,9 +19,10 @@ Table of Contents - [Alert types](#alert-types) - [Methods](#methods) - [Executor](#executor) - - [Licensing](#licensing) - - [Documentation](#documentation) - - [Tests](#tests) + - [Action variables](#action-variables) + - [Licensing](#licensing) + - [Documentation](#documentation) + - [Tests](#tests) - [Example](#example) - [Role Based Access-Control](#role-based-access-control) - [Alert Navigation](#alert-navigation) @@ -147,9 +148,9 @@ This is the primary function for an alert type. Whenever the alert needs to exec |createdBy|The userid that created this alert.| |updatedBy|The userid that last updated this alert.| -### The `actionVariables` property +### Action Variables -This property should contain the **flattened** names of the state and context variables available when an executor calls `alertInstance.scheduleActions(actionGroup, context)`. These names are meant to be used in prompters in the alerting user interface, are used as text values for display, and can be inserted into to an action parameter text entry field via UI gesture (eg, clicking a menu item from a menu built with these names). They should be flattened, so if a state or context variable is an object with properties, these should be listed with the "parent" property/properties in the name, separated by a `.` (period). +The `actionVariables` property should contain the **flattened** names of the state and context variables available when an executor calls `alertInstance.scheduleActions(actionGroup, context)`. These names are meant to be used in prompters in the alerting user interface, are used as text values for display, and can be inserted into to an action parameter text entry field via UI gesture (eg, clicking a menu item from a menu built with these names). They should be flattened, so if a state or context variable is an object with properties, these should be listed with the "parent" property/properties in the name, separated by a `.` (period). For example, if the `context` has one variable `foo` which is an object that has one property `bar`, and there are no `state` variables, the `actionVariables` value would be in the following shape: @@ -167,7 +168,12 @@ Currently most of the alerts are free features. But some alert types are subscri ## Documentation -You should create documentation for the new alert type. Make an entry in the alert type index [`docs/user/alerting/alert-types.asciidoc`](../../../docs/user/alerting/alert-types.asciidoc) that points to a new document for the alert type that should be in the proper application directory. +You should create asciidoc for the new alert type. +* For stack alerts, add an entry to the alert type index - [`docs/user/alerting/alert-types.asciidoc`](../../../docs/user/alerting/alert-types.asciidoc) which points to a new document for the alert type that should be in the directory [`docs/user/alerting/stack-alerts`](../../../docs/user/alerting/stack-alerts). + +* Solution specific alert documentation should live within the docs for the solution. + +We suggest following the template provided in `docs/alert-type-template.asciidoc`. The [Index Threshold alert type](https://www.elastic.co/guide/en/kibana/master/alert-type-index-threshold.html) is an example of documentation created following the template. ## Tests

W*_pdOd{W+4P?o&VT6AM%^E=?N1wX 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 VAUMk*;UEJLc)I$ztaD0e0svNfxw!xU literal 255161 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%0A+o&Bpl$9vG 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≪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