From 6ed93c3571b4a655d8545397497f8603573910e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20Haro?= Date: Tue, 27 Apr 2021 21:45:19 +0200 Subject: [PATCH] [Telemetry] Remove all usages of `any` (#98338) --- .eslintrc.js | 18 + api_docs/telemetry.json | 890 +++++++++++++++--- api_docs/telemetry.mdx | 9 +- ...na-plugin-plugins-data-public.searchbar.md | 4 +- packages/kbn-analytics/src/reporter.ts | 2 +- packages/kbn-analytics/src/storage.ts | 6 +- packages/kbn-analytics/src/util.ts | 2 +- .../public/management_app/types.ts | 3 +- src/plugins/data/server/server.api.md | 1 - ...emetry_application_usage_collector.test.ts | 19 +- .../register_config_usage_collector.test.ts | 2 +- .../core/core_usage_collector.test.ts | 2 +- .../kibana/get_saved_object_counts.test.ts | 6 +- .../server/collectors/kibana/index.test.ts | 3 +- .../telemetry_management_collector.test.ts | 7 +- .../telemetry_management_collector.ts | 5 +- .../server/collectors/ui_metric/index.test.ts | 56 +- .../get_telemetry_failure_details.test.ts | 12 +- .../get_telemetry_opt_in.test.ts | 3 +- .../components/opted_in_notice_banner.tsx | 2 +- src/plugins/telemetry/public/index.ts | 3 +- .../render_opt_in_banner.tsx | 2 +- .../public/services/telemetry_sender.ts | 4 +- .../collectors/usage/ensure_deep_object.ts | 5 +- .../usage/telemetry_usage_collector.test.ts | 12 +- src/plugins/telemetry/server/fetcher.ts | 19 +- src/plugins/telemetry/server/index.ts | 3 +- .../get_cluster_info.test.ts | 10 +- .../get_cluster_stats.test.ts | 12 +- .../get_data_telemetry.test.ts | 2 +- .../server/telemetry_collection/get_kibana.ts | 6 +- .../get_local_stats.test.ts | 19 +- .../telemetry_collection/get_local_stats.ts | 4 +- .../telemetry_collection/get_nodes_usage.ts | 12 +- .../server/telemetry_collection/index.ts | 1 + .../get_telemetry_saved_object.test.ts | 31 +- .../server/encryption/encrypt.ts | 8 +- .../server/plugin.ts | 10 +- ...telemetry_management_section.test.tsx.snap | 20 +- .../components/opt_in_example_flyout.tsx | 4 +- .../telemetry_management_section.test.tsx | 17 +- .../telemetry_management_section.tsx | 41 +- .../telemetry_management_section_wrapper.tsx | 12 +- .../public/plugin.tsx | 15 +- .../server/collector/collector.ts | 14 +- .../server/collector/collector_set.test.ts | 20 +- .../server/collector/collector_set.ts | 9 +- .../server/collector/usage_collector.ts | 2 + .../server/report/store_report.test.ts | 2 +- .../server/routes/stats/stats.ts | 15 +- .../telemetry_collection/get_license.test.ts | 6 +- .../get_stats_with_xpack.test.ts | 31 +- .../get_stats_with_xpack.ts | 4 +- .../is_cluster_opted_in.test.ts | 6 +- .../is_cluster_opted_in.ts | 4 +- 55 files changed, 1089 insertions(+), 348 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 0f7af42fafbfd..8a6ea7957927a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1406,6 +1406,24 @@ module.exports = { }, }, + /** + * Do not allow `any` + */ + { + files: [ + 'packages/kbn-analytics/**', + // 'packages/kbn-telemetry-tools/**', + 'src/plugins/kibana_usage_collection/**', + 'src/plugins/usage_collection/**', + 'src/plugins/telemetry/**', + 'src/plugins/telemetry_collection_manager/**', + 'src/plugins/telemetry_management_section/**', + 'x-pack/plugins/telemetry_collection_xpack/**', + ], + rules: { + '@typescript-eslint/no-explicit-any': 'error', + }, + }, { files: [ // core-team owned code diff --git a/api_docs/telemetry.json b/api_docs/telemetry.json index bff65ce9c68dd..bfb19a79bdb1e 100644 --- a/api_docs/telemetry.json +++ b/api_docs/telemetry.json @@ -1,9 +1,611 @@ { "id": "telemetry", "client": { - "classes": [], + "classes": [ + { + "id": "def-public.TelemetryNotifications", + "type": "Class", + "tags": [], + "label": "TelemetryNotifications", + "description": [], + "children": [ + { + "id": "def-public.TelemetryNotifications.Unnamed", + "type": "Function", + "label": "Constructor", + "signature": [ + "any" + ], + "description": [], + "children": [ + { + "id": "def-public.TelemetryNotifications.Unnamed.$1", + "type": "Object", + "label": "{ http, overlays, telemetryService }", + "isRequired": true, + "signature": [ + "TelemetryNotificationsConstructor" + ], + "description": [], + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_notifications/telemetry_notifications.ts", + "lineNumber": 27 + } + } + ], + "tags": [], + "returnComment": [], + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_notifications/telemetry_notifications.ts", + "lineNumber": 27 + } + }, + { + "id": "def-public.TelemetryNotifications.shouldShowOptedInNoticeBanner", + "type": "Function", + "children": [], + "signature": [ + "() => boolean" + ], + "description": [], + "label": "shouldShowOptedInNoticeBanner", + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_notifications/telemetry_notifications.ts", + "lineNumber": 33 + }, + "tags": [], + "returnComment": [] + }, + { + "id": "def-public.TelemetryNotifications.renderOptedInNoticeBanner", + "type": "Function", + "children": [], + "signature": [ + "() => void" + ], + "description": [], + "label": "renderOptedInNoticeBanner", + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_notifications/telemetry_notifications.ts", + "lineNumber": 39 + }, + "tags": [], + "returnComment": [] + }, + { + "id": "def-public.TelemetryNotifications.shouldShowOptInBanner", + "type": "Function", + "children": [], + "signature": [ + "() => boolean" + ], + "description": [], + "label": "shouldShowOptInBanner", + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_notifications/telemetry_notifications.ts", + "lineNumber": 49 + }, + "tags": [], + "returnComment": [] + }, + { + "id": "def-public.TelemetryNotifications.renderOptInBanner", + "type": "Function", + "children": [], + "signature": [ + "() => void" + ], + "description": [], + "label": "renderOptInBanner", + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_notifications/telemetry_notifications.ts", + "lineNumber": 55 + }, + "tags": [], + "returnComment": [] + }, + { + "id": "def-public.TelemetryNotifications.setOptedInNoticeSeen", + "type": "Function", + "children": [], + "signature": [ + "() => Promise" + ], + "description": [], + "label": "setOptedInNoticeSeen", + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_notifications/telemetry_notifications.ts", + "lineNumber": 73 + }, + "tags": [], + "returnComment": [] + } + ], + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_notifications/telemetry_notifications.ts", + "lineNumber": 20 + }, + "initialIsOpen": false + }, + { + "id": "def-public.TelemetryService", + "type": "Class", + "tags": [], + "label": "TelemetryService", + "description": [], + "children": [ + { + "tags": [], + "id": "def-public.TelemetryService.currentKibanaVersion", + "type": "string", + "label": "currentKibanaVersion", + "description": [], + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 28 + } + }, + { + "id": "def-public.TelemetryService.Unnamed", + "type": "Function", + "label": "Constructor", + "signature": [ + "any" + ], + "description": [], + "children": [ + { + "id": "def-public.TelemetryService.Unnamed.$1", + "type": "Object", + "label": "{\n config,\n http,\n notifications,\n currentKibanaVersion,\n reportOptInStatusChange = true,\n }", + "isRequired": true, + "signature": [ + "TelemetryServiceConstructor" + ], + "description": [], + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 30 + } + } + ], + "tags": [], + "returnComment": [], + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 30 + } + }, + { + "id": "def-public.TelemetryService.config", + "type": "Object", + "label": "config", + "tags": [], + "description": [], + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 44 + }, + "signature": [ + { + "pluginId": "telemetry", + "scope": "public", + "docId": "kibTelemetryPluginApi", + "section": "def-public.TelemetryPluginConfig", + "text": "TelemetryPluginConfig" + } + ] + }, + { + "id": "def-public.TelemetryService.config", + "type": "Object", + "label": "config", + "tags": [], + "description": [], + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 48 + }, + "signature": [ + { + "pluginId": "telemetry", + "scope": "public", + "docId": "kibTelemetryPluginApi", + "section": "def-public.TelemetryPluginConfig", + "text": "TelemetryPluginConfig" + } + ] + }, + { + "id": "def-public.TelemetryService.isOptedIn", + "type": "CompoundType", + "label": "isOptedIn", + "tags": [], + "description": [], + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 52 + }, + "signature": [ + "boolean | null" + ] + }, + { + "id": "def-public.TelemetryService.isOptedIn", + "type": "CompoundType", + "label": "isOptedIn", + "tags": [], + "description": [], + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 56 + }, + "signature": [ + "boolean | null" + ] + }, + { + "id": "def-public.TelemetryService.userHasSeenOptedInNotice", + "type": "CompoundType", + "label": "userHasSeenOptedInNotice", + "tags": [], + "description": [], + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 60 + }, + "signature": [ + "boolean | undefined" + ] + }, + { + "id": "def-public.TelemetryService.userHasSeenOptedInNotice", + "type": "CompoundType", + "label": "userHasSeenOptedInNotice", + "tags": [], + "description": [], + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 64 + }, + "signature": [ + "boolean | undefined" + ] + }, + { + "id": "def-public.TelemetryService.getCanChangeOptInStatus", + "type": "Function", + "children": [], + "signature": [ + "() => boolean" + ], + "description": [], + "label": "getCanChangeOptInStatus", + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 68 + }, + "tags": [], + "returnComment": [] + }, + { + "id": "def-public.TelemetryService.getOptInStatusUrl", + "type": "Function", + "children": [], + "signature": [ + "() => string" + ], + "description": [], + "label": "getOptInStatusUrl", + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 73 + }, + "tags": [], + "returnComment": [] + }, + { + "id": "def-public.TelemetryService.getTelemetryUrl", + "type": "Function", + "children": [], + "signature": [ + "() => string" + ], + "description": [], + "label": "getTelemetryUrl", + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 78 + }, + "tags": [], + "returnComment": [] + }, + { + "id": "def-public.TelemetryService.getUserShouldSeeOptInNotice", + "type": "Function", + "label": "getUserShouldSeeOptInNotice", + "signature": [ + "() => boolean" + ], + "description": [ + "\nReturns if an user should be shown the notice about Opt-In/Out telemetry.\nThe decision is made based on whether any user has already dismissed the message or\nthe user can't actually change the settings (in which case, there's no point on bothering them)" + ], + "children": [], + "tags": [], + "returnComment": [], + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 88 + } + }, + { + "id": "def-public.TelemetryService.userCanChangeSettings", + "type": "boolean", + "label": "userCanChangeSettings", + "tags": [], + "description": [], + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 95 + } + }, + { + "id": "def-public.TelemetryService.userCanChangeSettings", + "type": "boolean", + "label": "userCanChangeSettings", + "tags": [], + "description": [], + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 99 + } + }, + { + "id": "def-public.TelemetryService.getIsOptedIn", + "type": "Function", + "children": [], + "signature": [ + "() => boolean | null" + ], + "description": [], + "label": "getIsOptedIn", + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 103 + }, + "tags": [], + "returnComment": [] + }, + { + "id": "def-public.TelemetryService.fetchExample", + "type": "Function", + "children": [], + "signature": [ + "() => Promise" + ], + "description": [], + "label": "fetchExample", + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 107 + }, + "tags": [], + "returnComment": [] + }, + { + "id": "def-public.TelemetryService.fetchTelemetry", + "type": "Function", + "children": [ + { + "id": "def-public.TelemetryService.fetchTelemetry.$1", + "type": "Object", + "label": "{ unencrypted = false }", + "isRequired": true, + "signature": [ + "{ unencrypted?: boolean | undefined; }" + ], + "description": [], + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 111 + } + } + ], + "signature": [ + "({ unencrypted }?: { unencrypted?: boolean | undefined; }) => Promise" + ], + "description": [], + "label": "fetchTelemetry", + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 111 + }, + "tags": [], + "returnComment": [] + }, + { + "id": "def-public.TelemetryService.setOptIn", + "type": "Function", + "children": [ + { + "id": "def-public.TelemetryService.setOptIn.$1", + "type": "boolean", + "label": "optedIn", + "isRequired": true, + "signature": [ + "boolean" + ], + "description": [], + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 119 + } + } + ], + "signature": [ + "(optedIn: boolean) => Promise" + ], + "description": [], + "label": "setOptIn", + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 119 + }, + "tags": [], + "returnComment": [] + }, + { + "id": "def-public.TelemetryService.setUserHasSeenNotice", + "type": "Function", + "children": [], + "signature": [ + "() => Promise" + ], + "description": [], + "label": "setUserHasSeenNotice", + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 153 + }, + "tags": [], + "returnComment": [] + } + ], + "source": { + "path": "src/plugins/telemetry/public/services/telemetry_service.ts", + "lineNumber": 21 + }, + "initialIsOpen": false + } + ], "functions": [], - "interfaces": [], + "interfaces": [ + { + "id": "def-public.TelemetryPluginConfig", + "type": "Interface", + "label": "TelemetryPluginConfig", + "description": [], + "tags": [], + "children": [ + { + "tags": [], + "id": "def-public.TelemetryPluginConfig.enabled", + "type": "boolean", + "label": "enabled", + "description": [], + "source": { + "path": "src/plugins/telemetry/public/plugin.ts", + "lineNumber": 46 + } + }, + { + "tags": [], + "id": "def-public.TelemetryPluginConfig.url", + "type": "string", + "label": "url", + "description": [], + "source": { + "path": "src/plugins/telemetry/public/plugin.ts", + "lineNumber": 47 + } + }, + { + "tags": [], + "id": "def-public.TelemetryPluginConfig.banner", + "type": "boolean", + "label": "banner", + "description": [], + "source": { + "path": "src/plugins/telemetry/public/plugin.ts", + "lineNumber": 48 + } + }, + { + "tags": [], + "id": "def-public.TelemetryPluginConfig.allowChangingOptInStatus", + "type": "boolean", + "label": "allowChangingOptInStatus", + "description": [], + "source": { + "path": "src/plugins/telemetry/public/plugin.ts", + "lineNumber": 49 + } + }, + { + "tags": [], + "id": "def-public.TelemetryPluginConfig.optIn", + "type": "CompoundType", + "label": "optIn", + "description": [], + "source": { + "path": "src/plugins/telemetry/public/plugin.ts", + "lineNumber": 50 + }, + "signature": [ + "boolean | null" + ] + }, + { + "tags": [], + "id": "def-public.TelemetryPluginConfig.optInStatusUrl", + "type": "string", + "label": "optInStatusUrl", + "description": [], + "source": { + "path": "src/plugins/telemetry/public/plugin.ts", + "lineNumber": 51 + } + }, + { + "tags": [], + "id": "def-public.TelemetryPluginConfig.sendUsageFrom", + "type": "CompoundType", + "label": "sendUsageFrom", + "description": [], + "source": { + "path": "src/plugins/telemetry/public/plugin.ts", + "lineNumber": 52 + }, + "signature": [ + "\"browser\" | \"server\"" + ] + }, + { + "tags": [], + "id": "def-public.TelemetryPluginConfig.telemetryNotifyUserAboutOptInDefault", + "type": "CompoundType", + "label": "telemetryNotifyUserAboutOptInDefault", + "description": [], + "source": { + "path": "src/plugins/telemetry/public/plugin.ts", + "lineNumber": 53 + }, + "signature": [ + "boolean | undefined" + ] + }, + { + "tags": [], + "id": "def-public.TelemetryPluginConfig.userCanChangeSettings", + "type": "CompoundType", + "label": "userCanChangeSettings", + "description": [], + "source": { + "path": "src/plugins/telemetry/public/plugin.ts", + "lineNumber": 54 + }, + "signature": [ + "boolean | undefined" + ] + } + ], + "source": { + "path": "src/plugins/telemetry/public/plugin.ts", + "lineNumber": 45 + }, + "initialIsOpen": false + } + ], "enums": [], "misc": [], "objects": [], @@ -25,7 +627,13 @@ "lineNumber": 38 }, "signature": [ - "TelemetryService" + { + "pluginId": "telemetry", + "scope": "public", + "docId": "kibTelemetryPluginApi", + "section": "def-public.TelemetryService", + "text": "TelemetryService" + } ] }, { @@ -39,7 +647,13 @@ "lineNumber": 39 }, "signature": [ - "TelemetryNotifications" + { + "pluginId": "telemetry", + "scope": "public", + "docId": "kibTelemetryPluginApi", + "section": "def-public.TelemetryNotifications", + "text": "TelemetryNotifications" + } ] }, { @@ -82,7 +696,13 @@ "lineNumber": 34 }, "signature": [ - "TelemetryService" + { + "pluginId": "telemetry", + "scope": "public", + "docId": "kibTelemetryPluginApi", + "section": "def-public.TelemetryService", + "text": "TelemetryService" + } ] } ], @@ -95,137 +715,7 @@ } }, "server": { - "classes": [ - { - "id": "def-server.FetcherTask", - "type": "Class", - "tags": [], - "label": "FetcherTask", - "description": [], - "children": [ - { - "id": "def-server.FetcherTask.Unnamed", - "type": "Function", - "label": "Constructor", - "signature": [ - "any" - ], - "description": [], - "children": [ - { - "id": "def-server.FetcherTask.Unnamed.$1", - "type": "Object", - "label": "initializerContext", - "isRequired": true, - "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.PluginInitializerContext", - "text": "PluginInitializerContext" - }, - ">" - ], - "description": [], - "source": { - "path": "src/plugins/telemetry/server/fetcher.ts", - "lineNumber": 58 - } - } - ], - "tags": [], - "returnComment": [], - "source": { - "path": "src/plugins/telemetry/server/fetcher.ts", - "lineNumber": 58 - } - }, - { - "id": "def-server.FetcherTask.start", - "type": "Function", - "label": "start", - "signature": [ - "({ savedObjects, elasticsearch }: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - }, - ", { telemetryCollectionManager }: ", - "FetcherTaskDepsStart", - ") => void" - ], - "description": [], - "children": [ - { - "id": "def-server.FetcherTask.start.$1", - "type": "Object", - "label": "{ savedObjects, elasticsearch }", - "isRequired": true, - "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.CoreStart", - "text": "CoreStart" - } - ], - "description": [], - "source": { - "path": "src/plugins/telemetry/server/fetcher.ts", - "lineNumber": 65 - } - }, - { - "id": "def-server.FetcherTask.start.$2", - "type": "Object", - "label": "{ telemetryCollectionManager }", - "isRequired": true, - "signature": [ - "FetcherTaskDepsStart" - ], - "description": [], - "source": { - "path": "src/plugins/telemetry/server/fetcher.ts", - "lineNumber": 66 - } - } - ], - "tags": [], - "returnComment": [], - "source": { - "path": "src/plugins/telemetry/server/fetcher.ts", - "lineNumber": 64 - } - }, - { - "id": "def-server.FetcherTask.stop", - "type": "Function", - "label": "stop", - "signature": [ - "() => void" - ], - "description": [], - "children": [], - "tags": [], - "returnComment": [], - "source": { - "path": "src/plugins/telemetry/server/fetcher.ts", - "lineNumber": 77 - } - } - ], - "source": { - "path": "src/plugins/telemetry/server/fetcher.ts", - "lineNumber": 45 - }, - "initialIsOpen": false - } - ], + "classes": [], "functions": [ { "id": "def-server.buildDataTelemetryPayload", @@ -420,15 +910,16 @@ "section": "def-server.StatsCollectionContext", "text": "StatsCollectionContext" }, - ") => Promise<{ timestamp: string; cluster_uuid: string; cluster_name: string; version: string; cluster_stats: any; collection: string; stack_stats: { data: ", + ") => Promise<{ timestamp: string; cluster_uuid: string; cluster_name: string; version: string; cluster_stats: Pick<{ nodes: { usage: { nodes: ", { "pluginId": "telemetry", "scope": "server", "docId": "kibTelemetryPluginApi", - "section": "def-server.DataTelemetryPayload", - "text": "DataTelemetryPayload" + "section": "def-server.NodeUsage", + "text": "NodeUsage" }, - " | undefined; kibana: { count: number; indices: number; os: {}; versions: { version: string; count: number; }[]; plugins: { [plugin: string]: any; }; } | undefined; }; }[]>" + "[] | {}[]; }; count: ", + "ClusterNodeCount" ], "description": [ "\nGet statistics for all products joined by Elasticsearch cluster." @@ -656,6 +1147,123 @@ "lineNumber": 38 }, "initialIsOpen": false + }, + { + "id": "def-server.NodeUsage", + "type": "Interface", + "label": "NodeUsage", + "description": [], + "tags": [], + "children": [ + { + "tags": [], + "id": "def-server.NodeUsage.node_id", + "type": "string", + "label": "node_id", + "description": [], + "source": { + "path": "src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts", + "lineNumber": 18 + }, + "signature": [ + "string | undefined" + ] + }, + { + "tags": [], + "id": "def-server.NodeUsage.timestamp", + "type": "CompoundType", + "label": "timestamp", + "description": [], + "source": { + "path": "src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts", + "lineNumber": 19 + }, + "signature": [ + "React.ReactText" + ] + }, + { + "tags": [], + "id": "def-server.NodeUsage.since", + "type": "number", + "label": "since", + "description": [], + "source": { + "path": "src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts", + "lineNumber": 20 + } + }, + { + "tags": [], + "id": "def-server.NodeUsage.rest_actions", + "type": "Object", + "label": "rest_actions", + "description": [], + "source": { + "path": "src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts", + "lineNumber": 21 + }, + "signature": [ + "{ [key: string]: number; }" + ] + }, + { + "tags": [], + "id": "def-server.NodeUsage.aggregations", + "type": "Object", + "label": "aggregations", + "description": [], + "source": { + "path": "src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts", + "lineNumber": 24 + }, + "signature": [ + "{ [key: string]: ", + { + "pluginId": "telemetry", + "scope": "server", + "docId": "kibTelemetryPluginApi", + "section": "def-server.NodeUsageAggregation", + "text": "NodeUsageAggregation" + }, + "; } | undefined" + ] + } + ], + "source": { + "path": "src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts", + "lineNumber": 17 + }, + "initialIsOpen": false + }, + { + "id": "def-server.NodeUsageAggregation", + "type": "Interface", + "label": "NodeUsageAggregation", + "description": [], + "tags": [], + "children": [ + { + "id": "def-server.NodeUsageAggregation.Unnamed", + "type": "Any", + "label": "Unnamed", + "tags": [], + "description": [], + "source": { + "path": "src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts", + "lineNumber": 13 + }, + "signature": [ + "any" + ] + } + ], + "source": { + "path": "src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts", + "lineNumber": 12 + }, + "initialIsOpen": false } ], "enums": [], @@ -701,7 +1309,7 @@ "lineNumber": 51 }, "signature": [ - "{ timestamp: string; cluster_uuid: string; cluster_name: string; version: string; cluster_stats: any; collection: string; stack_stats: { data: DataTelemetryPayload | undefined; kibana: { count: number; indices: number; os: {}; versions: { version: string; count: number; }[]; plugins: { [plugin: string]: any; }; } | undefined; }; }" + "{ timestamp: string; cluster_uuid: string; cluster_name: string; version: string; cluster_stats: Pick; collection: string; stack_stats: { data: DataTelemetryPayload | undefined; kibana: { count: number; indices: number; os: {}; versions: { version: string; count: number; }[]; plugins: { [plugin: string]: Record; }; } | undefined; }; }" ], "initialIsOpen": false } diff --git a/api_docs/telemetry.mdx b/api_docs/telemetry.mdx index bf91eb198f08e..f9a58d29ebd86 100644 --- a/api_docs/telemetry.mdx +++ b/api_docs/telemetry.mdx @@ -19,6 +19,12 @@ import telemetryObj from './telemetry.json'; ### Start +### Classes + + +### Interfaces + + ## Server ### Setup @@ -30,9 +36,6 @@ import telemetryObj from './telemetry.json'; ### Functions -### Classes - - ### Interfaces diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md index 193a2e5a24f3f..5fffc5436e9c6 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md @@ -7,7 +7,7 @@ Signature: ```typescript -SearchBar: React.ComponentClass, "query" | "placeholder" | "isLoading" | "iconType" | "indexPatterns" | "filters" | "dataTestSubj" | "isClearable" | "refreshInterval" | "nonKqlMode" | "nonKqlModeHelpText" | "screenTitle" | "onRefresh" | "onRefreshChange" | "showQueryInput" | "showDatePicker" | "showAutoRefreshOnly" | "dateRangeFrom" | "dateRangeTo" | "isRefreshPaused" | "customSubmitButton" | "timeHistory" | "indicateNoData" | "onFiltersUpdated" | "savedQuery" | "showSaveQuery" | "onClearSavedQuery" | "showQueryBar" | "showFilterBar" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated">, any> & { - WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; +SearchBar: React.ComponentClass, "query" | "placeholder" | "isLoading" | "iconType" | "indexPatterns" | "filters" | "dataTestSubj" | "refreshInterval" | "isClearable" | "nonKqlMode" | "nonKqlModeHelpText" | "screenTitle" | "onRefresh" | "onRefreshChange" | "showQueryInput" | "showDatePicker" | "showAutoRefreshOnly" | "dateRangeFrom" | "dateRangeTo" | "isRefreshPaused" | "customSubmitButton" | "timeHistory" | "indicateNoData" | "onFiltersUpdated" | "savedQuery" | "showSaveQuery" | "onClearSavedQuery" | "showQueryBar" | "showFilterBar" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated">, any> & { + WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; } ``` diff --git a/packages/kbn-analytics/src/reporter.ts b/packages/kbn-analytics/src/reporter.ts index 44e6758eb4643..c7c9cf1541d21 100644 --- a/packages/kbn-analytics/src/reporter.ts +++ b/packages/kbn-analytics/src/reporter.ts @@ -68,7 +68,7 @@ export class Reporter { } }; - private log(message: any) { + private log(message: unknown) { if (this.debug) { // eslint-disable-next-line console.debug(message); diff --git a/packages/kbn-analytics/src/storage.ts b/packages/kbn-analytics/src/storage.ts index b080a53029724..ac1084e807fc7 100644 --- a/packages/kbn-analytics/src/storage.ts +++ b/packages/kbn-analytics/src/storage.ts @@ -8,10 +8,10 @@ import { Report } from './report'; -export interface Storage { - get: (key: string) => T | null; +export interface Storage { + get: (key: string) => T | undefined; set: (key: string, value: T) => S; - remove: (key: string) => T | null; + remove: (key: string) => T | undefined; clear: () => void; } diff --git a/packages/kbn-analytics/src/util.ts b/packages/kbn-analytics/src/util.ts index 96e18c43e104f..b3768b4df94b8 100644 --- a/packages/kbn-analytics/src/util.ts +++ b/packages/kbn-analytics/src/util.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -export function wrapArray(subj: T | T[]): T[] { +export function wrapArray(subj: T | T[]): T[] { return Array.isArray(subj) ? subj : [subj]; } diff --git a/src/plugins/advanced_settings/public/management_app/types.ts b/src/plugins/advanced_settings/public/management_app/types.ts index 50b39114d2143..854a70ae48a97 100644 --- a/src/plugins/advanced_settings/public/management_app/types.ts +++ b/src/plugins/advanced_settings/public/management_app/types.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import type { ReactElement } from 'react'; import { UiCounterMetricType } from '@kbn/analytics'; import { UiSettingsType, StringValidation, ImageValidation } from '../../../../core/public'; @@ -13,7 +14,7 @@ export interface FieldSetting { displayName: string; name: string; value: unknown; - description?: string; + description?: string | ReactElement; options?: string[]; optionLabels?: Record; requiresPageReload: boolean; diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index 15d3f5c403b1f..a69df282cd568 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -32,7 +32,6 @@ import { ExpressionsServerSetup } from 'src/plugins/expressions/server'; import { ExpressionValueBoxed } from 'src/plugins/expressions/common'; import { FormatFactory as FormatFactory_2 } from 'src/plugins/data/common/field_formats/utils'; import { IAggConfigs as IAggConfigs_2 } from 'src/plugins/data/public'; -import { ISavedObjectsRepository } from 'src/core/server'; import { IScopedClusterClient } from 'src/core/server'; import { ISearchOptions as ISearchOptions_2 } from 'src/plugins/data/public'; import { ISearchSource } from 'src/plugins/data/public'; diff --git a/src/plugins/kibana_usage_collection/server/collectors/application_usage/telemetry_application_usage_collector.test.ts b/src/plugins/kibana_usage_collection/server/collectors/application_usage/telemetry_application_usage_collector.test.ts index da4e1b101914f..38864945a17d0 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/application_usage/telemetry_application_usage_collector.test.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/application_usage/telemetry_application_usage_collector.test.ts @@ -116,10 +116,15 @@ describe('telemetry_application_usage', () => { minutesOnScreen: 10, numberOfClicks: 10, }, + type: opts.type, + references: [], + score: 0, }, ], total: 1, - } as any; + per_page: 10, + page: 1, + }; case SAVED_OBJECTS_DAILY_TYPE: return { saved_objects: [ @@ -131,9 +136,21 @@ describe('telemetry_application_usage', () => { minutesOnScreen: 0.5, numberOfClicks: 1, }, + type: opts.type, + references: [], + score: 0, }, ], total: 1, + per_page: 10, + page: 1, + }; + default: + return { + saved_objects: [], + total: 0, + per_page: 10, + page: 1, }; } }); diff --git a/src/plugins/kibana_usage_collection/server/collectors/config_usage/register_config_usage_collector.test.ts b/src/plugins/kibana_usage_collection/server/collectors/config_usage/register_config_usage_collector.test.ts index 7d4f03fd30edf..bc6f8c956b669 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/config_usage/register_config_usage_collector.test.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/config_usage/register_config_usage_collector.test.ts @@ -28,7 +28,7 @@ describe('kibana_config_usage', () => { const collectorFetchContext = createCollectorFetchContextMock(); const coreUsageDataStart = coreUsageDataServiceMock.createStartContract(); - const mockConfigUsage = (Symbol('config usage telemetry') as any) as ConfigUsageData; + const mockConfigUsage = (Symbol('config usage telemetry') as unknown) as ConfigUsageData; coreUsageDataStart.getConfigsUsageData.mockResolvedValue(mockConfigUsage); beforeAll(() => registerConfigUsageCollector(usageCollectionMock, () => coreUsageDataStart)); diff --git a/src/plugins/kibana_usage_collection/server/collectors/core/core_usage_collector.test.ts b/src/plugins/kibana_usage_collection/server/collectors/core/core_usage_collector.test.ts index b671a9f93d369..5410e491a85fd 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/core/core_usage_collector.test.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/core/core_usage_collector.test.ts @@ -28,7 +28,7 @@ describe('telemetry_core', () => { const collectorFetchContext = createCollectorFetchContextMock(); const coreUsageDataStart = coreUsageDataServiceMock.createStartContract(); - const getCoreUsageDataReturnValue = (Symbol('core telemetry') as any) as CoreUsageData; + const getCoreUsageDataReturnValue = (Symbol('core telemetry') as unknown) as CoreUsageData; coreUsageDataStart.getCoreUsageData.mockResolvedValue(getCoreUsageDataReturnValue); beforeAll(() => registerCoreUsageCollector(usageCollectionMock, () => coreUsageDataStart)); diff --git a/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.test.ts b/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.test.ts index 15cbecde386f7..3d5d7854d6f9e 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.test.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.test.ts @@ -9,13 +9,11 @@ import { elasticsearchServiceMock } from '../../../../../../src/core/server/mocks'; import { getSavedObjectsCounts } from './get_saved_object_counts'; -export function mockGetSavedObjectsCounts(params: any) { +export function mockGetSavedObjectsCounts(params: TBody) { const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; esClient.search.mockResolvedValue( // @ts-expect-error we only care about the response body - { - body: { ...params }, - } + { body: { ...params } } ); return esClient; } diff --git a/src/plugins/kibana_usage_collection/server/collectors/kibana/index.test.ts b/src/plugins/kibana_usage_collection/server/collectors/kibana/index.test.ts index e1afbfbcecc4e..2c75d3edc3a84 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/kibana/index.test.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/kibana/index.test.ts @@ -34,7 +34,8 @@ describe('telemetry_kibana', () => { const getMockFetchClients = (hits?: unknown[]) => { const fetchParamsMock = createCollectorFetchContextMock(); const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; - esClient.search.mockResolvedValue({ body: { hits: { hits } } } as any); + // @ts-expect-error for the sake of the tests, we only require `hits` + esClient.search.mockResolvedValue({ body: { hits: { hits } } }); fetchParamsMock.esClient = esClient; return fetchParamsMock; }; diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/telemetry_management_collector.test.ts b/src/plugins/kibana_usage_collection/server/collectors/management/telemetry_management_collector.test.ts index cb0b1c045397d..8295342c527ab 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/telemetry_management_collector.test.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/telemetry_management_collector.test.ts @@ -17,6 +17,7 @@ import { registerManagementUsageCollector, createCollectorFetch, } from './telemetry_management_collector'; +import { IUiSettingsClient } from 'kibana/server'; const logger = loggingSystemMock.createLogger(); @@ -30,7 +31,7 @@ describe('telemetry_application_usage_collector', () => { }); const uiSettingsClient = uiSettingsServiceMock.createClient(); - const getUiSettingsClient = jest.fn(() => uiSettingsClient); + const getUiSettingsClient = jest.fn((): IUiSettingsClient | undefined => uiSettingsClient); const mockedFetchContext = createCollectorFetchContextMock(); beforeAll(() => { @@ -42,7 +43,7 @@ describe('telemetry_application_usage_collector', () => { }); test('isReady() => false if no client', () => { - getUiSettingsClient.mockImplementationOnce(() => undefined as any); + getUiSettingsClient.mockImplementationOnce(() => undefined); expect(collector.isReady()).toBe(false); }); @@ -60,7 +61,7 @@ describe('telemetry_application_usage_collector', () => { }); test('fetch() should not fail if invoked when not ready', async () => { - getUiSettingsClient.mockImplementationOnce(() => undefined as any); + getUiSettingsClient.mockImplementationOnce(() => undefined); await expect(collector.fetch(mockedFetchContext)).resolves.toBe(undefined); }); }); 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 cba5140997f3f..7dd1a4dc4410e 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 @@ -22,12 +22,13 @@ export function createCollectorFetch(getUiSettingsClient: () => IUiSettingsClien const userProvided = await uiSettingsClient.getUserProvided(); const modifiedEntries = Object.entries(userProvided) .filter(([key]) => key !== 'buildNum') - .reduce((obj: any, [key, { userValue }]) => { + .reduce((obj: Record, [key, { userValue }]) => { const sensitive = uiSettingsClient.isSensitive(key); obj[key] = sensitive ? REDACTED_KEYWORD : userValue; return obj; }, {}); - return modifiedEntries; + // TODO: It would be Partial, but the telemetry-tools for the schema extraction still does not support it. We need to fix it before setting the right Partial type + return (modifiedEntries as unknown) as UsageStats; }; } diff --git a/src/plugins/kibana_usage_collection/server/collectors/ui_metric/index.test.ts b/src/plugins/kibana_usage_collection/server/collectors/ui_metric/index.test.ts index 51ecbf736bfc1..31cb869d14e57 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/ui_metric/index.test.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/ui_metric/index.test.ts @@ -30,6 +30,8 @@ describe('telemetry_ui_metric', () => { const registerType = jest.fn(); const mockedFetchContext = createCollectorFetchContextMock(); + const commonSavedObjectsAttributes = { score: 0, references: [], type: 'ui-metric' }; + beforeAll(() => registerUiMetricUsageCollector(usageCollectionMock, registerType, getUsageCollector) ); @@ -44,13 +46,12 @@ describe('telemetry_ui_metric', () => { test('when savedObjectClient is initialised, return something', async () => { const savedObjectClient = savedObjectsRepositoryMock.create(); - savedObjectClient.find.mockImplementation( - async () => - ({ - saved_objects: [], - total: 0, - } as any) - ); + savedObjectClient.find.mockImplementation(async () => ({ + saved_objects: [], + total: 0, + per_page: 10, + page: 1, + })); getUsageCollector.mockImplementation(() => savedObjectClient); expect(await collector.fetch(mockedFetchContext)).toStrictEqual({}); @@ -59,20 +60,33 @@ describe('telemetry_ui_metric', () => { test('results grouped by appName', async () => { const savedObjectClient = savedObjectsRepositoryMock.create(); - savedObjectClient.find.mockImplementation(async () => { - return { - saved_objects: [ - { id: 'testAppName:testKeyName1', attributes: { count: 3 } }, - { id: 'testAppName:testKeyName2', attributes: { count: 5 } }, - { id: 'testAppName2:testKeyName3', attributes: { count: 1 } }, - { - id: - 'kibana-user_agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:80.0) Gecko/20100101 Firefox/80.0', - attributes: { count: 1 }, - }, - ], - total: 3, - } as any; + savedObjectClient.find.mockResolvedValue({ + saved_objects: [ + { + ...commonSavedObjectsAttributes, + id: 'testAppName:testKeyName1', + attributes: { count: 3 }, + }, + { + ...commonSavedObjectsAttributes, + id: 'testAppName:testKeyName2', + attributes: { count: 5 }, + }, + { + ...commonSavedObjectsAttributes, + id: 'testAppName2:testKeyName3', + attributes: { count: 1 }, + }, + { + ...commonSavedObjectsAttributes, + id: + 'kibana-user_agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:80.0) Gecko/20100101 Firefox/80.0', + attributes: { count: 1 }, + }, + ], + total: 3, + per_page: 3, + page: 1, }); getUsageCollector.mockImplementation(() => savedObjectClient); diff --git a/src/plugins/telemetry/common/telemetry_config/get_telemetry_failure_details.test.ts b/src/plugins/telemetry/common/telemetry_config/get_telemetry_failure_details.test.ts index 617b5189de4a8..c93ba53230954 100644 --- a/src/plugins/telemetry/common/telemetry_config/get_telemetry_failure_details.test.ts +++ b/src/plugins/telemetry/common/telemetry_config/get_telemetry_failure_details.test.ts @@ -35,9 +35,10 @@ describe('getTelemetryFailureDetails: get details about server usage fetcher fai expect( getTelemetryFailureDetails({ telemetrySavedObject: { + // @ts-expect-error the test is intentionally testing malformed SOs reportFailureCount: null, reportFailureVersion: failureVersion, - } as any, + }, }) ).toStrictEqual({ failureVersion, failureCount: 0 }); expect( @@ -51,9 +52,10 @@ describe('getTelemetryFailureDetails: get details about server usage fetcher fai expect( getTelemetryFailureDetails({ telemetrySavedObject: { + // @ts-expect-error the test is intentionally testing malformed SOs reportFailureCount: 'not_a_number', reportFailureVersion: failureVersion, - } as any, + }, }) ).toStrictEqual({ failureVersion, failureCount: 0 }); }); @@ -63,9 +65,10 @@ describe('getTelemetryFailureDetails: get details about server usage fetcher fai expect( getTelemetryFailureDetails({ telemetrySavedObject: { + // @ts-expect-error the test is intentionally testing malformed SOs reportFailureVersion: null, reportFailureCount: failureCount, - } as any, + }, }) ).toStrictEqual({ failureCount, failureVersion: undefined }); expect( @@ -76,9 +79,10 @@ describe('getTelemetryFailureDetails: get details about server usage fetcher fai expect( getTelemetryFailureDetails({ telemetrySavedObject: { + // @ts-expect-error the test is intentionally testing malformed SOs reportFailureVersion: 123, reportFailureCount: failureCount, - } as any, + }, }) ).toStrictEqual({ failureCount, failureVersion: undefined }); }); diff --git a/src/plugins/telemetry/common/telemetry_config/get_telemetry_opt_in.test.ts b/src/plugins/telemetry/common/telemetry_config/get_telemetry_opt_in.test.ts index 65e4a2d43eef7..ede56688e0449 100644 --- a/src/plugins/telemetry/common/telemetry_config/get_telemetry_opt_in.test.ts +++ b/src/plugins/telemetry/common/telemetry_config/get_telemetry_opt_in.test.ts @@ -55,6 +55,7 @@ describe('getTelemetryOptIn', () => { // build a table of tests with version checks, with results for enabled false type VersionCheckTable = Array>; + // @ts-expect-error the test is intentionally testing malformed objects const EnabledFalseVersionChecks: VersionCheckTable = [ { lastVersionChecked: '8.0.0', currentKibanaVersion: '8.0.0', result: false }, { lastVersionChecked: '8.0.0', currentKibanaVersion: '8.0.1', result: false }, @@ -112,7 +113,7 @@ describe('getTelemetryOptIn', () => { interface CallGetTelemetryOptInParams { savedObjectNotFound: boolean; savedObjectForbidden: boolean; - lastVersionChecked?: any; // should be a string, but test with non-strings + lastVersionChecked?: string; // should be a string, but test with non-strings currentKibanaVersion: string; result?: boolean | null; enabled: boolean | null | undefined; diff --git a/src/plugins/telemetry/public/components/opted_in_notice_banner.tsx b/src/plugins/telemetry/public/components/opted_in_notice_banner.tsx index b91f6ee9e4b51..a10c26c22e3fa 100644 --- a/src/plugins/telemetry/public/components/opted_in_notice_banner.tsx +++ b/src/plugins/telemetry/public/components/opted_in_notice_banner.tsx @@ -17,7 +17,7 @@ import { HttpSetup } from '../../../../core/public'; interface Props { http: HttpSetup; - onSeenBanner: () => any; + onSeenBanner: () => unknown; } export class OptedInNoticeBanner extends React.PureComponent { diff --git a/src/plugins/telemetry/public/index.ts b/src/plugins/telemetry/public/index.ts index 47ba7828eaec2..aef955e228dd3 100644 --- a/src/plugins/telemetry/public/index.ts +++ b/src/plugins/telemetry/public/index.ts @@ -8,7 +8,8 @@ import { PluginInitializerContext } from 'kibana/public'; import { TelemetryPlugin, TelemetryPluginConfig } from './plugin'; -export type { TelemetryPluginStart, TelemetryPluginSetup } from './plugin'; +export type { TelemetryPluginStart, TelemetryPluginSetup, TelemetryPluginConfig } from './plugin'; +export type { TelemetryNotifications, TelemetryService } from './services'; export function plugin(initializerContext: PluginInitializerContext) { return new TelemetryPlugin(initializerContext); diff --git a/src/plugins/telemetry/public/services/telemetry_notifications/render_opt_in_banner.tsx b/src/plugins/telemetry/public/services/telemetry_notifications/render_opt_in_banner.tsx index 4180f577e3037..f880aef3e3235 100644 --- a/src/plugins/telemetry/public/services/telemetry_notifications/render_opt_in_banner.tsx +++ b/src/plugins/telemetry/public/services/telemetry_notifications/render_opt_in_banner.tsx @@ -13,7 +13,7 @@ import { toMountPoint } from '../../../../kibana_react/public'; interface RenderBannerConfig { overlays: CoreStart['overlays']; - setOptIn: (isOptIn: boolean) => Promise; + setOptIn: (isOptIn: boolean) => Promise; } export function renderOptInBanner({ setOptIn, overlays }: RenderBannerConfig) { diff --git a/src/plugins/telemetry/public/services/telemetry_sender.ts b/src/plugins/telemetry/public/services/telemetry_sender.ts index 05588f4c9e704..937416d283872 100644 --- a/src/plugins/telemetry/public/services/telemetry_sender.ts +++ b/src/plugins/telemetry/public/services/telemetry_sender.ts @@ -58,8 +58,8 @@ export class TelemetrySender { this.isSending = true; try { const telemetryUrl = this.telemetryService.getTelemetryUrl(); - const telemetryData: any | any[] = await this.telemetryService.fetchTelemetry(); - const clusters: string[] = [].concat(telemetryData); + const telemetryData: string | string[] = await this.telemetryService.fetchTelemetry(); + const clusters: string[] = ([] as string[]).concat(telemetryData); await Promise.all( clusters.map( async (cluster) => diff --git a/src/plugins/telemetry/server/collectors/usage/ensure_deep_object.ts b/src/plugins/telemetry/server/collectors/usage/ensure_deep_object.ts index 6b79cc6c7410a..c5624d1f62bf7 100644 --- a/src/plugins/telemetry/server/collectors/usage/ensure_deep_object.ts +++ b/src/plugins/telemetry/server/collectors/usage/ensure_deep_object.ts @@ -8,12 +8,15 @@ // // THIS IS A DIRECT COPY OF -// '../../../../../../../../src/core/server/config/ensure_deep_object' +// 'packages/kbn-config/src/raw/ensure_deep_object.ts' // BECAUSE THAT IS BLOCKED FOR IMPORTING BY OUR LINTER. // // IF THAT IS EXPOSED, WE SHOULD USE IT RATHER THAN CLONE IT. // +/* eslint-disable @typescript-eslint/no-explicit-any */ +// ^ Disabling the rule for the entire file because of the complexity to type this + const separator = '.'; /** diff --git a/src/plugins/telemetry/server/collectors/usage/telemetry_usage_collector.test.ts b/src/plugins/telemetry/server/collectors/usage/telemetry_usage_collector.test.ts index ac439f0753a2b..2acc6676d13db 100644 --- a/src/plugins/telemetry/server/collectors/usage/telemetry_usage_collector.test.ts +++ b/src/plugins/telemetry/server/collectors/usage/telemetry_usage_collector.test.ts @@ -15,10 +15,11 @@ import { readTelemetryFile, MAX_FILE_SIZE, } from './telemetry_usage_collector'; +import { usageCollectionPluginMock } from '../../../../usage_collection/server/mocks'; -const mockUsageCollector = () => ({ - makeUsageCollector: jest.fn().mockImplementationOnce((arg: object) => arg), -}); +const mockUsageCollector = () => { + return usageCollectionPluginMock.createSetupContract(); +}; describe('telemetry_usage_collector', () => { const tempDir = tmpdir(); @@ -105,14 +106,15 @@ describe('telemetry_usage_collector', () => { // dir // the `makeUsageCollector` is mocked above to return the argument passed to it - const usageCollector = mockUsageCollector() as any; + const usageCollector = mockUsageCollector(); const collectorOptions = createTelemetryUsageCollector( usageCollector, async () => tempFiles.unreadable ); expect(collectorOptions.type).toBe('static_telemetry'); - expect(await collectorOptions.fetch({} as any)).toEqual(expectedObject); // Sending any as the callCluster client because it's not needed in this collector but TS requires it when calling it. + // @ts-expect-error this collector does not require any arguments in the fetch method, but TS complains + expect(await collectorOptions.fetch()).toEqual(expectedObject); }); }); }); diff --git a/src/plugins/telemetry/server/fetcher.ts b/src/plugins/telemetry/server/fetcher.ts index 5db1b62cb3e26..fb188a2414b98 100644 --- a/src/plugins/telemetry/server/fetcher.ts +++ b/src/plugins/telemetry/server/fetcher.ts @@ -9,10 +9,7 @@ import { Observable, Subscription, timer } from 'rxjs'; import { take } from 'rxjs/operators'; import fetch from 'node-fetch'; -import { - TelemetryCollectionManagerPluginStart, - UsageStatsPayload, -} from 'src/plugins/telemetry_collection_manager/server'; +import type { TelemetryCollectionManagerPluginStart } from 'src/plugins/telemetry_collection_manager/server'; import { PluginInitializerContext, Logger, @@ -40,6 +37,7 @@ interface TelemetryConfig { telemetryUrl: string; failureCount: number; failureVersion: string | undefined; + currentVersion: string; } export class FetcherTask { @@ -104,7 +102,7 @@ export class FetcherTask { return; } - let clusters: Array = []; + let clusters: string[] = []; this.isSending = true; try { @@ -160,6 +158,7 @@ export class FetcherTask { telemetryUrl, failureCount, failureVersion, + currentVersion: currentKibanaVersion, }; } @@ -187,11 +186,11 @@ export class FetcherTask { private shouldSendReport({ telemetryOptIn, telemetrySendUsageFrom, - reportFailureCount, + failureCount, + failureVersion, currentVersion, - reportFailureVersion, - }: any) { - if (reportFailureCount > 2 && reportFailureVersion === currentVersion) { + }: TelemetryConfig) { + if (failureCount > 2 && failureVersion === currentVersion) { return false; } @@ -209,7 +208,7 @@ export class FetcherTask { }); } - private async sendTelemetry(url: string, cluster: any): Promise { + private async sendTelemetry(url: string, cluster: string): Promise { this.logger.debug(`Sending usage stats.`); /** * send OPTIONS before sending usage data. diff --git a/src/plugins/telemetry/server/index.ts b/src/plugins/telemetry/server/index.ts index 1c335426ffd03..005f50721e778 100644 --- a/src/plugins/telemetry/server/index.ts +++ b/src/plugins/telemetry/server/index.ts @@ -11,7 +11,6 @@ import { TelemetryPlugin } from './plugin'; import * as constants from '../common/constants'; import { configSchema, TelemetryConfigType } from './config'; -export { FetcherTask } from './fetcher'; export { handleOldSettings } from './handle_old_settings'; export type { TelemetryPluginSetup, TelemetryPluginStart } from './plugin'; @@ -42,4 +41,6 @@ export type { TelemetryLocalStats, DataTelemetryIndex, DataTelemetryPayload, + NodeUsage, + NodeUsageAggregation, } from './telemetry_collection'; diff --git a/src/plugins/telemetry/server/telemetry_collection/get_cluster_info.test.ts b/src/plugins/telemetry/server/telemetry_collection/get_cluster_info.test.ts index 9e70e31925226..cd414beb42182 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_cluster_info.test.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_cluster_info.test.ts @@ -9,14 +9,10 @@ import { elasticsearchServiceMock } from '../../../../../src/core/server/mocks'; import { getClusterInfo } from './get_cluster_info'; -export function mockGetClusterInfo(clusterInfo: any) { +export function mockGetClusterInfo(clusterInfo: ClusterInfo) { const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; - esClient.info.mockResolvedValue( - // @ts-expect-error we only care about the response body - { - body: { ...clusterInfo }, - } - ); + // @ts-expect-error we only care about the response body + esClient.info.mockResolvedValue({ body: { ...clusterInfo } }); return esClient; } diff --git a/src/plugins/telemetry/server/telemetry_collection/get_cluster_stats.test.ts b/src/plugins/telemetry/server/telemetry_collection/get_cluster_stats.test.ts index a2c22fbbb0a78..06d3ebeb7ea0e 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_cluster_stats.test.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_cluster_stats.test.ts @@ -10,15 +10,9 @@ import { elasticsearchServiceMock } from '../../../../../src/core/server/mocks'; import { getClusterStats } from './get_cluster_stats'; import { TIMEOUT } from './constants'; -export function mockGetClusterStats(clusterStats: any) { - const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; - esClient.cluster.stats.mockResolvedValue(clusterStats); - return esClient; -} - describe('get_cluster_stats', () => { it('uses the esClient to get the response from the `cluster.stats` API', async () => { - const response = Promise.resolve({ body: { cluster_uuid: '1234' } }); + const response = { body: { cluster_uuid: '1234' } }; const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; esClient.cluster.stats.mockImplementationOnce( // @ts-expect-error the method only cares about the response body @@ -26,8 +20,8 @@ describe('get_cluster_stats', () => { return response; } ); - const result = getClusterStats(esClient); + const result = await getClusterStats(esClient); expect(esClient.cluster.stats).toHaveBeenCalledWith({ timeout: TIMEOUT }); - expect(result).toStrictEqual(response); + expect(result).toStrictEqual(response.body); }); }); diff --git a/src/plugins/telemetry/server/telemetry_collection/get_data_telemetry/get_data_telemetry.test.ts b/src/plugins/telemetry/server/telemetry_collection/get_data_telemetry/get_data_telemetry.test.ts index d2113dce9548f..dab1eaeed27ce 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_data_telemetry/get_data_telemetry.test.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_data_telemetry/get_data_telemetry.test.ts @@ -271,7 +271,7 @@ describe('get_data_telemetry', () => { function mockEsClient( indicesMappings: string[] = [], // an array of `indices` to get mappings from. { isECS = false, dataStreamDataset = '', dataStreamType = '', shipper = '' } = {}, - indexStats: any = {} + indexStats = {} ) { const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; // @ts-expect-error diff --git a/src/plugins/telemetry/server/telemetry_collection/get_kibana.ts b/src/plugins/telemetry/server/telemetry_collection/get_kibana.ts index 566c942890150..3f1966901544a 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_kibana.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_kibana.ts @@ -8,7 +8,7 @@ import { omit } from 'lodash'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; -import { ISavedObjectsRepository, KibanaRequest, SavedObjectsClientContract } from 'kibana/server'; +import { KibanaRequest, SavedObjectsClientContract } from 'kibana/server'; import { StatsCollectionContext } from 'src/plugins/telemetry_collection_manager/server'; import { ElasticsearchClient } from 'src/core/server'; @@ -27,7 +27,7 @@ export interface KibanaUsageStats { }; }; - [plugin: string]: any; + [plugin: string]: Record; } export function handleKibanaStats( @@ -73,7 +73,7 @@ export function handleKibanaStats( export async function getKibana( usageCollection: UsageCollectionSetup, asInternalUser: ElasticsearchClient, - soClient: SavedObjectsClientContract | ISavedObjectsRepository, + soClient: SavedObjectsClientContract, kibanaRequest: KibanaRequest | undefined // intentionally `| undefined` to enforce providing the parameter ): Promise { const usage = await usageCollection.bulkFetch(asInternalUser, soClient, kibanaRequest); diff --git a/src/plugins/telemetry/server/telemetry_collection/get_local_stats.test.ts b/src/plugins/telemetry/server/telemetry_collection/get_local_stats.test.ts index edf8dbb30809b..7fd6ca4080d6a 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_local_stats.test.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_local_stats.test.ts @@ -20,17 +20,18 @@ import { StatsCollectionConfig } from '../../../telemetry_collection_manager/ser function mockUsageCollection(kibanaUsage = {}) { const usageCollection = usageCollectionPluginMock.createSetupContract(); usageCollection.bulkFetch = jest.fn().mockResolvedValue(kibanaUsage); - usageCollection.toObject = jest.fn().mockImplementation((data: any) => data); + usageCollection.toObject = jest.fn().mockImplementation((data) => data); return usageCollection; } // set up successful call mocks for info, cluster stats, nodes usage and data telemetry -function mockGetLocalStats(clusterInfo: any, clusterStats: any) { +function mockGetLocalStats( + clusterInfo: ClusterInfo, + clusterStats: ClusterStats +) { const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; esClient.info.mockResolvedValue( // @ts-expect-error we only care about the response body - { - body: { ...clusterInfo }, - } + { body: { ...clusterInfo } } ); esClient.cluster.stats // @ts-expect-error we only care about the response body @@ -70,8 +71,8 @@ function mockGetLocalStats(clusterInfo: any, clusterStats: any) { } function mockStatsCollectionConfig( - clusterInfo: any, - clusterStats: any, + clusterInfo: unknown, + clusterStats: unknown, kibana: {} ): StatsCollectionConfig { return { @@ -113,13 +114,13 @@ describe('get_local_stats', () => { }, }, ]; - const clusterStats = { + const clusterStats = ({ _nodes: { failed: 123 }, cluster_name: 'real-cool', indices: { totally: 456 }, nodes: { yup: 'abc' }, random: 123, - }; + } as unknown) as estypes.ClusterStatsResponse; const kibana = { kibana: { diff --git a/src/plugins/telemetry/server/telemetry_collection/get_local_stats.ts b/src/plugins/telemetry/server/telemetry_collection/get_local_stats.ts index 67f9ebb8ff3e4..72f6ba855096c 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_local_stats.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_local_stats.ts @@ -26,10 +26,10 @@ import { getDataTelemetry, DATA_TELEMETRY_ID, DataTelemetryPayload } from './get * @param {Object} clusterStats Cluster stats (GET /_cluster/stats) * @param {Object} kibana The Kibana Usage stats */ -export function handleLocalStats( +export function handleLocalStats( // eslint-disable-next-line @typescript-eslint/naming-convention { cluster_name, cluster_uuid, version }: estypes.RootNodeInfoResponse, - { _nodes, cluster_name: clusterName, ...clusterStats }: any, + { _nodes, cluster_name: clusterName, ...clusterStats }: ClusterStats, kibana: KibanaUsageStats | undefined, dataTelemetry: DataTelemetryPayload | undefined, context: StatsCollectionContext diff --git a/src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts b/src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts index e46d4be540734..544142c8d742f 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts @@ -9,12 +9,12 @@ import { ElasticsearchClient } from 'src/core/server'; import { TIMEOUT } from './constants'; -export interface NodeAggregation { +export interface NodeUsageAggregation { [key: string]: number; } // we set aggregations as an optional type because it was only added in v7.8.0 -export interface NodeObj { +export interface NodeUsage { node_id?: string; timestamp: number | string; since: number; @@ -22,20 +22,20 @@ export interface NodeObj { [key: string]: number; }; aggregations?: { - [key: string]: NodeAggregation; + [key: string]: NodeUsageAggregation; }; } export interface NodesFeatureUsageResponse { cluster_name: string; nodes: { - [key: string]: NodeObj; + [key: string]: NodeUsage; }; } export type NodesUsageGetter = ( esClient: ElasticsearchClient -) => Promise<{ nodes: NodeObj[] | Array<{}> }>; +) => Promise<{ nodes: NodeUsage[] | Array<{}> }>; /** * Get the nodes usage data from the connected cluster. * @@ -61,7 +61,7 @@ export async function fetchNodesUsage( export const getNodesUsage: NodesUsageGetter = async (esClient) => { const result = await fetchNodesUsage(esClient); const transformedNodes = Object.entries(result?.nodes || {}).map(([key, value]) => ({ - ...(value as NodeObj), + ...(value as NodeUsage), node_id: key, })); return { nodes: transformedNodes }; diff --git a/src/plugins/telemetry/server/telemetry_collection/index.ts b/src/plugins/telemetry/server/telemetry_collection/index.ts index 151e89a11a192..f55147a0a083f 100644 --- a/src/plugins/telemetry/server/telemetry_collection/index.ts +++ b/src/plugins/telemetry/server/telemetry_collection/index.ts @@ -10,5 +10,6 @@ export { DATA_TELEMETRY_ID, buildDataTelemetryPayload } from './get_data_telemet export type { DataTelemetryIndex, DataTelemetryPayload } from './get_data_telemetry'; export { getLocalStats } from './get_local_stats'; export type { TelemetryLocalStats } from './get_local_stats'; +export type { NodeUsage, NodeUsageAggregation } from './get_nodes_usage'; export { getClusterUuids } from './get_cluster_stats'; export { registerCollection } from './register_collection'; diff --git a/src/plugins/telemetry/server/telemetry_repository/get_telemetry_saved_object.test.ts b/src/plugins/telemetry/server/telemetry_repository/get_telemetry_saved_object.test.ts index fbead0125fe09..5ea8211739a13 100644 --- a/src/plugins/telemetry/server/telemetry_repository/get_telemetry_saved_object.test.ts +++ b/src/plugins/telemetry/server/telemetry_repository/get_telemetry_saved_object.test.ts @@ -8,6 +8,7 @@ import { getTelemetrySavedObject } from './get_telemetry_saved_object'; import { SavedObjectsErrorHelpers } from '../../../../core/server'; +import { savedObjectsClientMock } from '../../../../core/server/mocks'; describe('getTelemetrySavedObject', () => { it('returns null when saved object not found', async () => { @@ -51,7 +52,7 @@ interface CallGetTelemetrySavedObjectParams { savedObjectNotFound: boolean; savedObjectForbidden: boolean; savedObjectOtherError: boolean; - result?: any; + result?: unknown; } const DefaultParams = { @@ -68,26 +69,22 @@ function getCallGetTelemetrySavedObjectParams( async function callGetTelemetrySavedObject(params: CallGetTelemetrySavedObjectParams) { const savedObjectsClient = getMockSavedObjectsClient(params); - return await getTelemetrySavedObject(savedObjectsClient as any); + return await getTelemetrySavedObject(savedObjectsClient); } const SavedObjectForbiddenMessage = 'savedObjectForbidden'; const SavedObjectOtherErrorMessage = 'savedObjectOtherError'; function getMockSavedObjectsClient(params: CallGetTelemetrySavedObjectParams) { - return { - async get(type: string, id: string) { - if (params.savedObjectNotFound) throw SavedObjectsErrorHelpers.createGenericNotFoundError(); - if (params.savedObjectForbidden) - throw SavedObjectsErrorHelpers.decorateForbiddenError( - new Error(SavedObjectForbiddenMessage) - ); - if (params.savedObjectOtherError) - throw SavedObjectsErrorHelpers.decorateGeneralError( - new Error(SavedObjectOtherErrorMessage) - ); - - return { attributes: { enabled: null } }; - }, - }; + const savedObjectsClient = savedObjectsClientMock.create(); + savedObjectsClient.get.mockImplementation(async (type, id) => { + if (params.savedObjectNotFound) throw SavedObjectsErrorHelpers.createGenericNotFoundError(); + if (params.savedObjectForbidden) + throw SavedObjectsErrorHelpers.decorateForbiddenError(new Error(SavedObjectForbiddenMessage)); + if (params.savedObjectOtherError) + throw SavedObjectsErrorHelpers.decorateGeneralError(new Error(SavedObjectOtherErrorMessage)); + + return { id, type, attributes: { enabled: null }, references: [] }; + }); + return savedObjectsClient; } diff --git a/src/plugins/telemetry_collection_manager/server/encryption/encrypt.ts b/src/plugins/telemetry_collection_manager/server/encryption/encrypt.ts index a2c24627f6fd7..1b80a2c29b362 100644 --- a/src/plugins/telemetry_collection_manager/server/encryption/encrypt.ts +++ b/src/plugins/telemetry_collection_manager/server/encryption/encrypt.ts @@ -13,12 +13,12 @@ export function getKID(useProdKey = false): string { return useProdKey ? 'kibana1' : 'kibana_dev1'; } -export async function encryptTelemetry( - payload: any, +export async function encryptTelemetry( + payload: Payload | Payload[], { useProdKey = false } = {} ): Promise { const kid = getKID(useProdKey); const encryptor = await createRequestEncryptor(telemetryJWKS); - const clusters = [].concat(payload); - return Promise.all(clusters.map((cluster: any) => encryptor.encrypt(kid, cluster))); + const clusters = ([] as Payload[]).concat(payload); + return Promise.all(clusters.map((cluster) => encryptor.encrypt(kid, cluster))); } diff --git a/src/plugins/telemetry_collection_manager/server/plugin.ts b/src/plugins/telemetry_collection_manager/server/plugin.ts index 692d91b963d9d..0efdde5eeafd6 100644 --- a/src/plugins/telemetry_collection_manager/server/plugin.ts +++ b/src/plugins/telemetry_collection_manager/server/plugin.ts @@ -7,7 +7,7 @@ */ import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; -import { +import type { PluginInitializerContext, CoreSetup, CoreStart, @@ -19,7 +19,7 @@ import { SavedObjectsClientContract, } from 'src/core/server'; -import { +import type { TelemetryCollectionManagerPluginSetup, TelemetryCollectionManagerPluginStart, BasicStatsPayload, @@ -29,6 +29,8 @@ import { StatsCollectionConfig, UsageStatsPayload, StatsCollectionContext, + UnencryptedStatsGetterConfig, + EncryptedStatsGetterConfig, } from './types'; import { encryptTelemetry } from './encryption'; import { TelemetrySavedObjectsClient } from './telemetry_saved_objects_client'; @@ -40,7 +42,7 @@ interface TelemetryCollectionPluginsDepsSetup { export class TelemetryCollectionManagerPlugin implements Plugin { private readonly logger: Logger; - private collectionStrategy: CollectionStrategy | undefined; + private collectionStrategy: CollectionStrategy | undefined; private usageGetterMethodPriority = -1; private usageCollection?: UsageCollectionSetup; private elasticsearchClient?: IClusterClient; @@ -215,6 +217,8 @@ export class TelemetryCollectionManagerPlugin })); }; + private async getStats(config: UnencryptedStatsGetterConfig): Promise; + private async getStats(config: EncryptedStatsGetterConfig): Promise; private async getStats(config: StatsGetterConfig) { if (!this.usageCollection) { return []; diff --git a/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap b/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap index 896b1671328a9..e0ba7e7527af7 100644 --- a/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap +++ b/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap @@ -95,13 +95,14 @@ exports[`TelemetryManagementSectionComponent renders as expected 1`] = ` size="s" />

@@ -156,12 +157,26 @@ exports[`TelemetryManagementSectionComponent renders as expected 1`] = `

, "displayName": "Provide usage statistics", + "isCustom": true, + "isOverridden": false, "name": "telemetry:enabled", + "requiresPageReload": false, "type": "boolean", "value": true, } } - toasts={null} + toasts={ + Object { + "add": [MockFunction], + "addDanger": [MockFunction], + "addError": [MockFunction], + "addInfo": [MockFunction], + "addSuccess": [MockFunction], + "addWarning": [MockFunction], + "get$": [MockFunction], + "remove": [MockFunction], + } + } /> @@ -170,6 +185,7 @@ exports[`TelemetryManagementSectionComponent renders as expected 1`] = ` exports[`TelemetryManagementSectionComponent renders null because allowChangingOptInStatus is false 1`] = ` Promise; + fetchExample: () => Promise; onClose: () => void; } interface State { isLoading: boolean; hasPrivilegeToRead: boolean; - data: any[] | null; + data: unknown[] | null; } /** diff --git a/src/plugins/telemetry_management_section/public/components/telemetry_management_section.test.tsx b/src/plugins/telemetry_management_section/public/components/telemetry_management_section.test.tsx index 7e7e255edea8c..019dedd793fa2 100644 --- a/src/plugins/telemetry_management_section/public/components/telemetry_management_section.test.tsx +++ b/src/plugins/telemetry_management_section/public/components/telemetry_management_section.test.tsx @@ -12,9 +12,11 @@ import TelemetryManagementSection from './telemetry_management_section'; import { TelemetryService } from '../../../telemetry/public/services'; import { coreMock } from '../../../../core/public/mocks'; import { render } from '@testing-library/react'; +import type { DocLinksStart } from 'src/core/public'; describe('TelemetryManagementSectionComponent', () => { const coreStart = coreMock.createStart(); + const docLinks = {} as DocLinksStart['links']; const coreSetup = coreMock.createSetup(); it('renders as expected', () => { @@ -45,6 +47,7 @@ describe('TelemetryManagementSectionComponent', () => { enableSaving={true} isSecurityExampleEnabled={isSecurityExampleEnabled} toasts={coreStart.notifications.toasts} + docLinks={docLinks} /> ) ).toMatchSnapshot(); @@ -78,6 +81,7 @@ describe('TelemetryManagementSectionComponent', () => { enableSaving={true} isSecurityExampleEnabled={isSecurityExampleEnabled} toasts={coreStart.notifications.toasts} + docLinks={docLinks} /> ); @@ -93,6 +97,7 @@ describe('TelemetryManagementSectionComponent', () => { enableSaving={true} toasts={coreStart.notifications.toasts} isSecurityExampleEnabled={isSecurityExampleEnabled} + docLinks={docLinks} /> ); @@ -130,6 +135,7 @@ describe('TelemetryManagementSectionComponent', () => { isSecurityExampleEnabled={isSecurityExampleEnabled} enableSaving={true} toasts={coreStart.notifications.toasts} + docLinks={docLinks} /> ); try { @@ -177,6 +183,7 @@ describe('TelemetryManagementSectionComponent', () => { enableSaving={true} isSecurityExampleEnabled={isSecurityExampleEnabled} toasts={coreStart.notifications.toasts} + docLinks={docLinks} /> ); try { @@ -215,6 +222,7 @@ describe('TelemetryManagementSectionComponent', () => { enableSaving={true} isSecurityExampleEnabled={isSecurityExampleEnabled} toasts={coreStart.notifications.toasts} + docLinks={docLinks} /> ); try { @@ -254,6 +262,7 @@ describe('TelemetryManagementSectionComponent', () => { isSecurityExampleEnabled={isSecurityExampleEnabled} enableSaving={true} toasts={coreStart.notifications.toasts} + docLinks={docLinks} /> ); try { @@ -293,6 +302,7 @@ describe('TelemetryManagementSectionComponent', () => { isSecurityExampleEnabled={isSecurityExampleEnabled} enableSaving={true} toasts={coreStart.notifications.toasts} + docLinks={docLinks} /> ); @@ -332,6 +342,7 @@ describe('TelemetryManagementSectionComponent', () => { enableSaving={true} isSecurityExampleEnabled={isSecurityExampleEnabled} toasts={coreStart.notifications.toasts} + docLinks={docLinks} /> ); try { @@ -339,11 +350,12 @@ describe('TelemetryManagementSectionComponent', () => { await expect( toggleOptInComponent.prop('handleChange')() ).resolves.toBe(true); - expect((component.state() as any).enabled).toBe(true); + // TODO: Fix `mountWithIntl` types in @kbn/test/jest to make testing easier + expect((component.state() as { enabled: boolean }).enabled).toBe(true); await expect( toggleOptInComponent.prop('handleChange')() ).resolves.toBe(true); - expect((component.state() as any).enabled).toBe(false); + expect((component.state() as { enabled: boolean }).enabled).toBe(false); telemetryService.setOptIn = jest.fn().mockRejectedValue(Error('test-error')); await expect( toggleOptInComponent.prop('handleChange')() @@ -381,6 +393,7 @@ describe('TelemetryManagementSectionComponent', () => { enableSaving={true} toasts={coreStart.notifications.toasts} isSecurityExampleEnabled={isSecurityExampleEnabled} + docLinks={docLinks} /> ).html() ).toMatchSnapshot(); diff --git a/src/plugins/telemetry_management_section/public/components/telemetry_management_section.tsx b/src/plugins/telemetry_management_section/public/components/telemetry_management_section.tsx index 5a9f3922c6caf..e9ddc4cf82dfc 100644 --- a/src/plugins/telemetry_management_section/public/components/telemetry_management_section.tsx +++ b/src/plugins/telemetry_management_section/public/components/telemetry_management_section.tsx @@ -20,12 +20,12 @@ import { import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { TelemetryPluginSetup } from 'src/plugins/telemetry/public'; +import type { TelemetryPluginSetup } from 'src/plugins/telemetry/public'; +import type { DocLinksStart, ToastsStart } from 'src/core/public'; import { PRIVACY_STATEMENT_URL } from '../../../telemetry/common/constants'; import { OptInExampleFlyout } from './opt_in_example_flyout'; import { OptInSecurityExampleFlyout } from './opt_in_security_example_flyout'; import { LazyField } from '../../../advanced_settings/public'; -import { ToastsStart } from '../../../../core/public'; import { TrackApplicationView } from '../../../usage_collection/public'; type TelemetryService = TelemetryPluginSetup['telemetryService']; @@ -40,6 +40,7 @@ interface Props { enableSaving: boolean; query?: { text: string }; toasts: ToastsStart; + docLinks: DocLinksStart['links']; } interface State { @@ -130,24 +131,26 @@ export class TelemetryManagementSection extends Component { {this.maybeGetAppliesSettingMessage()} diff --git a/src/plugins/telemetry_management_section/public/components/telemetry_management_section_wrapper.tsx b/src/plugins/telemetry_management_section/public/components/telemetry_management_section_wrapper.tsx index cc38b1ec74b37..91881dffa52d7 100644 --- a/src/plugins/telemetry_management_section/public/components/telemetry_management_section_wrapper.tsx +++ b/src/plugins/telemetry_management_section/public/components/telemetry_management_section_wrapper.tsx @@ -8,10 +8,12 @@ import React, { lazy, Suspense } from 'react'; import { EuiLoadingSpinner } from '@elastic/eui'; -import { TelemetryPluginSetup } from 'src/plugins/telemetry/public'; -// It should be this but the types are way too vague in the AdvancedSettings plugin `Record` -// type Props = Omit; -type Props = any; +import type { TelemetryPluginSetup } from 'src/plugins/telemetry/public'; +import type TelemetryManagementSection from './telemetry_management_section'; +export type TelemetryManagementSectionWrapperProps = Omit< + TelemetryManagementSection['props'], + 'telemetryService' | 'showAppliesSettingMessage' | 'isSecurityExampleEnabled' +>; const TelemetryManagementSectionComponent = lazy(() => import('./telemetry_management_section')); @@ -19,7 +21,7 @@ export function telemetryManagementSectionWrapper( telemetryService: TelemetryPluginSetup['telemetryService'], shouldShowSecuritySolutionUsageExample: () => boolean ) { - const TelemetryManagementSectionWrapper = (props: Props) => ( + const TelemetryManagementSectionWrapper = (props: TelemetryManagementSectionWrapperProps) => ( }> ); }, diff --git a/src/plugins/usage_collection/server/collector/collector.ts b/src/plugins/usage_collection/server/collector/collector.ts index 90e873388d22e..22c91ac0c038d 100644 --- a/src/plugins/usage_collection/server/collector/collector.ts +++ b/src/plugins/usage_collection/server/collector/collector.ts @@ -141,11 +141,11 @@ export type CollectorOptions< }); export class Collector { - public readonly extendFetchContext: CollectorOptionsFetchExtendedContext; - public readonly type: CollectorOptions['type']; - public readonly init?: CollectorOptions['init']; - public readonly fetch: CollectorFetchMethod; - public readonly isReady: CollectorOptions['isReady']; + public readonly extendFetchContext: CollectorOptionsFetchExtendedContext; + public readonly type: CollectorOptions['type']; + public readonly init?: CollectorOptions['init']; + public readonly fetch: CollectorFetchMethod; + public readonly isReady: CollectorOptions['isReady']; /** * @private Constructor of a Collector. It should be called via the CollectorSet factory methods: `makeStatsCollector` and `makeUsageCollector` * @param log {@link Logger} @@ -160,7 +160,9 @@ export class Collector { isReady, extendFetchContext = {}, ...options - }: CollectorOptions + }: // Any does not affect here, but needs to be set so it doesn't affect anything else down the line + // eslint-disable-next-line @typescript-eslint/no-explicit-any + CollectorOptions ) { if (type === undefined) { throw new Error('Collector must be instantiated with a options.type string property'); diff --git a/src/plugins/usage_collection/server/collector/collector_set.test.ts b/src/plugins/usage_collection/server/collector/collector_set.test.ts index 0ef9a27cf094c..5a617e2316dda 100644 --- a/src/plugins/usage_collection/server/collector/collector_set.test.ts +++ b/src/plugins/usage_collection/server/collector/collector_set.test.ts @@ -13,7 +13,7 @@ import { UsageCollector } from './usage_collector'; import { elasticsearchServiceMock, loggingSystemMock, - savedObjectsRepositoryMock, + savedObjectsClientMock, } from '../../../../core/server/mocks'; const logger = loggingSystemMock.createLogger(); @@ -34,7 +34,7 @@ describe('CollectorSet', () => { loggerSpies.warn.mockRestore(); }); const mockEsClient = elasticsearchServiceMock.createClusterClient().asInternalUser; - const mockSoClient = savedObjectsRepositoryMock.create(); + const mockSoClient = savedObjectsClientMock.create(); const req = void 0; // No need to instantiate any KibanaRequest in these tests it('should throw an error if non-Collector type of object is registered', () => { @@ -43,8 +43,9 @@ describe('CollectorSet', () => { collectors.registerCollector({ type: 'type_collector_test', init, + // @ts-expect-error we are intentionally sending it wrong. fetch, - } as any); // We are intentionally sending it wrong. + }); }; expect(registerPojo).toThrowError( @@ -71,13 +72,14 @@ describe('CollectorSet', () => { }); it('should log debug status of fetching from the collector', async () => { - mockEsClient.get.mockResolvedValue({ passTest: 1000 } as any); + // @ts-expect-error we are just mocking the output of any call + mockEsClient.ping.mockResolvedValue({ passTest: 1000 }); const collectors = new CollectorSet({ logger }); collectors.registerCollector( new Collector(logger, { type: 'MY_TEST_COLLECTOR', - fetch: (collectorFetchContext: any) => { - return collectorFetchContext.esClient.get(); + fetch: (collectorFetchContext) => { + return collectorFetchContext.esClient.ping(); }, isReady: () => true, }) @@ -122,7 +124,8 @@ describe('CollectorSet', () => { new Collector(logger, { type: 'MY_TEST_COLLECTOR', fetch: () => ({ test: 1 }), - isReady: true as any, + // @ts-expect-error we are intentionally sending it wrong + isReady: true, }) ); @@ -138,10 +141,11 @@ describe('CollectorSet', () => { it('should not break if isReady is not provided', async () => { const collectors = new CollectorSet({ logger }); collectors.registerCollector( + // @ts-expect-error we are intentionally sending it wrong. new Collector(logger, { type: 'MY_TEST_COLLECTOR', fetch: () => ({ test: 1 }), - } as any) + }) ); const result = await collectors.bulkFetch(mockEsClient, mockSoClient, req); diff --git a/src/plugins/usage_collection/server/collector/collector_set.ts b/src/plugins/usage_collection/server/collector/collector_set.ts index 4de5691eaaa70..d42eb6644bbbe 100644 --- a/src/plugins/usage_collection/server/collector/collector_set.ts +++ b/src/plugins/usage_collection/server/collector/collector_set.ts @@ -7,16 +7,17 @@ */ import { snakeCase } from 'lodash'; -import { +import type { Logger, ElasticsearchClient, - ISavedObjectsRepository, SavedObjectsClientContract, KibanaRequest, } from 'src/core/server'; import { Collector, CollectorOptions } from './collector'; import { UsageCollector, UsageCollectorOptions } from './usage_collector'; +// Needed for the general array containing all the collectors. We don't really care about their types here +// eslint-disable-next-line @typescript-eslint/no-explicit-any type AnyCollector = Collector; interface CollectorSetConfig { @@ -144,7 +145,7 @@ export class CollectorSet { public bulkFetch = async ( esClient: ElasticsearchClient, - soClient: SavedObjectsClientContract | ISavedObjectsRepository, + soClient: SavedObjectsClientContract, kibanaRequest: KibanaRequest | undefined, // intentionally `| undefined` to enforce providing the parameter collectors: Map = this.collectors ) => { @@ -183,7 +184,7 @@ export class CollectorSet { public bulkFetchUsage = async ( esClient: ElasticsearchClient, - savedObjectsClient: SavedObjectsClientContract | ISavedObjectsRepository, + savedObjectsClient: SavedObjectsClientContract, kibanaRequest: KibanaRequest | undefined // intentionally `| undefined` to enforce providing the parameter ) => { const usageCollectors = this.getFilteredCollectorSet((c) => c instanceof UsageCollector); diff --git a/src/plugins/usage_collection/server/collector/usage_collector.ts b/src/plugins/usage_collection/server/collector/usage_collector.ts index 1509b10654f49..3af3a7bb65f84 100644 --- a/src/plugins/usage_collection/server/collector/usage_collector.ts +++ b/src/plugins/usage_collection/server/collector/usage_collector.ts @@ -23,6 +23,8 @@ export class UsageCollector exte > { constructor( log: Logger, + // Needed because it doesn't affect on anything here but being explicit creates a lot of pain down the line + // eslint-disable-next-line @typescript-eslint/no-explicit-any collectorOptions: UsageCollectorOptions ) { super(log, collectorOptions); diff --git a/src/plugins/usage_collection/server/report/store_report.test.ts b/src/plugins/usage_collection/server/report/store_report.test.ts index 08fdec4ae804f..789e01020bb2e 100644 --- a/src/plugins/usage_collection/server/report/store_report.test.ts +++ b/src/plugins/usage_collection/server/report/store_report.test.ts @@ -118,7 +118,7 @@ describe('store_report', () => { expect(storeApplicationUsageMock).toHaveBeenCalledTimes(1); expect(storeApplicationUsageMock).toHaveBeenCalledWith( repository, - Object.values(report.application_usage as Record), + Object.values(report.application_usage!), expect.any(Date) ); }); diff --git a/src/plugins/usage_collection/server/routes/stats/stats.ts b/src/plugins/usage_collection/server/routes/stats/stats.ts index 416a69dd9a8f9..6cae56afa281b 100644 --- a/src/plugins/usage_collection/server/routes/stats/stats.ts +++ b/src/plugins/usage_collection/server/routes/stats/stats.ts @@ -15,7 +15,6 @@ import { first } from 'rxjs/operators'; import { ElasticsearchClient, IRouter, - ISavedObjectsRepository, KibanaRequest, MetricsServiceSetup, SavedObjectsClientContract, @@ -30,6 +29,12 @@ const STATS_NOT_READY_MESSAGE = i18n.translate('usageCollection.stats.notReadyMe const SNAPSHOT_REGEX = /-snapshot/i; +interface UsageObject { + kibana?: UsageObject; + xpack?: UsageObject; + [key: string]: unknown | UsageObject; +} + export function registerStatsRoute({ router, config, @@ -55,9 +60,9 @@ export function registerStatsRoute({ }) { const getUsage = async ( esClient: ElasticsearchClient, - savedObjectsClient: SavedObjectsClientContract | ISavedObjectsRepository, + savedObjectsClient: SavedObjectsClientContract, kibanaRequest: KibanaRequest - ): Promise => { + ): Promise => { const usage = await collectorSet.bulkFetchUsage(esClient, savedObjectsClient, kibanaRequest); return collectorSet.toObject(usage); }; @@ -104,7 +109,7 @@ export function registerStatsRoute({ const usagePromise = shouldGetUsage ? getUsage(asCurrentUser, savedObjectsClient, req) - : Promise.resolve({}); + : Promise.resolve({}); const [usage, clusterUuid] = await Promise.all([ usagePromise, getClusterUuid(asCurrentUser), @@ -138,7 +143,7 @@ export function registerStatsRoute({ } return accum; - }, {} as any); + }, {} as UsageObject); extended = { usage: modifiedUsage, diff --git a/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_license.test.ts b/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_license.test.ts index 694b155632d04..bee6db57bee42 100644 --- a/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_license.test.ts +++ b/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_license.test.ts @@ -24,7 +24,8 @@ describe('getLicenseFromLocalOrMaster', () => { test('returns the license it fetches from Elasticsearch', async () => { const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; // The local fetch succeeds - esClient.license.get.mockResolvedValue({ body: { license: { type: 'basic' } } } as any); + // @ts-expect-error it's enough to test with minimal payload + esClient.license.get.mockResolvedValue({ body: { license: { type: 'basic' } } }); const license = await getLicenseFromLocalOrMaster(esClient); @@ -51,7 +52,8 @@ describe('getLicenseFromLocalOrMaster', () => { // The local fetch fails esClient.license.get.mockRejectedValueOnce(new Error('Something went terribly wrong')); // The master fetch succeeds - esClient.license.get.mockResolvedValue({ body: { license: { type: 'basic' } } } as any); + // @ts-expect-error it's enough to test with minimal payload + esClient.license.get.mockResolvedValue({ body: { license: { type: 'basic' } } }); const license = await getLicenseFromLocalOrMaster(esClient); diff --git a/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_stats_with_xpack.test.ts b/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_stats_with_xpack.test.ts index 6ddb10e825684..86d1554a4fd57 100644 --- a/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_stats_with_xpack.test.ts +++ b/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_stats_with_xpack.test.ts @@ -8,6 +8,8 @@ import type { estypes } from '@elastic/elasticsearch'; import { coreMock, elasticsearchServiceMock } from '../../../../../src/core/server/mocks'; import { getStatsWithXpack } from './get_stats_with_xpack'; +import { SavedObjectsClient } from '../../../../../src/core/server'; +import { usageCollectionPluginMock } from '../../../../../src/plugins/usage_collection/server/mocks'; const kibana = { kibana: { @@ -50,10 +52,16 @@ const getContext = () => ({ logger: coreMock.createPluginInitializerContext().logger.get('test'), }); -const mockUsageCollection = (kibanaUsage: Record = kibana) => ({ - bulkFetch: () => kibanaUsage, - toObject: (data: any) => data, -}); +const mockUsageCollection = (kibanaUsage: Record = kibana) => { + const usageCollectionMock = usageCollectionPluginMock.createSetupContract(); + usageCollectionMock.bulkFetch.mockImplementation(async () => + Object.entries(kibanaUsage).map(([type, result]) => ({ type, result })) + ); + usageCollectionMock.toObject.mockImplementation((data) => + Object.fromEntries((data || []).map(({ type, result }) => [type, result])) + ); + return usageCollectionMock; +}; /** * Instantiate the esClient mock with the common requests @@ -91,6 +99,9 @@ function mockEsClient() { } describe('Telemetry Collection: Get Aggregated Stats', () => { + const soClient = new SavedObjectsClient( + coreMock.createStart().savedObjects.createInternalRepository() + ); test('OSS-like telemetry (no license nor X-Pack telemetry)', async () => { const esClient = mockEsClient(); // mock for xpack.usage should throw a 404 for this test @@ -106,7 +117,9 @@ describe('Telemetry Collection: Get Aggregated Stats', () => { { esClient, usageCollection, - } as any, + soClient, + kibanaRequest: undefined, + }, context ); stats.forEach((entry) => { @@ -126,7 +139,9 @@ describe('Telemetry Collection: Get Aggregated Stats', () => { { esClient, usageCollection, - } as any, + soClient, + kibanaRequest: undefined, + }, context ); stats.forEach((entry) => { @@ -151,7 +166,9 @@ describe('Telemetry Collection: Get Aggregated Stats', () => { { esClient, usageCollection, - } as any, + soClient, + kibanaRequest: undefined, + }, context ); stats.forEach((entry, index) => { diff --git a/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_stats_with_xpack.ts b/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_stats_with_xpack.ts index 30bcd19007c0d..3adc5bc9f2eac 100644 --- a/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_stats_with_xpack.ts +++ b/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_stats_with_xpack.ts @@ -45,7 +45,9 @@ export const getStatsWithXpack: StatsGetter = async fu }) .reduce((acc, stats) => { // Concatenate the telemetry reported via monitoring as additional payloads instead of reporting it inside of stack_stats.kibana.plugins.monitoringTelemetry - const monitoringTelemetry = stats.stack_stats.kibana?.plugins?.monitoringTelemetry?.stats; + const monitoringTelemetry = stats.stack_stats.kibana?.plugins?.monitoringTelemetry?.stats as + | TelemetryAggregatedStats[] + | undefined; if (monitoringTelemetry) { delete stats.stack_stats.kibana!.plugins.monitoringTelemetry; } diff --git a/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/is_cluster_opted_in.test.ts b/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/is_cluster_opted_in.test.ts index 5fa7584879f07..481bf70a5f5a7 100644 --- a/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/is_cluster_opted_in.test.ts +++ b/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/is_cluster_opted_in.test.ts @@ -6,13 +6,14 @@ */ import { isClusterOptedIn } from './is_cluster_opted_in'; +import type { TelemetryAggregatedStats } from './get_stats_with_xpack'; -const createMockClusterUsage = (plugins: any) => { +const createMockClusterUsage = (plugins: unknown) => { return { stack_stats: { kibana: { plugins }, }, - }; + } as TelemetryAggregatedStats; }; describe('isClusterOptedIn', () => { @@ -33,6 +34,7 @@ describe('isClusterOptedIn', () => { }); it('returns true if kibana.plugins.telemetry does not exist', () => { expect(isClusterOptedIn(createMockClusterUsage({}))).toBe(true); + // @ts-expect-error we want to test the logic anyway because this object may come from very dynamic requests that any-fy the code expect(isClusterOptedIn({})).toBe(true); expect(isClusterOptedIn(undefined)).toBe(true); }); diff --git a/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/is_cluster_opted_in.ts b/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/is_cluster_opted_in.ts index 4bc35a238152b..49876f3d5a981 100644 --- a/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/is_cluster_opted_in.ts +++ b/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/is_cluster_opted_in.ts @@ -5,7 +5,9 @@ * 2.0. */ -export const isClusterOptedIn = (clusterUsage: any): boolean => { +import type { TelemetryAggregatedStats } from './get_stats_with_xpack'; + +export const isClusterOptedIn = (clusterUsage?: TelemetryAggregatedStats): boolean => { return ( clusterUsage?.stack_stats?.kibana?.plugins?.telemetry?.opt_in_status === true || // If stack_stats.kibana.plugins.telemetry does not exist, assume opted-in for BWC