From 71357a2572c14aa45e57d2f8a6045852f9c4176e Mon Sep 17 00:00:00 2001 From: Ahmad Bamieh Date: Tue, 20 Oct 2020 21:37:05 +0300 Subject: [PATCH] [7.10] [Telemetry] Add method to enable endpoint security data usage example (#80940) (#81170) --- ...telemetry_management_section.test.tsx.snap | 62 +++++++++- .../telemetry_management_section.test.tsx | 55 +++++++++ .../telemetry_management_section.tsx | 110 +++++++++++------- .../telemetry_management_section_wrapper.tsx | 4 +- .../public/index.ts | 4 +- .../public/plugin.tsx | 20 +++- x-pack/plugins/security_solution/kibana.json | 3 +- .../public/common/lib/telemetry/index.ts | 10 +- .../security_solution/public/plugin.tsx | 8 +- .../plugins/security_solution/public/types.ts | 2 + .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 12 files changed, 226 insertions(+), 54 deletions(-) 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 7357598c8495f..21b579bce898a 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 @@ -1,5 +1,50 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`TelemetryManagementSectionComponent does not show the endpoint link when isSecurityExampleEnabled returns false 1`] = ` + +

+ + + , + } + } + /> +

+

+ + + , + } + } + /> +

+
+`; + exports[`TelemetryManagementSectionComponent renders as expected 1`] = ` , "endpointSecurityData": { it('renders as expected', () => { const onQueryMatchChange = jest.fn(); + const isSecurityExampleEnabled = jest.fn().mockReturnValue(true); const telemetryService = new TelemetryService({ config: { enabled: true, @@ -51,6 +52,7 @@ describe('TelemetryManagementSectionComponent', () => { onQueryMatchChange={onQueryMatchChange} showAppliesSettingMessage={true} enableSaving={true} + isSecurityExampleEnabled={isSecurityExampleEnabled} toasts={coreStart.notifications.toasts} /> ) @@ -59,6 +61,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, @@ -81,6 +84,7 @@ describe('TelemetryManagementSectionComponent', () => { onQueryMatchChange={onQueryMatchChange} showAppliesSettingMessage={false} enableSaving={true} + isSecurityExampleEnabled={isSecurityExampleEnabled} toasts={coreStart.notifications.toasts} /> @@ -96,6 +100,7 @@ describe('TelemetryManagementSectionComponent', () => { showAppliesSettingMessage={false} enableSaving={true} toasts={coreStart.notifications.toasts} + isSecurityExampleEnabled={isSecurityExampleEnabled} /> ); @@ -108,6 +113,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, @@ -128,6 +134,7 @@ describe('TelemetryManagementSectionComponent', () => { telemetryService={telemetryService} onQueryMatchChange={onQueryMatchChange} showAppliesSettingMessage={false} + isSecurityExampleEnabled={isSecurityExampleEnabled} enableSaving={true} toasts={coreStart.notifications.toasts} /> @@ -152,6 +159,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, @@ -173,6 +181,7 @@ describe('TelemetryManagementSectionComponent', () => { onQueryMatchChange={onQueryMatchChange} showAppliesSettingMessage={true} enableSaving={true} + isSecurityExampleEnabled={isSecurityExampleEnabled} toasts={coreStart.notifications.toasts} /> ); @@ -187,6 +196,7 @@ describe('TelemetryManagementSectionComponent', () => { it('shows the OptInExampleFlyout', () => { const onQueryMatchChange = jest.fn(); + const isSecurityExampleEnabled = jest.fn().mockReturnValue(true); const telemetryService = new TelemetryService({ config: { enabled: true, @@ -208,6 +218,7 @@ describe('TelemetryManagementSectionComponent', () => { onQueryMatchChange={onQueryMatchChange} showAppliesSettingMessage={false} enableSaving={true} + isSecurityExampleEnabled={isSecurityExampleEnabled} toasts={coreStart.notifications.toasts} /> ); @@ -223,6 +234,7 @@ describe('TelemetryManagementSectionComponent', () => { it('shows the OptInSecurityExampleFlyout', () => { const onQueryMatchChange = jest.fn(); + const isSecurityExampleEnabled = jest.fn().mockReturnValue(true); const telemetryService = new TelemetryService({ config: { enabled: true, @@ -243,6 +255,7 @@ describe('TelemetryManagementSectionComponent', () => { telemetryService={telemetryService} onQueryMatchChange={onQueryMatchChange} showAppliesSettingMessage={false} + isSecurityExampleEnabled={isSecurityExampleEnabled} enableSaving={true} toasts={coreStart.notifications.toasts} /> @@ -257,8 +270,47 @@ describe('TelemetryManagementSectionComponent', () => { } }); + 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', + }, + reportOptInStatusChange: false, + notifications: coreStart.notifications, + http: coreSetup.http, + }); + + const component = mountWithIntl( + + ); + + 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, @@ -280,6 +332,7 @@ describe('TelemetryManagementSectionComponent', () => { onQueryMatchChange={onQueryMatchChange} showAppliesSettingMessage={false} enableSaving={true} + isSecurityExampleEnabled={isSecurityExampleEnabled} toasts={coreStart.notifications.toasts} /> ); @@ -304,6 +357,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, @@ -327,6 +381,7 @@ describe('TelemetryManagementSectionComponent', () => { onQueryMatchChange={onQueryMatchChange} enableSaving={true} toasts={coreStart.notifications.toasts} + isSecurityExampleEnabled={isSecurityExampleEnabled} /> ).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 822d8b49661c1..c43b600597c57 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 @@ -45,6 +45,7 @@ const SEARCH_TERMS = ['telemetry', 'usage', 'data', 'usage data']; interface Props { telemetryService: TelemetryService; onQueryMatchChange: (searchTermMatches: boolean) => void; + isSecurityExampleEnabled: () => boolean; showAppliesSettingMessage: boolean; enableSaving: boolean; query?: any; @@ -89,8 +90,9 @@ export class TelemetryManagementSection extends Component { } render() { - const { telemetryService } = this.props; + const { telemetryService, isSecurityExampleEnabled } = this.props; const { showExample, showSecurityExample, queryMatches, enabled, processing } = this.state; + const securityExampleEnabled = isSecurityExampleEnabled(); if (!telemetryService.getCanChangeOptInStatus()) { return null; @@ -108,7 +110,9 @@ export class TelemetryManagementSection extends Component { onClose={this.toggleExample} /> )} - {showSecurityExample && } + {showSecurityExample && securityExampleEnabled && ( + + )} @@ -181,48 +185,63 @@ export class TelemetryManagementSection extends Component { ); }; - renderDescription = () => ( - -

- - - - ), - }} - /> -

-

- - - - ), - endpointSecurityData: ( - - - - ), - }} - /> -

-
- ); + renderDescription = () => { + const { isSecurityExampleEnabled } = this.props; + const securityExampleEnabled = isSecurityExampleEnabled(); + const clusterDataLink = ( + + + + ); + + const endpointSecurityDataLink = ( + + + + ); + + return ( + +

+ + + + ), + }} + /> +

+

+ {securityExampleEnabled ? ( + + ) : ( + + )} +

+
+ ); + }; toggleOptIn = async (): Promise => { const { telemetryService, toasts } = this.props; @@ -264,6 +283,9 @@ export class TelemetryManagementSection extends Component { }; toggleSecurityExample = () => { + const { isSecurityExampleEnabled } = this.props; + const securityExampleEnabled = isSecurityExampleEnabled(); + if (!securityExampleEnabled) return; this.setState({ showSecurityExample: !this.state.showSecurityExample, }); 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 f61268c4772a3..95acbaba38845 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 @@ -28,13 +28,15 @@ type Props = any; const TelemetryManagementSectionComponent = lazy(() => import('./telemetry_management_section')); export function telemetryManagementSectionWrapper( - telemetryService: TelemetryPluginSetup['telemetryService'] + telemetryService: TelemetryPluginSetup['telemetryService'], + shouldShowSecuritySolutionUsageExample: () => boolean ) { const TelemetryManagementSectionWrapper = (props: Props) => ( }> diff --git a/src/plugins/telemetry_management_section/public/index.ts b/src/plugins/telemetry_management_section/public/index.ts index 082f68809a67e..f3aef9eca750d 100644 --- a/src/plugins/telemetry_management_section/public/index.ts +++ b/src/plugins/telemetry_management_section/public/index.ts @@ -16,9 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -export { OptInExampleFlyout } from './components'; import { TelemetryManagementSectionPlugin } from './plugin'; +export { OptInExampleFlyout } from './components'; + +export { TelemetryManagementSectionPluginSetup } from './plugin'; export function plugin() { return new TelemetryManagementSectionPlugin(); } diff --git a/src/plugins/telemetry_management_section/public/plugin.tsx b/src/plugins/telemetry_management_section/public/plugin.tsx index 738b38c36d30d..c200e830c8f61 100644 --- a/src/plugins/telemetry_management_section/public/plugin.tsx +++ b/src/plugins/telemetry_management_section/public/plugin.tsx @@ -38,16 +38,32 @@ export interface TelemetryManagementSectionPluginDepsSetup { advancedSettings: AdvancedSettingsSetup; } -export class TelemetryManagementSectionPlugin implements Plugin { +export interface TelemetryManagementSectionPluginSetup { + toggleSecuritySolutionExample: (enabled: boolean) => void; +} + +export class TelemetryManagementSectionPlugin + implements Plugin { + private showSecuritySolutionExample = false; + private shouldShowSecuritySolutionExample = () => { + return this.showSecuritySolutionExample; + }; + public setup( core: CoreSetup, { advancedSettings, telemetry: { telemetryService } }: TelemetryManagementSectionPluginDepsSetup ) { advancedSettings.component.register( advancedSettings.component.componentType.PAGE_FOOTER_COMPONENT, - telemetryManagementSectionWrapper(telemetryService), + telemetryManagementSectionWrapper(telemetryService, this.shouldShowSecuritySolutionExample), true ); + + return { + toggleSecuritySolutionExample: (enabled: boolean) => { + this.showSecuritySolutionExample = enabled; + }, + }; } public start(core: CoreStart) {} diff --git a/x-pack/plugins/security_solution/kibana.json b/x-pack/plugins/security_solution/kibana.json index 1fea4bb1aba54..145e34c4fc99c 100644 --- a/x-pack/plugins/security_solution/kibana.json +++ b/x-pack/plugins/security_solution/kibana.json @@ -28,7 +28,8 @@ "usageCollection", "lists", "home", - "telemetry" + "telemetry", + "telemetryManagementSection" ], "server": true, "ui": true, diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/index.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/index.ts index e79ef0d128225..863097a5cd2ee 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/index.ts @@ -25,7 +25,15 @@ export const track: TrackFn = (type, event, count) => { } }; -export const initTelemetry = (usageCollection: SetupPlugins['usageCollection'], appId: string) => { +export const initTelemetry = ( + { + usageCollection, + telemetryManagementSection, + }: Pick, + appId: string +) => { + telemetryManagementSection?.toggleSecuritySolutionExample(true); + _track = usageCollection?.reportUiStats?.bind(null, appId) ?? noop; }; diff --git a/x-pack/plugins/security_solution/public/plugin.tsx b/x-pack/plugins/security_solution/public/plugin.tsx index 96ab695e8d33c..a659d8f427ea4 100644 --- a/x-pack/plugins/security_solution/public/plugin.tsx +++ b/x-pack/plugins/security_solution/public/plugin.tsx @@ -74,7 +74,13 @@ export class Plugin implements IPlugin