Revert "Remove security example from telemetry management panel. (#105722)" (#105974)

This reverts commit 6ae078f3c6.
This commit is contained in:
Pete Hampton 2021-07-16 18:23:25 +01:00 committed by GitHub
parent 8f4111e204
commit ca0b362754
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 628 additions and 23 deletions

View file

@ -216,7 +216,7 @@ generating deep links to other apps, and creating short URLs.
|{kib-repo}blob/{branch}/src/plugins/telemetry_management_section/README.md[telemetryManagementSection]
|This plugin adds the Advanced Settings section for the Usage Data collection (aka Telemetry).
|This plugin adds the Advanced Settings section for the Usage and Security Data collection (aka Telemetry).
|{kib-repo}blob/{branch}/src/plugins/tile_map/README.md[tileMap]

View file

@ -1,5 +1,5 @@
# Telemetry Management Section
This plugin adds the Advanced Settings section for the Usage Data collection (aka Telemetry).
This plugin adds the Advanced Settings section for the Usage and Security Data collection (aka Telemetry).
The reason for having it separated from the `telemetry` plugin is to avoid circular dependencies. The plugin `advancedSettings` depends on the `home` app that depends on the `telemetry` plugin because of the telemetry banner in the welcome screen.

View file

@ -0,0 +1,110 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`example security payload renders as expected 1`] = `
<EuiCodeBlock
language="js"
>
{
"@timestamp": "2020-09-22T14:34:56.82202300Z",
"agent": {
"build": {
"original": "version: 7.9.1, compiled: Thu Aug 27 14:50:21 2020, branch: 7.9, commit: b594beb958817dee9b9d908191ed766d483df3ea"
},
"id": "22dd8544-bcac-46cb-b970-5e681bb99e0b",
"type": "endpoint",
"version": "7.9.1"
},
"Endpoint": {
"policy": {
"applied": {
"artifacts": {
"global": {
"identifiers": [
{
"sha256": "6a546aade5563d3e8dffc1fe2d93d33edda8f9ca3e17ac3cc9ac707620cb9ecd",
"name": "endpointpe-v4-blocklist"
},
{
"sha256": "04f9f87accc5d5aea433427bd1bd4ec6908f8528c78ceed26f70df7875a99385",
"name": "endpointpe-v4-exceptionlist"
},
{
"sha256": "1471838597fcd79a54ea4a3ec9a9beee1a86feaedab6c98e61102559ced822a8",
"name": "endpointpe-v4-model"
},
{
"sha256": "824859b0c6749cc31951d92a73bbdddfcfe9f38abfe432087934d4dab9766ce8",
"name": "global-exceptionlist-windows"
}
],
"version": "1.0.0"
},
"user": {
"identifiers": [
{
"sha256": "d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658",
"name": "endpoint-exceptionlist-windows-v1"
}
],
"version": "1.0.0"
}
}
}
}
},
"ecs": {
"version": "1.5.0"
},
"elastic": {
"agent": {
"id": "b2e88aea-2671-402a-828a-957526bac315"
}
},
"file": {
"path": "C:\\\\Windows\\\\Temp\\\\mimikatz.exe",
"size": 1263880,
"created": "2020-05-19T07:50:06.0Z",
"accessed": "2020-09-22T14:29:19.93531400Z",
"mtime": "2020-09-22T14:29:03.6040000Z",
"directory": "C:\\\\Windows\\\\Temp",
"hash": {
"sha1": "c9fb7f8a4c6b7b12b493a99a8dc6901d17867388",
"sha256": "cb1553a3c88817e4cc774a5a93f9158f6785bd3815447d04b6c3f4c2c4b21ed7",
"md5": "465d5d850f54d9cde767bda90743df30"
},
"Ext": {
"code_signature": {
"trusted": true,
"subject_name": "Open Source Developer, Benjamin Delpy",
"exists": true,
"status": "trusted"
},
"malware_classification": {
"identifier": "endpointpe-v4-model",
"score": 0.99956864118576,
"threshold": 0.71,
"version": "0.0.0"
}
}
},
"host": {
"os": {
"Ext": {
"variant": "Windows 10 Enterprise Evaluation"
},
"kernel": "2004 (10.0.19041.388)",
"name": "Windows",
"family": "windows",
"version": "2004 (10.0.19041.388)",
"platform": "windows",
"full": "Windows 10 Enterprise Evaluation 2004 (10.0.19041.388)"
}
},
"event": {
"kind": "alert"
},
"cluster_uuid": "kLbKvSMcRiiFAR0t8LebDA",
"cluster_name": "elasticsearch"
}
</EuiCodeBlock>
`;

View file

@ -0,0 +1,45 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`security flyout renders as expected renders as expected 1`] = `
<EuiPortal>
<EuiFlyout
maxWidth={true}
onClose={[MockFunction]}
ownFocus={true}
>
<EuiFlyoutHeader>
<EuiTitle>
<h2>
Endpoint security data
</h2>
</EuiTitle>
<EuiTextColor
color="subdued"
>
<EuiText>
This is a representative sample of the endpoint security alert event that we collect. Endpoint security data is collected only when the Elastic Endpoint is enabled. It includes information about the endpoint configuration and detection events.
</EuiText>
</EuiTextColor>
</EuiFlyoutHeader>
<EuiFlyoutBody>
<Suspense
fallback={
<EuiFlexGroup
justifyContent="spaceAround"
>
<EuiFlexItem
grow={false}
>
<EuiLoadingSpinner
size="xl"
/>
</EuiFlexItem>
</EuiFlexGroup>
}
>
<lazy />
</Suspense>
</EuiFlyoutBody>
</EuiFlyout>
</EuiPortal>
`;

View file

@ -1,5 +1,50 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TelemetryManagementSectionComponent does not show the endpoint link when isSecurityExampleEnabled returns false 1`] = `
<React.Fragment>
<p>
<FormattedMessage
defaultMessage="Enabling data usage collection helps us manage and improve our products and services. See our {privacyStatementLink} for more details."
id="telemetry.telemetryConfigAndLinkDescription"
values={
Object {
"privacyStatementLink": <EuiLink
href="https://www.elastic.co/legal/privacy-statement"
target="_blank"
>
<FormattedMessage
defaultMessage="Privacy Statement"
id="telemetry.readOurUsageDataPrivacyStatementLinkText"
values={Object {}}
/>
</EuiLink>,
}
}
/>
</p>
<p>
<FormattedMessage
defaultMessage="See an example of the {clusterData} that we collect."
id="telemetry.seeExampleOfClusterData"
values={
Object {
"clusterData": <EuiLink
data-test-id="cluster_data_example"
onClick={[Function]}
>
<FormattedMessage
defaultMessage="cluster data"
id="telemetry.clusterData"
values={Object {}}
/>
</EuiLink>,
}
}
/>
</p>
</React.Fragment>
`;
exports[`TelemetryManagementSectionComponent renders as expected 1`] = `
<Fragment>
<_EuiSplitPanelOuter
@ -79,8 +124,8 @@ exports[`TelemetryManagementSectionComponent renders as expected 1`] = `
</p>
<p>
<FormattedMessage
defaultMessage="See an example of the {clusterData} that we collect."
id="telemetry.seeExampleOfClusterData"
defaultMessage="See examples of the {clusterData} and {endpointSecurityData} that we collect."
id="telemetry.seeExampleOfClusterDataAndEndpointSecuity"
values={
Object {
"clusterData": <EuiLink
@ -93,6 +138,16 @@ exports[`TelemetryManagementSectionComponent renders as expected 1`] = `
values={Object {}}
/>
</EuiLink>,
"endpointSecurityData": <EuiLink
data-test-id="endpoint_security_example"
onClick={[Function]}
>
<FormattedMessage
defaultMessage="endpoint security data"
id="telemetry.securityData"
values={Object {}}
/>
</EuiLink>,
}
}
/>
@ -232,6 +287,19 @@ exports[`TelemetryManagementSectionComponent renders null because allowChangingO
"timeZone": null,
}
}
isSecurityExampleEnabled={
[MockFunction] {
"calls": Array [
Array [],
],
"results": Array [
Object {
"type": "return",
"value": true,
},
],
}
}
onQueryMatchChange={[MockFunction]}
showAppliesSettingMessage={true}
telemetryService={

View file

@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import React from 'react';
import { shallowWithIntl } from '@kbn/test/jest';
import ExampleSecurityPayload from './example_security_payload';
describe('example security payload', () => {
it('renders as expected', () => {
expect(shallowWithIntl(<ExampleSecurityPayload />)).toMatchSnapshot();
});
});

View file

@ -0,0 +1,124 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { EuiCodeBlock } from '@elastic/eui';
import * as React from 'react';
const exampleSecurityPayload = {
'@timestamp': '2020-09-22T14:34:56.82202300Z',
agent: {
build: {
original:
'version: 7.9.1, compiled: Thu Aug 27 14:50:21 2020, branch: 7.9, commit: b594beb958817dee9b9d908191ed766d483df3ea',
},
id: '22dd8544-bcac-46cb-b970-5e681bb99e0b',
type: 'endpoint',
version: '7.9.1',
},
Endpoint: {
policy: {
applied: {
artifacts: {
global: {
identifiers: [
{
sha256: '6a546aade5563d3e8dffc1fe2d93d33edda8f9ca3e17ac3cc9ac707620cb9ecd',
name: 'endpointpe-v4-blocklist',
},
{
sha256: '04f9f87accc5d5aea433427bd1bd4ec6908f8528c78ceed26f70df7875a99385',
name: 'endpointpe-v4-exceptionlist',
},
{
sha256: '1471838597fcd79a54ea4a3ec9a9beee1a86feaedab6c98e61102559ced822a8',
name: 'endpointpe-v4-model',
},
{
sha256: '824859b0c6749cc31951d92a73bbdddfcfe9f38abfe432087934d4dab9766ce8',
name: 'global-exceptionlist-windows',
},
],
version: '1.0.0',
},
user: {
identifiers: [
{
sha256: 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658',
name: 'endpoint-exceptionlist-windows-v1',
},
],
version: '1.0.0',
},
},
},
},
},
ecs: {
version: '1.5.0',
},
elastic: {
agent: {
id: 'b2e88aea-2671-402a-828a-957526bac315',
},
},
file: {
path: 'C:\\Windows\\Temp\\mimikatz.exe',
size: 1263880,
created: '2020-05-19T07:50:06.0Z',
accessed: '2020-09-22T14:29:19.93531400Z',
mtime: '2020-09-22T14:29:03.6040000Z',
directory: 'C:\\Windows\\Temp',
hash: {
sha1: 'c9fb7f8a4c6b7b12b493a99a8dc6901d17867388',
sha256: 'cb1553a3c88817e4cc774a5a93f9158f6785bd3815447d04b6c3f4c2c4b21ed7',
md5: '465d5d850f54d9cde767bda90743df30',
},
Ext: {
code_signature: {
trusted: true,
subject_name: 'Open Source Developer, Benjamin Delpy',
exists: true,
status: 'trusted',
},
malware_classification: {
identifier: 'endpointpe-v4-model',
score: 0.99956864118576,
threshold: 0.71,
version: '0.0.0',
},
},
},
host: {
os: {
Ext: {
variant: 'Windows 10 Enterprise Evaluation',
},
kernel: '2004 (10.0.19041.388)',
name: 'Windows',
family: 'windows',
version: '2004 (10.0.19041.388)',
platform: 'windows',
full: 'Windows 10 Enterprise Evaluation 2004 (10.0.19041.388)',
},
},
event: {
kind: 'alert',
},
cluster_uuid: 'kLbKvSMcRiiFAR0t8LebDA',
cluster_name: 'elasticsearch',
};
const ExampleSecurityPayload: React.FC = () => {
return (
<EuiCodeBlock language="js">{JSON.stringify(exampleSecurityPayload, null, 2)}</EuiCodeBlock>
);
};
// Used for lazy import
// eslint-disable-next-line import/no-default-export
export default ExampleSecurityPayload;

View file

@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import React from 'react';
import { shallowWithIntl } from '@kbn/test/jest';
import { OptInSecurityExampleFlyout } from './opt_in_security_example_flyout';
describe('security flyout renders as expected', () => {
it('renders as expected', () => {
expect(shallowWithIntl(<OptInSecurityExampleFlyout onClose={jest.fn()} />)).toMatchSnapshot();
});
});

View file

@ -0,0 +1,58 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import * as React from 'react';
import {
EuiFlyout,
EuiFlyoutHeader,
EuiFlyoutBody,
EuiPortal, // EuiPortal is a temporary requirement to use EuiFlyout with "ownFocus"
EuiText,
EuiTextColor,
EuiTitle,
} from '@elastic/eui';
import { loadingSpinner } from './loading_spinner';
interface Props {
onClose: () => void;
}
const LazyExampleSecurityPayload = React.lazy(() => import('./example_security_payload'));
/**
* React component for displaying the example data associated with the Telemetry opt-in banner.
*/
export class OptInSecurityExampleFlyout extends React.PureComponent<Props> {
render() {
return (
<EuiPortal>
<EuiFlyout ownFocus onClose={this.props.onClose} maxWidth={true}>
<EuiFlyoutHeader>
<EuiTitle>
<h2>Endpoint security data</h2>
</EuiTitle>
<EuiTextColor color="subdued">
<EuiText>
This is a representative sample of the endpoint security alert event that we
collect. Endpoint security data is collected only when the Elastic Endpoint is
enabled. It includes information about the endpoint configuration and detection
events.
</EuiText>
</EuiTextColor>
</EuiFlyoutHeader>
<EuiFlyoutBody>
<React.Suspense fallback={loadingSpinner}>
<LazyExampleSecurityPayload />
</React.Suspense>
</EuiFlyoutBody>
</EuiFlyout>
</EuiPortal>
);
}
}

View file

@ -21,6 +21,7 @@ describe('TelemetryManagementSectionComponent', () => {
it('renders as expected', () => {
const onQueryMatchChange = jest.fn();
const isSecurityExampleEnabled = jest.fn().mockReturnValue(true);
const telemetryService = new TelemetryService({
config: {
enabled: true,
@ -45,6 +46,7 @@ describe('TelemetryManagementSectionComponent', () => {
onQueryMatchChange={onQueryMatchChange}
showAppliesSettingMessage={true}
enableSaving={true}
isSecurityExampleEnabled={isSecurityExampleEnabled}
toasts={coreStart.notifications.toasts}
docLinks={docLinks}
/>
@ -54,6 +56,7 @@ describe('TelemetryManagementSectionComponent', () => {
it('renders null because query does not match the SEARCH_TERMS', () => {
const onQueryMatchChange = jest.fn();
const isSecurityExampleEnabled = jest.fn().mockReturnValue(true);
const telemetryService = new TelemetryService({
config: {
enabled: true,
@ -78,6 +81,7 @@ describe('TelemetryManagementSectionComponent', () => {
onQueryMatchChange={onQueryMatchChange}
showAppliesSettingMessage={false}
enableSaving={true}
isSecurityExampleEnabled={isSecurityExampleEnabled}
toasts={coreStart.notifications.toasts}
docLinks={docLinks}
/>
@ -94,6 +98,7 @@ describe('TelemetryManagementSectionComponent', () => {
showAppliesSettingMessage={false}
enableSaving={true}
toasts={coreStart.notifications.toasts}
isSecurityExampleEnabled={isSecurityExampleEnabled}
docLinks={docLinks}
/>
</React.Suspense>
@ -107,6 +112,7 @@ describe('TelemetryManagementSectionComponent', () => {
it('renders because query matches the SEARCH_TERMS', () => {
const onQueryMatchChange = jest.fn();
const isSecurityExampleEnabled = jest.fn().mockReturnValue(true);
const telemetryService = new TelemetryService({
config: {
enabled: true,
@ -129,6 +135,7 @@ describe('TelemetryManagementSectionComponent', () => {
telemetryService={telemetryService}
onQueryMatchChange={onQueryMatchChange}
showAppliesSettingMessage={false}
isSecurityExampleEnabled={isSecurityExampleEnabled}
enableSaving={true}
toasts={coreStart.notifications.toasts}
docLinks={docLinks}
@ -154,6 +161,7 @@ describe('TelemetryManagementSectionComponent', () => {
it('renders null because allowChangingOptInStatus is false', () => {
const onQueryMatchChange = jest.fn();
const isSecurityExampleEnabled = jest.fn().mockReturnValue(true);
const telemetryService = new TelemetryService({
config: {
enabled: true,
@ -177,6 +185,7 @@ describe('TelemetryManagementSectionComponent', () => {
onQueryMatchChange={onQueryMatchChange}
showAppliesSettingMessage={true}
enableSaving={true}
isSecurityExampleEnabled={isSecurityExampleEnabled}
toasts={coreStart.notifications.toasts}
docLinks={docLinks}
/>
@ -192,6 +201,7 @@ describe('TelemetryManagementSectionComponent', () => {
it('shows the OptInExampleFlyout', () => {
const onQueryMatchChange = jest.fn();
const isSecurityExampleEnabled = jest.fn().mockReturnValue(true);
const telemetryService = new TelemetryService({
config: {
enabled: true,
@ -215,6 +225,7 @@ describe('TelemetryManagementSectionComponent', () => {
onQueryMatchChange={onQueryMatchChange}
showAppliesSettingMessage={false}
enableSaving={true}
isSecurityExampleEnabled={isSecurityExampleEnabled}
toasts={coreStart.notifications.toasts}
docLinks={docLinks}
/>
@ -229,8 +240,91 @@ describe('TelemetryManagementSectionComponent', () => {
}
});
it('shows the OptInSecurityExampleFlyout', () => {
const onQueryMatchChange = jest.fn();
const isSecurityExampleEnabled = jest.fn().mockReturnValue(true);
const telemetryService = new TelemetryService({
config: {
enabled: true,
url: '',
banner: true,
allowChangingOptInStatus: true,
optIn: false,
optInStatusUrl: '',
sendUsageFrom: 'browser',
},
isScreenshotMode: false,
reportOptInStatusChange: false,
notifications: coreStart.notifications,
currentKibanaVersion: 'mock_kibana_version',
http: coreSetup.http,
});
const component = mountWithIntl(
<TelemetryManagementSection
telemetryService={telemetryService}
onQueryMatchChange={onQueryMatchChange}
showAppliesSettingMessage={false}
isSecurityExampleEnabled={isSecurityExampleEnabled}
enableSaving={true}
toasts={coreStart.notifications.toasts}
docLinks={docLinks}
/>
);
try {
const toggleExampleComponent = component.find('FormattedMessage > EuiLink[onClick]').at(1);
const updatedView = toggleExampleComponent.simulate('click');
updatedView.find('OptInSecurityExampleFlyout');
updatedView.simulate('close');
} finally {
component.unmount();
}
});
it('does not show the endpoint link when isSecurityExampleEnabled returns false', () => {
const onQueryMatchChange = jest.fn();
const isSecurityExampleEnabled = jest.fn().mockReturnValue(false);
const telemetryService = new TelemetryService({
config: {
enabled: true,
url: '',
banner: true,
allowChangingOptInStatus: true,
optIn: false,
optInStatusUrl: '',
sendUsageFrom: 'browser',
},
isScreenshotMode: false,
reportOptInStatusChange: false,
currentKibanaVersion: 'mock_kibana_version',
notifications: coreStart.notifications,
http: coreSetup.http,
});
const component = mountWithIntl(
<TelemetryManagementSection
telemetryService={telemetryService}
onQueryMatchChange={onQueryMatchChange}
showAppliesSettingMessage={false}
isSecurityExampleEnabled={isSecurityExampleEnabled}
enableSaving={true}
toasts={coreStart.notifications.toasts}
docLinks={docLinks}
/>
);
try {
const description = (component.instance() as TelemetryManagementSection).renderDescription();
expect(isSecurityExampleEnabled).toBeCalled();
expect(description).toMatchSnapshot();
} finally {
component.unmount();
}
});
it('toggles the OptIn button', async () => {
const onQueryMatchChange = jest.fn();
const isSecurityExampleEnabled = jest.fn().mockReturnValue(true);
const telemetryService = new TelemetryService({
config: {
enabled: true,
@ -254,6 +348,7 @@ describe('TelemetryManagementSectionComponent', () => {
onQueryMatchChange={onQueryMatchChange}
showAppliesSettingMessage={false}
enableSaving={true}
isSecurityExampleEnabled={isSecurityExampleEnabled}
toasts={coreStart.notifications.toasts}
docLinks={docLinks}
/>
@ -280,6 +375,7 @@ describe('TelemetryManagementSectionComponent', () => {
it('test the wrapper (for coverage purposes)', () => {
const onQueryMatchChange = jest.fn();
const isSecurityExampleEnabled = jest.fn().mockReturnValue(true);
const telemetryService = new TelemetryService({
config: {
enabled: true,
@ -305,6 +401,7 @@ describe('TelemetryManagementSectionComponent', () => {
onQueryMatchChange={onQueryMatchChange}
enableSaving={true}
toasts={coreStart.notifications.toasts}
isSecurityExampleEnabled={isSecurityExampleEnabled}
docLinks={docLinks}
/>
).html()

View file

@ -15,6 +15,7 @@ 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 { TrackApplicationView } from '../../../usage_collection/public';
@ -25,6 +26,7 @@ const SEARCH_TERMS = ['telemetry', 'usage', 'data', 'usage data'];
interface Props {
telemetryService: TelemetryService;
onQueryMatchChange: (searchTermMatches: boolean) => void;
isSecurityExampleEnabled: () => boolean;
showAppliesSettingMessage: boolean;
enableSaving: boolean;
query?: { text: string };
@ -35,6 +37,7 @@ interface Props {
interface State {
processing: boolean;
showExample: boolean;
showSecurityExample: boolean;
queryMatches: boolean | null;
enabled: boolean;
}
@ -46,6 +49,7 @@ export class TelemetryManagementSection extends Component<Props, State> {
this.state = {
processing: false,
showExample: false,
showSecurityExample: false,
queryMatches: props.query ? this.checkQueryMatch(props.query) : null,
enabled: this.props.telemetryService.getIsOptedIn() || false,
};
@ -76,8 +80,9 @@ export class TelemetryManagementSection extends Component<Props, State> {
}
render() {
const { telemetryService } = this.props;
const { showExample, queryMatches, enabled, processing } = this.state;
const { telemetryService, isSecurityExampleEnabled } = this.props;
const { showExample, showSecurityExample, queryMatches, enabled, processing } = this.state;
const securityExampleEnabled = isSecurityExampleEnabled();
if (!telemetryService.getCanChangeOptInStatus()) {
return null;
@ -97,6 +102,11 @@ export class TelemetryManagementSection extends Component<Props, State> {
/>
</TrackApplicationView>
)}
{showSecurityExample && securityExampleEnabled && (
<TrackApplicationView viewId="optInSecurityExampleFlyout">
<OptInSecurityExampleFlyout onClose={this.toggleSecurityExample} />
</TrackApplicationView>
)}
<EuiSplitPanel.Outer hasBorder>
<EuiForm>
<EuiSplitPanel.Inner color="subdued">
@ -172,12 +182,20 @@ export class TelemetryManagementSection extends Component<Props, State> {
};
renderDescription = () => {
const { isSecurityExampleEnabled } = this.props;
const securityExampleEnabled = isSecurityExampleEnabled();
const clusterDataLink = (
<EuiLink onClick={this.toggleExample} data-test-id="cluster_data_example">
<FormattedMessage id="telemetry.clusterData" defaultMessage="cluster data" />
</EuiLink>
);
const endpointSecurityDataLink = (
<EuiLink onClick={this.toggleSecurityExample} data-test-id="endpoint_security_example">
<FormattedMessage id="telemetry.securityData" defaultMessage="endpoint security data" />
</EuiLink>
);
return (
<Fragment>
<p>
@ -198,13 +216,24 @@ export class TelemetryManagementSection extends Component<Props, State> {
/>
</p>
<p>
<FormattedMessage
id="telemetry.seeExampleOfClusterData"
defaultMessage="See an example of the {clusterData} that we collect."
values={{
clusterData: clusterDataLink,
}}
/>
{securityExampleEnabled ? (
<FormattedMessage
id="telemetry.seeExampleOfClusterDataAndEndpointSecuity"
defaultMessage="See examples of the {clusterData} and {endpointSecurityData} that we collect."
values={{
clusterData: clusterDataLink,
endpointSecurityData: endpointSecurityDataLink,
}}
/>
) : (
<FormattedMessage
id="telemetry.seeExampleOfClusterData"
defaultMessage="See an example of the {clusterData} that we collect."
values={{
clusterData: clusterDataLink,
}}
/>
)}
</p>
</Fragment>
);
@ -248,6 +277,15 @@ export class TelemetryManagementSection extends Component<Props, State> {
showExample: !this.state.showExample,
});
};
toggleSecurityExample = () => {
const { isSecurityExampleEnabled } = this.props;
const securityExampleEnabled = isSecurityExampleEnabled();
if (!securityExampleEnabled) return;
this.setState({
showSecurityExample: !this.state.showSecurityExample,
});
};
}
// required for lazy loading

View file

@ -12,19 +12,21 @@ import type { TelemetryPluginSetup } from 'src/plugins/telemetry/public';
import type TelemetryManagementSection from './telemetry_management_section';
export type TelemetryManagementSectionWrapperProps = Omit<
TelemetryManagementSection['props'],
'telemetryService' | 'showAppliesSettingMessage'
'telemetryService' | 'showAppliesSettingMessage' | 'isSecurityExampleEnabled'
>;
const TelemetryManagementSectionComponent = lazy(() => import('./telemetry_management_section'));
export function telemetryManagementSectionWrapper(
telemetryService: TelemetryPluginSetup['telemetryService']
telemetryService: TelemetryPluginSetup['telemetryService'],
shouldShowSecuritySolutionUsageExample: () => boolean
) {
const TelemetryManagementSectionWrapper = (props: TelemetryManagementSectionWrapperProps) => (
<Suspense fallback={<EuiLoadingSpinner />}>
<TelemetryManagementSectionComponent
showAppliesSettingMessage={true}
telemetryService={telemetryService}
isSecurityExampleEnabled={shouldShowSecuritySolutionUsageExample}
{...props}
/>
</Suspense>

View file

@ -10,6 +10,7 @@ import { TelemetryManagementSectionPlugin } from './plugin';
export { OptInExampleFlyout } from './components';
export type { TelemetryManagementSectionPluginSetup } from './plugin';
export function plugin() {
return new TelemetryManagementSectionPlugin();
}

View file

@ -10,7 +10,7 @@ import React from 'react';
import type { AdvancedSettingsSetup } from 'src/plugins/advanced_settings/public';
import type { TelemetryPluginSetup } from 'src/plugins/telemetry/public';
import type { UsageCollectionSetup } from 'src/plugins/usage_collection/public';
import type { CoreStart, CoreSetup } from 'src/core/public';
import type { Plugin, CoreStart, CoreSetup } from 'src/core/public';
import {
telemetryManagementSectionWrapper,
@ -34,7 +34,17 @@ export interface TelemetryManagementSectionPluginDepsSetup {
usageCollection?: UsageCollectionSetup;
}
export class TelemetryManagementSectionPlugin {
export interface TelemetryManagementSectionPluginSetup {
toggleSecuritySolutionExample: (enabled: boolean) => void;
}
export class TelemetryManagementSectionPlugin
implements Plugin<TelemetryManagementSectionPluginSetup> {
private showSecuritySolutionExample = false;
private shouldShowSecuritySolutionExample = () => {
return this.showSecuritySolutionExample;
};
public setup(
core: CoreSetup,
{
@ -50,16 +60,21 @@ export class TelemetryManagementSectionPlugin {
(props) => {
return (
<ApplicationUsageTrackingProvider>
{telemetryManagementSectionWrapper(telemetryService)(
props as TelemetryManagementSectionWrapperProps
)}
{telemetryManagementSectionWrapper(
telemetryService,
this.shouldShowSecuritySolutionExample
)(props as TelemetryManagementSectionWrapperProps)}
</ApplicationUsageTrackingProvider>
);
},
true
);
return {};
return {
toggleSecuritySolutionExample: (enabled: boolean) => {
this.showSecuritySolutionExample = enabled;
},
};
}
public start(core: CoreStart) {}

View file

@ -32,7 +32,8 @@
"usageCollection",
"lists",
"home",
"telemetry"
"telemetry",
"telemetryManagementSection"
],
"server": true,
"ui": true,

View file

@ -27,9 +27,14 @@ export const track: TrackFn = (type, event, count) => {
};
export const initTelemetry = (
{ usageCollection }: Pick<SetupPlugins, 'usageCollection'>,
{
usageCollection,
telemetryManagementSection,
}: Pick<SetupPlugins, 'usageCollection' | 'telemetryManagementSection'>,
appId: string
) => {
telemetryManagementSection?.toggleSecuritySolutionExample(true);
_track = usageCollection?.reportUiCounter?.bind(null, appId) ?? noop;
};

View file

@ -91,6 +91,7 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S
initTelemetry(
{
usageCollection: plugins.usageCollection,
telemetryManagementSection: plugins.telemetryManagementSection,
},
APP_ID
);

View file

@ -13,6 +13,7 @@ import { NewsfeedPublicPluginStart } from '../../../../src/plugins/newsfeed/publ
import { Start as InspectorStart } from '../../../../src/plugins/inspector/public';
import { UiActionsStart } from '../../../../src/plugins/ui_actions/public';
import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/public';
import { TelemetryManagementSectionPluginSetup } from '../../../../src/plugins/telemetry_management_section/public';
import { Storage } from '../../../../src/plugins/kibana_utils/public';
import { FleetStart } from '../../fleet/public';
import { PluginStart as ListsPluginStart } from '../../lists/public';
@ -45,6 +46,7 @@ export interface SetupPlugins {
security: SecurityPluginSetup;
triggersActionsUi: TriggersActionsSetup;
usageCollection?: UsageCollectionSetup;
telemetryManagementSection?: TelemetryManagementSectionPluginSetup;
ml?: MlPluginSetup;
}

View file

@ -3560,7 +3560,9 @@
"telemetry.provideUsageStatisticsAriaName": "使用統計を提供",
"telemetry.provideUsageStatisticsTitle": "使用統計を提供",
"telemetry.readOurUsageDataPrivacyStatementLinkText": "プライバシーポリシー",
"telemetry.securityData": "Endpoint Security データ",
"telemetry.seeExampleOfClusterData": "収集する {clusterData} の例をご覧ください。",
"telemetry.seeExampleOfClusterDataAndEndpointSecuity": "当社が収集する{clusterData}および{endpointSecurityData}の例をご覧ください。",
"telemetry.telemetryBannerDescription": "Elastic Stackの改善にご協力ください使用状況データの収集は現在無効です。使用状況データの収集を有効にすると、製品とサービスを管理して改善することができます。詳細については、{privacyStatementLink}をご覧ください。",
"telemetry.telemetryConfigAndLinkDescription": "使用状況データの収集を有効にすると、製品とサービスを管理して改善することができます。詳細については、{privacyStatementLink}をご覧ください。",
"telemetry.telemetryConfigDescription": "基本的な機能の利用状況に関する統計情報を提供して、Elastic Stack の改善にご協力ください。このデータは Elastic 社外と共有されません。",

View file

@ -3586,7 +3586,9 @@
"telemetry.provideUsageStatisticsAriaName": "提供使用情况统计",
"telemetry.provideUsageStatisticsTitle": "提供使用情况统计",
"telemetry.readOurUsageDataPrivacyStatementLinkText": "隐私声明",
"telemetry.securityData": "终端安全数据",
"telemetry.seeExampleOfClusterData": "查看我们收集的{clusterData}的示例。",
"telemetry.seeExampleOfClusterDataAndEndpointSecuity": "查看我们收集的{clusterData}和 {endpointSecurityData}示例。",
"telemetry.telemetryBannerDescription": "想帮助我们改进 Elastic Stack数据使用情况收集当前已禁用。启用使用情况数据收集可帮助我们管理并改善产品和服务。有关更多详情请参阅我们的{privacyStatementLink}。",
"telemetry.telemetryConfigAndLinkDescription": "启用使用情况数据收集可帮助我们管理并改善产品和服务。有关更多详情,请参阅我们的{privacyStatementLink}。",
"telemetry.telemetryConfigDescription": "通过提供基本功能的使用情况统计信息,来帮助我们改进 Elastic Stack。我们不会在 Elastic 之外共享此数据。",