[Telemetry] Move privacy statement URL to doc links (#126597)

* [DocLinksService] Define privacyStatement property

* Fix dockLinks typo

* Use docLinks instead of global constant

* Remove const

* Improve imports

* Update snapshot to fix UTs

* Fix incorrect imports

* Fix management section UTs

* Provide missing docLinks property to TelemetryManagementSectionComponent

* Simplify props, fix UTs

* Fix UTs broken by merge from main

* Code cleanup

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Gerard Soldevila 2022-03-18 10:56:38 +01:00 committed by GitHub
parent 6aefe172fa
commit 649fc1f583
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 386 additions and 202 deletions

View file

@ -602,5 +602,8 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => {
endpoints: {
troubleshooting: `${ELASTIC_WEBSITE_URL}guide/en/security/${DOC_LINK_VERSION}/ts-management.html#ts-endpoints`,
},
legal: {
privacyStatement: `${ELASTIC_WEBSITE_URL}legal/privacy-statement`,
},
});
};

View file

@ -364,4 +364,7 @@ export interface DocLinks {
readonly endpoints: {
readonly troubleshooting: string;
};
readonly legal: {
readonly privacyStatement: string;
};
}

View file

@ -12,11 +12,11 @@ import type { SharedUxDocLinksService } from '../doc_links';
/**
* A factory function for creating a Jest implementation of `SharedUxDocLinksService`.
*/
export type MockDockLinksServiceFactory = ServiceFactory<SharedUxDocLinksService>;
export type MockDocLinksServiceFactory = ServiceFactory<SharedUxDocLinksService>;
/**
* A factory function for creating a Jest-based implementation of `SharedUxDocLinksService`.
*/
export const docLinksServiceFactory: MockDockLinksServiceFactory = () => ({
export const docLinksServiceFactory: MockDocLinksServiceFactory = () => ({
dataViewsDocLink: 'dummy link',
});

View file

@ -16,7 +16,7 @@ import { userPermissionsServiceFactory } from './permissions.mock';
import { platformServiceFactory } from './platform.mock';
export type { MockApplicationServiceFactory } from './application.mock';
export type { MockDockLinksServiceFactory } from './doc_links.mock';
export type { MockDocLinksServiceFactory } from './doc_links.mock';
export type { MockEditorsServiceFactory } from './editors.mock';
export type { MockHttpServiceFactory } from './http.mock';
export type { MockUserPermissionsServiceFactory } from './permissions.mock';

View file

@ -12,11 +12,11 @@ import type { SharedUxDocLinksService } from '../doc_links';
/**
* A factory function for creating a stubbed implementation of `SharedUxDocLinksService`.
*/
export type DockLinksServiceFactory = ServiceFactory<SharedUxDocLinksService>;
export type DocLinksServiceFactory = ServiceFactory<SharedUxDocLinksService>;
/**
* A factory function for creating a stubbed implementation of `SharedUxDocLinksService`.
*/
export const docLinksServiceFactory: DockLinksServiceFactory = () => ({
export const docLinksServiceFactory: DocLinksServiceFactory = () => ({
dataViewsDocLink: 'docs',
});

View file

@ -252,7 +252,7 @@ describe('AdvancedSettings', () => {
history={mockHistory}
enableSaving={true}
toasts={notificationServiceMock.createStartContract().toasts}
dockLinks={docLinksServiceMock.createStartContract().links}
docLinks={docLinksServiceMock.createStartContract().links}
uiSettings={mockConfig().core.uiSettings}
componentRegistry={new ComponentRegistry().start}
theme={themeServiceMock.createStartContract().theme$}
@ -275,7 +275,7 @@ describe('AdvancedSettings', () => {
history={mockHistory}
enableSaving={false}
toasts={notificationServiceMock.createStartContract().toasts}
dockLinks={docLinksServiceMock.createStartContract().links}
docLinks={docLinksServiceMock.createStartContract().links}
uiSettings={mockConfig().core.uiSettings}
componentRegistry={new ComponentRegistry().start}
theme={themeServiceMock.createStartContract().theme$}
@ -302,7 +302,7 @@ describe('AdvancedSettings', () => {
history={mockHistory}
enableSaving={false}
toasts={toasts}
dockLinks={docLinksServiceMock.createStartContract().links}
docLinks={docLinksServiceMock.createStartContract().links}
uiSettings={mockConfig().core.uiSettings}
componentRegistry={new ComponentRegistry().start}
theme={themeServiceMock.createStartContract().theme$}

View file

@ -41,7 +41,7 @@ interface AdvancedSettingsProps {
history: ScopedHistory;
enableSaving: boolean;
uiSettings: IUiSettingsClient;
dockLinks: DocLinksStart['links'];
docLinks: DocLinksStart['links'];
toasts: ToastsStart;
theme: ThemeServiceStart['theme$'];
componentRegistry: ComponentRegistry['start'];
@ -270,7 +270,7 @@ export class AdvancedSettings extends Component<AdvancedSettingsProps, AdvancedS
save={this.saveConfig}
showNoResultsMessage={!footerQueryMatched}
enableSaving={this.props.enableSaving}
dockLinks={this.props.dockLinks}
docLinks={this.props.docLinks}
toasts={this.props.toasts}
trackUiMetric={this.props.trackUiMetric}
queryText={query.text}

View file

@ -207,7 +207,7 @@ describe('Field', () => {
handleChange={handleChange}
enableSaving={true}
toasts={notificationServiceMock.createStartContract().toasts}
dockLinks={docLinksServiceMock.createStartContract().links}
docLinks={docLinksServiceMock.createStartContract().links}
/>
);
@ -226,7 +226,7 @@ describe('Field', () => {
handleChange={handleChange}
enableSaving={true}
toasts={notificationServiceMock.createStartContract().toasts}
dockLinks={docLinksServiceMock.createStartContract().links}
docLinks={docLinksServiceMock.createStartContract().links}
/>
);
@ -240,7 +240,7 @@ describe('Field', () => {
handleChange={handleChange}
enableSaving={false}
toasts={notificationServiceMock.createStartContract().toasts}
dockLinks={docLinksServiceMock.createStartContract().links}
docLinks={docLinksServiceMock.createStartContract().links}
/>
);
expect(component).toMatchSnapshot();
@ -257,7 +257,7 @@ describe('Field', () => {
handleChange={handleChange}
enableSaving={true}
toasts={notificationServiceMock.createStartContract().toasts}
dockLinks={docLinksServiceMock.createStartContract().links}
docLinks={docLinksServiceMock.createStartContract().links}
/>
);
@ -274,7 +274,7 @@ describe('Field', () => {
handleChange={handleChange}
enableSaving={true}
toasts={notificationServiceMock.createStartContract().toasts}
dockLinks={docLinksServiceMock.createStartContract().links}
docLinks={docLinksServiceMock.createStartContract().links}
/>
);
expect(component).toMatchSnapshot();
@ -289,7 +289,7 @@ describe('Field', () => {
handleChange={handleChange}
enableSaving={true}
toasts={notificationServiceMock.createStartContract().toasts}
dockLinks={docLinksServiceMock.createStartContract().links}
docLinks={docLinksServiceMock.createStartContract().links}
unsavedChanges={{
// @ts-ignore
value: exampleValues[setting.type],
@ -311,7 +311,7 @@ describe('Field', () => {
handleChange={handleChange}
enableSaving={true}
toasts={notificationServiceMock.createStartContract().toasts}
dockLinks={docLinksServiceMock.createStartContract().links}
docLinks={docLinksServiceMock.createStartContract().links}
/>
);
const select = findTestSubject(component, `advancedSetting-editField-${setting.name}`);
@ -333,7 +333,7 @@ describe('Field', () => {
handleChange={handleChange}
enableSaving={true}
toasts={notificationServiceMock.createStartContract().toasts}
dockLinks={docLinksServiceMock.createStartContract().links}
docLinks={docLinksServiceMock.createStartContract().links}
{...props}
/>
</I18nProvider>

View file

@ -41,7 +41,7 @@ interface FieldProps {
setting: FieldSetting;
handleChange: (name: string, value: FieldState) => void;
enableSaving: boolean;
dockLinks: DocLinksStart['links'];
docLinks: DocLinksStart['links'];
toasts: ToastsStart;
clearChange?: (name: string) => void;
unsavedChanges?: FieldState;
@ -459,7 +459,7 @@ export class Field extends PureComponent<FieldProps> {
let deprecation;
if (setting.deprecation) {
const links = this.props.dockLinks;
const links = this.props.docLinks;
deprecation = (
<>

View file

@ -52,7 +52,7 @@ exports[`Form should not render no settings message when instructed not to 1`] =
<_EuiSplitPanelInner>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={true}
handleChange={[Function]}
key="general:test:date"
@ -78,7 +78,7 @@ exports[`Form should not render no settings message when instructed not to 1`] =
/>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={true}
handleChange={[Function]}
key="setting:test"
@ -104,7 +104,7 @@ exports[`Form should not render no settings message when instructed not to 1`] =
/>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={true}
handleChange={[Function]}
key="general:test:array"
@ -158,7 +158,7 @@ exports[`Form should not render no settings message when instructed not to 1`] =
<_EuiSplitPanelInner>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={true}
handleChange={[Function]}
key="dashboard:test:setting"
@ -236,7 +236,7 @@ exports[`Form should not render no settings message when instructed not to 1`] =
<_EuiSplitPanelInner>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={true}
handleChange={[Function]}
key="xpack:test:setting"
@ -321,7 +321,7 @@ exports[`Form should render no settings message when there are no settings 1`] =
<_EuiSplitPanelInner>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={true}
handleChange={[Function]}
key="general:test:date"
@ -347,7 +347,7 @@ exports[`Form should render no settings message when there are no settings 1`] =
/>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={true}
handleChange={[Function]}
key="setting:test"
@ -373,7 +373,7 @@ exports[`Form should render no settings message when there are no settings 1`] =
/>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={true}
handleChange={[Function]}
key="general:test:array"
@ -427,7 +427,7 @@ exports[`Form should render no settings message when there are no settings 1`] =
<_EuiSplitPanelInner>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={true}
handleChange={[Function]}
key="dashboard:test:setting"
@ -505,7 +505,7 @@ exports[`Form should render no settings message when there are no settings 1`] =
<_EuiSplitPanelInner>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={true}
handleChange={[Function]}
key="xpack:test:setting"
@ -590,7 +590,7 @@ exports[`Form should render normally 1`] = `
<_EuiSplitPanelInner>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={true}
handleChange={[Function]}
key="general:test:date"
@ -616,7 +616,7 @@ exports[`Form should render normally 1`] = `
/>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={true}
handleChange={[Function]}
key="setting:test"
@ -642,7 +642,7 @@ exports[`Form should render normally 1`] = `
/>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={true}
handleChange={[Function]}
key="general:test:array"
@ -696,7 +696,7 @@ exports[`Form should render normally 1`] = `
<_EuiSplitPanelInner>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={true}
handleChange={[Function]}
key="dashboard:test:setting"
@ -774,7 +774,7 @@ exports[`Form should render normally 1`] = `
<_EuiSplitPanelInner>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={true}
handleChange={[Function]}
key="xpack:test:setting"
@ -859,7 +859,7 @@ exports[`Form should render read-only when saving is disabled 1`] = `
<_EuiSplitPanelInner>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={false}
handleChange={[Function]}
key="general:test:date"
@ -885,7 +885,7 @@ exports[`Form should render read-only when saving is disabled 1`] = `
/>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={false}
handleChange={[Function]}
key="setting:test"
@ -911,7 +911,7 @@ exports[`Form should render read-only when saving is disabled 1`] = `
/>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={false}
handleChange={[Function]}
key="general:test:array"
@ -965,7 +965,7 @@ exports[`Form should render read-only when saving is disabled 1`] = `
<_EuiSplitPanelInner>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={false}
handleChange={[Function]}
key="dashboard:test:setting"
@ -1043,7 +1043,7 @@ exports[`Form should render read-only when saving is disabled 1`] = `
<_EuiSplitPanelInner>
<Field
clearChange={[Function]}
dockLinks={Object {}}
docLinks={Object {}}
enableSaving={false}
handleChange={[Function]}
key="xpack:test:setting"

View file

@ -8,12 +8,10 @@
import React from 'react';
import { shallowWithI18nProvider, mountWithI18nProvider } from '@kbn/test-jest-helpers';
import { UiSettingsType } from '../../../../../../core/public';
import { themeServiceMock } from '../../../../../../core/public/mocks';
import { findTestSubject } from '@elastic/eui/lib/test';
import { notificationServiceMock } from '../../../../../../core/public/mocks';
import { UiSettingsType } from '../../../../../../core/public';
import { themeServiceMock, notificationServiceMock } from '../../../../../../core/public/mocks';
import { SettingsChanges } from '../../types';
import { Form } from './form';
@ -127,7 +125,7 @@ describe('Form', () => {
showNoResultsMessage={true}
enableSaving={true}
toasts={{} as any}
dockLinks={{} as any}
docLinks={{} as any}
theme={themeServiceMock.createStartContract().theme$}
/>
);
@ -147,7 +145,7 @@ describe('Form', () => {
showNoResultsMessage={true}
enableSaving={false}
toasts={{} as any}
dockLinks={{} as any}
docLinks={{} as any}
theme={themeServiceMock.createStartContract().theme$}
/>
);
@ -167,7 +165,7 @@ describe('Form', () => {
showNoResultsMessage={true}
enableSaving={true}
toasts={{} as any}
dockLinks={{} as any}
docLinks={{} as any}
theme={themeServiceMock.createStartContract().theme$}
/>
);
@ -187,7 +185,7 @@ describe('Form', () => {
showNoResultsMessage={false}
enableSaving={true}
toasts={{} as any}
dockLinks={{} as any}
docLinks={{} as any}
theme={themeServiceMock.createStartContract().theme$}
/>
);
@ -207,7 +205,7 @@ describe('Form', () => {
showNoResultsMessage={true}
enableSaving={false}
toasts={{} as any}
dockLinks={{} as any}
docLinks={{} as any}
theme={themeServiceMock.createStartContract().theme$}
/>
);
@ -238,7 +236,7 @@ describe('Form', () => {
showNoResultsMessage={true}
enableSaving={false}
toasts={toasts}
dockLinks={{} as any}
docLinks={{} as any}
theme={themeServiceMock.createStartContract().theme$}
/>
);
@ -275,7 +273,7 @@ describe('Form', () => {
showNoResultsMessage={true}
enableSaving={false}
toasts={{} as any}
dockLinks={{} as any}
docLinks={{} as any}
theme={themeServiceMock.createStartContract().theme$}
/>
);
@ -304,7 +302,7 @@ describe('Form', () => {
showNoResultsMessage={true}
enableSaving={false}
toasts={{} as any}
dockLinks={{} as any}
docLinks={{} as any}
theme={themeServiceMock.createStartContract().theme$}
/>
);

View file

@ -44,7 +44,7 @@ interface FormProps {
save: (changes: SettingsChanges) => Promise<boolean[]>;
showNoResultsMessage: boolean;
enableSaving: boolean;
dockLinks: DocLinksStart['links'];
docLinks: DocLinksStart['links'];
toasts: ToastsStart;
theme: ThemeServiceStart['theme$'];
trackUiMetric?: (metricType: UiCounterMetricType, eventName: string | string[]) => void;
@ -264,7 +264,7 @@ export class Form extends PureComponent<FormProps> {
unsavedChanges={this.state.unsavedChanges[setting.name]}
clearChange={this.clearChange}
enableSaving={this.props.enableSaving}
dockLinks={this.props.dockLinks}
docLinks={this.props.docLinks}
toasts={this.props.toasts}
/>
);

View file

@ -82,7 +82,7 @@ export async function mountManagementSection(
history={params.history}
enableSaving={canSave}
toasts={notifications.toasts}
dockLinks={docLinks.links}
docLinks={docLinks.links}
uiSettings={uiSettings}
theme={params.theme$}
componentRegistry={componentRegistry}

View file

@ -6,9 +6,12 @@
* Side Public License, v 1.
*/
import { notificationServiceMock } from '../../../../../core/public/mocks';
import { httpServiceMock, themeServiceMock } from '../../../../../core/public/mocks';
import { docLinksServiceMock } from '../../../../../core/public/mocks';
import {
notificationServiceMock,
httpServiceMock,
themeServiceMock,
docLinksServiceMock,
} from '../../../../../core/public/mocks';
import type { ObjectStorageClient } from '../../../common/types';
import { HistoryMock } from '../../services/history.mock';

View file

@ -7,12 +7,9 @@
*/
import { i18n } from '@kbn/i18n';
import { CoreStart } from 'kibana/public';
import { ChromeStart, DocLinksStart } from 'kibana/public';
export function addHelpMenuToAppChrome(
chrome: CoreStart['chrome'],
docLinks: CoreStart['docLinks']
) {
export function addHelpMenuToAppChrome(chrome: ChromeStart, docLinks: DocLinksStart) {
chrome.setHelpExtension({
appName: i18n.translate('dashboard.helpMenu.appName', {
defaultMessage: 'Dashboards',

View file

@ -7,11 +7,11 @@
*/
import { EuiLink, EuiSpacer, EuiText } from '@elastic/eui';
import { CoreStart } from 'kibana/public';
import { DocLinksStart } from 'kibana/public';
import React from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
export const SearchSessionIncompleteWarning = (docLinks: CoreStart['docLinks']) => (
export const SearchSessionIncompleteWarning = (docLinks: DocLinksStart) => (
<>
<EuiSpacer size="s" />
It needs more time to fully render. You can wait here or come back to it later.

View file

@ -22,11 +22,15 @@ import {
} from 'rxjs/operators';
import { PublicMethodsOf } from '@kbn/utility-types';
import {
CoreSetup,
ApplicationStart,
CoreStart,
DocLinksStart,
HttpSetup,
IHttpFetchError,
IUiSettingsClient,
ThemeServiceSetup,
ToastsSetup,
ExecutionContextSetup,
} from 'kibana/public';
import { i18n } from '@kbn/i18n';
import { BatchedFunc, BfetchPublicSetup, DISABLE_BFETCH } from '../../../../bfetch/public';
@ -60,9 +64,9 @@ import { SearchAbortController } from './search_abort_controller';
export interface SearchInterceptorDeps {
bfetch: BfetchPublicSetup;
http: CoreSetup['http'];
executionContext: CoreSetup['executionContext'];
uiSettings: CoreSetup['uiSettings'];
http: HttpSetup;
executionContext: ExecutionContextSetup;
uiSettings: IUiSettingsClient;
startServices: Promise<[CoreStart, any, unknown]>;
toasts: ToastsSetup;
usageCollector?: SearchUsageCollector;
@ -91,8 +95,8 @@ export class SearchInterceptor {
/**
* @internal
*/
private application!: CoreStart['application'];
private docLinks!: CoreStart['docLinks'];
private application!: ApplicationStart;
private docLinks!: DocLinksStart;
private batchedFetch!: BatchedFunc<
{ request: IKibanaSearchRequest; options: ISearchOptionsSerializable },
IKibanaSearchResponse

View file

@ -11,11 +11,11 @@ import { EuiLink } from '@elastic/eui';
import type { FunctionComponent } from 'react';
import React, { useCallback } from 'react';
import type { CoreStart } from 'src/core/public';
import type { DocLinksStart } from 'kibana/public';
import { useKibana } from './use_kibana';
export type DocLinks = CoreStart['docLinks']['links'];
export type DocLinks = DocLinksStart['links'];
export type GetDocLinkFunction = (app: string, doc: string) => string;
/**

View file

@ -26,7 +26,7 @@ const SavedObjectsEditionPage = ({
}) => {
const { type, id } = useParams<{ type: string; id: string }>();
const capabilities = coreStart.application.capabilities;
const dockLinks = coreStart.docLinks.links;
const docLinks = coreStart.docLinks.links;
const { search } = useLocation();
const query = parse(search);
@ -64,7 +64,7 @@ const SavedObjectsEditionPage = ({
notFoundType={query.notFound as string}
uiSettings={coreStart.uiSettings}
history={history}
docLinks={dockLinks}
docLinks={docLinks}
/>
</RedirectAppLinks>
);

View file

@ -22,11 +22,6 @@ export const LOCALSTORAGE_KEY = 'telemetry.data';
*/
export const PATH_TO_ADVANCED_SETTINGS = '/app/management/kibana/settings';
/**
* Link to the Elastic Telemetry privacy statement.
*/
export const PRIVACY_STATEMENT_URL = `https://www.elastic.co/legal/privacy-statement`;
/**
* The telemetry payload content encryption encoding
*/

View file

@ -11,7 +11,13 @@ exports[`OptInDetailsComponent renders as expected 1`] = `
/>
}
>
<OptInMessage />
<OptInMessage
telemetryConstants={
Object {
"getPrivacyStatementUrl": [Function],
}
}
/>
<EuiSpacer
size="s"
/>

View file

@ -8,7 +8,7 @@ exports[`OptInMessage renders as expected 1`] = `
values={
Object {
"privacyStatementLink": <EuiLink
href="https://www.elastic.co/legal/privacy-statement"
href="https://some-host/some-url"
rel="noopener"
target="_blank"
>

View file

@ -20,7 +20,7 @@ exports[`OptInDetailsComponent renders as expected 1`] = `
/>
</EuiLink>,
"privacyStatementLink": <EuiLink
href="https://www.elastic.co/legal/privacy-statement"
href="https://some-host/some-url"
onClick={[Function]}
rel="noopener"
target="_blank"

View file

@ -10,15 +10,24 @@ import React from 'react';
import { EuiButton } from '@elastic/eui';
import { shallowWithIntl } from '@kbn/test-jest-helpers';
import { OptInBanner } from './opt_in_banner';
import { mockTelemetryConstants } from '../mocks';
describe('OptInDetailsComponent', () => {
const telemetryConstants = mockTelemetryConstants();
it('renders as expected', () => {
expect(shallowWithIntl(<OptInBanner onChangeOptInClick={() => {}} />)).toMatchSnapshot();
expect(
shallowWithIntl(
<OptInBanner onChangeOptInClick={() => {}} telemetryConstants={telemetryConstants} />
)
).toMatchSnapshot();
});
it('fires the "onChangeOptInClick" prop with true when a enable is clicked', () => {
const onClick = jest.fn();
const component = shallowWithIntl(<OptInBanner onChangeOptInClick={onClick} />);
const component = shallowWithIntl(
<OptInBanner onChangeOptInClick={onClick} telemetryConstants={telemetryConstants} />
);
const enableButton = component.findWhere((n) => {
const props = n.props();
@ -36,7 +45,9 @@ describe('OptInDetailsComponent', () => {
it('fires the "onChangeOptInClick" with false when a disable is clicked', () => {
const onClick = jest.fn();
const component = shallowWithIntl(<OptInBanner onChangeOptInClick={onClick} />);
const component = shallowWithIntl(
<OptInBanner onChangeOptInClick={onClick} telemetryConstants={telemetryConstants} />
);
const disableButton = component.findWhere((n) => {
const props = n.props();

View file

@ -10,14 +10,16 @@ import * as React from 'react';
import { EuiButton, EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { OptInMessage } from './opt_in_message';
import { TelemetryConstants } from '..';
interface Props {
onChangeOptInClick: (isOptIn: boolean) => void;
telemetryConstants: TelemetryConstants;
}
export class OptInBanner extends React.PureComponent<Props> {
render() {
const { onChangeOptInClick } = this.props;
const { onChangeOptInClick, telemetryConstants } = this.props;
const title = (
<FormattedMessage
id="telemetry.welcomeBanner.title"
@ -26,7 +28,7 @@ export class OptInBanner extends React.PureComponent<Props> {
);
return (
<EuiCallOut iconType="questionInCircle" title={title}>
<OptInMessage />
<OptInMessage telemetryConstants={telemetryConstants} />
<EuiSpacer size="s" />
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>

View file

@ -9,9 +9,14 @@
import React from 'react';
import { shallowWithIntl } from '@kbn/test-jest-helpers';
import { OptInMessage } from './opt_in_message';
import { mockTelemetryConstants } from '../mocks';
const telemetryConstants = mockTelemetryConstants();
describe('OptInMessage', () => {
it('renders as expected', () => {
expect(shallowWithIntl(<OptInMessage />)).toMatchSnapshot();
expect(
shallowWithIntl(<OptInMessage telemetryConstants={telemetryConstants} />)
).toMatchSnapshot();
});
});

View file

@ -9,9 +9,13 @@
import * as React from 'react';
import { EuiLink } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { PRIVACY_STATEMENT_URL } from '../../common/constants';
import { TelemetryConstants } from '..';
export class OptInMessage extends React.PureComponent {
interface Props {
telemetryConstants: TelemetryConstants;
}
export class OptInMessage extends React.PureComponent<Props> {
render() {
return (
<React.Fragment>
@ -20,7 +24,11 @@ export class OptInMessage extends React.PureComponent {
defaultMessage="Want to help us improve the Elastic Stack? Data usage collection is currently disabled. Enabling data usage collection helps us manage and improve our products and services. See our {privacyStatementLink} for more details."
values={{
privacyStatementLink: (
<EuiLink href={PRIVACY_STATEMENT_URL} target="_blank" rel="noopener">
<EuiLink
href={this.props.telemetryConstants.getPrivacyStatementUrl()}
target="_blank"
rel="noopener"
>
<FormattedMessage
id="telemetry.welcomeBanner.telemetryConfigDetailsDescription.telemetryPrivacyStatementLinkText"
defaultMessage="Privacy Statement"

View file

@ -10,22 +10,33 @@ import React from 'react';
import { EuiButton } from '@elastic/eui';
import { shallowWithIntl } from '@kbn/test-jest-helpers';
import { OptedInNoticeBanner } from './opted_in_notice_banner';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { httpServiceMock } from '../../../../core/public/http/http_service.mock';
import { httpServiceMock } from '../../../../core/public/mocks';
import { mockTelemetryConstants } from '../mocks';
const mockHttp = httpServiceMock.createStartContract();
const telemetryConstants = mockTelemetryConstants();
describe('OptInDetailsComponent', () => {
it('renders as expected', () => {
expect(
shallowWithIntl(<OptedInNoticeBanner onSeenBanner={() => {}} http={mockHttp} />)
shallowWithIntl(
<OptedInNoticeBanner
onSeenBanner={() => {}}
http={mockHttp}
telemetryConstants={telemetryConstants}
/>
)
).toMatchSnapshot();
});
it('fires the "onSeenBanner" prop when a link is clicked', () => {
const onLinkClick = jest.fn();
const component = shallowWithIntl(
<OptedInNoticeBanner onSeenBanner={onLinkClick} http={mockHttp} />
<OptedInNoticeBanner
onSeenBanner={onLinkClick}
http={mockHttp}
telemetryConstants={telemetryConstants}
/>
);
const button = component.findWhere((n) => n.type() === EuiButton);

View file

@ -12,17 +12,19 @@ import * as React from 'react';
import { EuiButton, EuiLink, EuiCallOut, EuiSpacer } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
import { PATH_TO_ADVANCED_SETTINGS, PRIVACY_STATEMENT_URL } from '../../common/constants';
import { HttpSetup } from '../../../../core/public';
import { HttpSetup } from 'kibana/public';
import { PATH_TO_ADVANCED_SETTINGS } from '../../common/constants';
import { TelemetryConstants } from '..';
interface Props {
http: HttpSetup;
onSeenBanner: () => unknown;
telemetryConstants: TelemetryConstants;
}
export class OptedInNoticeBanner extends React.PureComponent<Props> {
render() {
const { onSeenBanner, http } = this.props;
const { onSeenBanner, http, telemetryConstants } = this.props;
const basePath = http.basePath.get();
const bannerTitle = i18n.translate('telemetry.telemetryOptedInNoticeTitle', {
@ -38,7 +40,7 @@ export class OptedInNoticeBanner extends React.PureComponent<Props> {
privacyStatementLink: (
<EuiLink
onClick={onSeenBanner}
href={PRIVACY_STATEMENT_URL}
href={telemetryConstants.getPrivacyStatementUrl()}
target="_blank"
rel="noopener"
>

View file

@ -10,6 +10,7 @@ import type { PluginInitializerContext } from 'src/core/public';
import type { TelemetryPluginConfig } from './plugin';
import { TelemetryPlugin } from './plugin';
export type {
TelemetryConstants,
TelemetryPluginStart,
TelemetryPluginSetup,
TelemetryPluginConfig,

View file

@ -6,15 +6,15 @@
* Side Public License, v 1.
*/
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { overlayServiceMock } from '../../../core/public/overlays/overlay_service.mock';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { httpServiceMock } from '../../../core/public/http/http_service.mock';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { notificationServiceMock } from '../../../core/public/notifications/notifications_service.mock';
import {
overlayServiceMock,
httpServiceMock,
notificationServiceMock,
} from '../../../core/public/mocks';
import { TelemetryService } from './services/telemetry_service';
import { TelemetryNotifications } from './services/telemetry_notifications/telemetry_notifications';
import { TelemetryPluginStart, TelemetryPluginSetup, TelemetryPluginConfig } from './plugin';
import { TelemetryConstants } from '.';
// The following is to be able to access private methods
/* eslint-disable dot-notation */
@ -61,6 +61,12 @@ export function mockTelemetryService({
return telemetryService;
}
export function mockTelemetryConstants(): TelemetryConstants {
return {
getPrivacyStatementUrl: () => 'https://some-host/some-url',
};
}
export function mockTelemetryNotifications({
telemetryService,
}: {
@ -70,6 +76,7 @@ export function mockTelemetryNotifications({
http: httpServiceMock.createSetupContract(),
overlays: overlayServiceMock.createStartContract(),
telemetryService,
telemetryConstants: mockTelemetryConstants(),
});
}
@ -94,13 +101,12 @@ function createSetupContract(): Setup {
function createStartContract(): Start {
const telemetryService = mockTelemetryService();
const telemetryNotifications = mockTelemetryNotifications({ telemetryService });
const telemetryConstants = mockTelemetryConstants();
const startContract: Start = {
telemetryService,
telemetryNotifications,
telemetryConstants: {
getPrivacyStatementUrl: jest.fn(),
},
telemetryConstants,
};
return startContract;

View file

@ -15,6 +15,7 @@ import type {
SavedObjectsClientContract,
SavedObjectsBatchResponse,
ApplicationStart,
DocLinksStart,
} from 'src/core/public';
import type { ScreenshotModePluginSetup } from 'src/plugins/screenshot_mode/public';
@ -30,7 +31,6 @@ import {
getTelemetrySendUsageFrom,
} from '../common/telemetry_config';
import { getNotifyUserAboutOptInDefault } from '../common/telemetry_config/get_telemetry_notify_user_about_optin_default';
import { PRIVACY_STATEMENT_URL } from '../common/constants';
import { HomePublicPluginSetup } from '../../home/public';
import { renderWelcomeTelemetryNotice } from './render_welcome_telemetry_notice';
@ -67,6 +67,11 @@ export interface TelemetryPluginSetup {
/**
* Public's start exposed APIs by the telemetry plugin
*/
export interface TelemetryConstants {
/** Elastic's privacy statement url **/
getPrivacyStatementUrl: () => string;
}
export interface TelemetryPluginStart {
/** {@link TelemetryServicePublicApis} **/
telemetryService: TelemetryServicePublicApis;
@ -76,10 +81,7 @@ export interface TelemetryPluginStart {
setOptedInNoticeSeen: () => Promise<void>;
};
/** Set of publicly exposed telemetry constants **/
telemetryConstants: {
/** Elastic's privacy statement url **/
getPrivacyStatementUrl: () => string;
};
telemetryConstants: TelemetryConstants;
}
interface TelemetryPluginSetupDependencies {
@ -109,6 +111,12 @@ export interface TelemetryPluginConfig {
userCanChangeSettings?: boolean;
}
function getTelemetryConstants(docLinks: DocLinksStart): TelemetryConstants {
return {
getPrivacyStatementUrl: () => docLinks.links.legal.privacyStatement,
};
}
export class TelemetryPlugin implements Plugin<TelemetryPluginSetup, TelemetryPluginStart> {
private readonly currentKibanaVersion: string;
private readonly config: TelemetryPluginConfig;
@ -124,7 +132,7 @@ export class TelemetryPlugin implements Plugin<TelemetryPluginSetup, TelemetryPl
}
public setup(
{ http, notifications }: CoreSetup,
{ http, notifications, getStartServices }: CoreSetup,
{ screenshotMode, home }: TelemetryPluginSetupDependencies
): TelemetryPluginSetup {
const config = this.config;
@ -137,6 +145,12 @@ export class TelemetryPlugin implements Plugin<TelemetryPluginSetup, TelemetryPl
currentKibanaVersion,
});
let telemetryConstants: TelemetryConstants;
getStartServices().then(([{ docLinks }]) => {
telemetryConstants = getTelemetryConstants(docLinks);
});
this.telemetrySender = new TelemetrySender(this.telemetryService, async () => {
await this.refreshConfig();
});
@ -149,7 +163,11 @@ export class TelemetryPlugin implements Plugin<TelemetryPluginSetup, TelemetryPl
});
home.welcomeScreen.registerTelemetryNoticeRenderer(() =>
renderWelcomeTelemetryNotice(this.telemetryService!, http.basePath.prepend)
renderWelcomeTelemetryNotice(
this.telemetryService!,
http.basePath.prepend,
telemetryConstants
)
);
}
@ -158,18 +176,26 @@ export class TelemetryPlugin implements Plugin<TelemetryPluginSetup, TelemetryPl
};
}
public start({ http, overlays, application, savedObjects }: CoreStart): TelemetryPluginStart {
public start({
http,
overlays,
application,
savedObjects,
docLinks,
}: CoreStart): TelemetryPluginStart {
if (!this.telemetryService) {
throw Error('Telemetry plugin failed to initialize properly.');
}
this.canUserChangeSettings = this.getCanUserChangeSettings(application);
this.telemetryService.userCanChangeSettings = this.canUserChangeSettings;
const telemetryConstants = getTelemetryConstants(docLinks);
const telemetryNotifications = new TelemetryNotifications({
http,
overlays,
telemetryService: this.telemetryService,
telemetryConstants,
});
this.telemetryNotifications = telemetryNotifications;
@ -197,9 +223,7 @@ export class TelemetryPlugin implements Plugin<TelemetryPluginSetup, TelemetryPl
telemetryNotifications: {
setOptedInNoticeSeen: () => telemetryNotifications.setOptedInNoticeSeen(),
},
telemetryConstants: {
getPrivacyStatementUrl: () => PRIVACY_STATEMENT_URL,
},
telemetryConstants,
};
}

View file

@ -8,24 +8,32 @@
import { mountWithIntl } from '@kbn/test-jest-helpers';
import { renderWelcomeTelemetryNotice } from './render_welcome_telemetry_notice';
import { mockTelemetryService } from './mocks';
import { mockTelemetryConstants, mockTelemetryService } from './mocks';
describe('renderWelcomeTelemetryNotice', () => {
const telemetryConstants = mockTelemetryConstants();
test('it should show the opt-out message', () => {
const telemetryService = mockTelemetryService();
const component = mountWithIntl(renderWelcomeTelemetryNotice(telemetryService, (url) => url));
const component = mountWithIntl(
renderWelcomeTelemetryNotice(telemetryService, (url) => url, telemetryConstants)
);
expect(component.exists('[id="telemetry.dataManagementDisableCollectionLink"]')).toBe(true);
});
test('it should show the opt-in message', () => {
const telemetryService = mockTelemetryService({ config: { optIn: false } });
const component = mountWithIntl(renderWelcomeTelemetryNotice(telemetryService, (url) => url));
const component = mountWithIntl(
renderWelcomeTelemetryNotice(telemetryService, (url) => url, telemetryConstants)
);
expect(component.exists('[id="telemetry.dataManagementEnableCollectionLink"]')).toBe(true);
});
test('it should not show opt-in/out options if user cannot change the settings', () => {
const telemetryService = mockTelemetryService({ config: { allowChangingOptInStatus: false } });
const component = mountWithIntl(renderWelcomeTelemetryNotice(telemetryService, (url) => url));
const component = mountWithIntl(
renderWelcomeTelemetryNotice(telemetryService, (url) => url, telemetryConstants)
);
expect(component.exists('[id="telemetry.dataManagementDisableCollectionLink"]')).toBe(false);
expect(component.exists('[id="telemetry.dataManagementEnableCollectionLink"]')).toBe(false);
});

View file

@ -10,11 +10,12 @@ import React from 'react';
import { EuiLink, EuiSpacer, EuiTextColor } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import type { TelemetryService } from './services';
import { PRIVACY_STATEMENT_URL } from '../common/constants';
import { TelemetryConstants } from './plugin';
export function renderWelcomeTelemetryNotice(
telemetryService: TelemetryService,
addBasePath: (url: string) => string
addBasePath: (url: string) => string,
telemetryConstants: TelemetryConstants
) {
return (
<>
@ -23,7 +24,7 @@ export function renderWelcomeTelemetryNotice(
id="telemetry.dataManagementDisclaimerPrivacy"
defaultMessage="To learn about how usage data helps us manage and improve our products and services, see our "
/>
<EuiLink href={PRIVACY_STATEMENT_URL} target="_blank" rel="noopener">
<EuiLink href={telemetryConstants.getPrivacyStatementUrl()} target="_blank" rel="noopener">
<FormattedMessage
id="telemetry.dataManagementDisclaimerPrivacyLink"
defaultMessage="Privacy Statement."

View file

@ -7,18 +7,20 @@
*/
import { renderOptInBanner } from './render_opt_in_banner';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { overlayServiceMock } from '../../../../../core/public/overlays/overlay_service.mock';
import { overlayServiceMock } from '../../../../../core/public/mocks';
import { mockTelemetryConstants } from '../../mocks';
describe('renderOptInBanner', () => {
it('adds a banner to banners with priority of 10000', () => {
const bannerID = 'brucer-wayne';
const overlays = overlayServiceMock.createStartContract();
const telemetryConstants = mockTelemetryConstants();
overlays.banners.add.mockReturnValue(bannerID);
const returnedBannerId = renderOptInBanner({
setOptIn: jest.fn(),
overlays,
telemetryConstants,
});
expect(overlays.banners.add).toBeCalledTimes(1);

View file

@ -7,17 +7,21 @@
*/
import React from 'react';
import { CoreStart } from 'kibana/public';
import { OverlayStart } from 'kibana/public';
import { OptInBanner } from '../../components/opt_in_banner';
import { toMountPoint } from '../../../../kibana_react/public';
import { TelemetryConstants } from '../..';
interface RenderBannerConfig {
overlays: CoreStart['overlays'];
overlays: OverlayStart;
setOptIn: (isOptIn: boolean) => Promise<unknown>;
telemetryConstants: TelemetryConstants;
}
export function renderOptInBanner({ setOptIn, overlays }: RenderBannerConfig) {
const mount = toMountPoint(<OptInBanner onChangeOptInClick={setOptIn} />);
export function renderOptInBanner({ setOptIn, overlays, telemetryConstants }: RenderBannerConfig) {
const mount = toMountPoint(
<OptInBanner onChangeOptInClick={setOptIn} telemetryConstants={telemetryConstants} />
);
const bannerId = overlays.banners.add(mount, 10000);
return bannerId;

View file

@ -7,22 +7,22 @@
*/
import { renderOptedInNoticeBanner } from './render_opted_in_notice_banner';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { overlayServiceMock } from '../../../../../core/public/overlays/overlay_service.mock';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { httpServiceMock } from '../../../../../core/public/http/http_service.mock';
import { overlayServiceMock, httpServiceMock } from '../../../../../core/public/mocks';
import { mockTelemetryConstants } from '../../mocks';
describe('renderOptedInNoticeBanner', () => {
it('adds a banner to banners with priority of 10000', () => {
const bannerID = 'brucer-wayne';
const overlays = overlayServiceMock.createStartContract();
const mockHttp = httpServiceMock.createStartContract();
const telemetryConstants = mockTelemetryConstants();
overlays.banners.add.mockReturnValue(bannerID);
const returnedBannerId = renderOptedInNoticeBanner({
http: mockHttp,
onSeen: jest.fn(),
overlays,
telemetryConstants,
});
expect(overlays.banners.add).toBeCalledTimes(1);

View file

@ -7,17 +7,30 @@
*/
import React from 'react';
import { CoreStart } from 'kibana/public';
import { HttpStart, OverlayStart } from 'kibana/public';
import { OptedInNoticeBanner } from '../../components/opted_in_notice_banner';
import { toMountPoint } from '../../../../kibana_react/public';
import { TelemetryConstants } from '../..';
interface RenderBannerConfig {
http: CoreStart['http'];
overlays: CoreStart['overlays'];
http: HttpStart;
overlays: OverlayStart;
onSeen: () => void;
telemetryConstants: TelemetryConstants;
}
export function renderOptedInNoticeBanner({ onSeen, overlays, http }: RenderBannerConfig) {
const mount = toMountPoint(<OptedInNoticeBanner onSeenBanner={onSeen} http={http} />);
export function renderOptedInNoticeBanner({
onSeen,
overlays,
http,
telemetryConstants,
}: RenderBannerConfig) {
const mount = toMountPoint(
<OptedInNoticeBanner
onSeenBanner={onSeen}
http={http}
telemetryConstants={telemetryConstants}
/>
);
const bannerId = overlays.banners.add(mount, 10000);
return bannerId;

View file

@ -6,31 +6,40 @@
* Side Public License, v 1.
*/
import { CoreStart } from 'kibana/public';
import { HttpStart, OverlayStart } from 'kibana/public';
import { renderOptedInNoticeBanner } from './render_opted_in_notice_banner';
import { renderOptInBanner } from './render_opt_in_banner';
import { TelemetryService } from '../telemetry_service';
import { TelemetryConstants } from '../..';
interface TelemetryNotificationsConstructor {
http: CoreStart['http'];
overlays: CoreStart['overlays'];
http: HttpStart;
overlays: OverlayStart;
telemetryService: TelemetryService;
telemetryConstants: TelemetryConstants;
}
/**
* Helpers to the Telemetry banners spread through the code base in Welcome and Home landing pages.
*/
export class TelemetryNotifications {
private readonly http: CoreStart['http'];
private readonly overlays: CoreStart['overlays'];
private readonly http: HttpStart;
private readonly overlays: OverlayStart;
private readonly telemetryConstants: TelemetryConstants;
private readonly telemetryService: TelemetryService;
private optedInNoticeBannerId?: string;
private optInBannerId?: string;
constructor({ http, overlays, telemetryService }: TelemetryNotificationsConstructor) {
constructor({
http,
overlays,
telemetryService,
telemetryConstants,
}: TelemetryNotificationsConstructor) {
this.telemetryService = telemetryService;
this.http = http;
this.overlays = overlays;
this.telemetryConstants = telemetryConstants;
}
/**
@ -50,6 +59,7 @@ export class TelemetryNotifications {
http: this.http,
onSeen: this.setOptedInNoticeSeen,
overlays: this.overlays,
telemetryConstants: this.telemetryConstants,
});
this.optedInNoticeBannerId = bannerId;
@ -71,6 +81,7 @@ export class TelemetryNotifications {
const bannerId = renderOptInBanner({
setOptIn: this.onSetOptInClick,
overlays: this.overlays,
telemetryConstants: this.telemetryConstants,
});
this.optInBannerId = bannerId;

View file

@ -47,7 +47,13 @@ exports[`TelemetryManagementSectionComponent renders as expected 1`] = `
size="s"
/>
<lazy
dockLinks={Object {}}
docLinks={
Object {
"legal": Object {
"privacyStatement": "https://some-host/some-url",
},
}
}
enableSaving={true}
handleChange={[Function]}
loading={false}
@ -64,7 +70,7 @@ exports[`TelemetryManagementSectionComponent renders as expected 1`] = `
values={
Object {
"privacyStatementLink": <EuiLink
href="https://www.elastic.co/legal/privacy-statement"
href="https://some-host/some-url"
target="_blank"
>
<FormattedMessage
@ -139,7 +145,13 @@ exports[`TelemetryManagementSectionComponent renders as expected 1`] = `
exports[`TelemetryManagementSectionComponent renders null because allowChangingOptInStatus is false 1`] = `
<TelemetryManagementSection
docLinks={Object {}}
docLinks={
Object {
"legal": Object {
"privacyStatement": "https://some-host/some-url",
},
}
}
enableSaving={true}
intl={
Object {

View file

@ -16,7 +16,9 @@ import type { DocLinksStart } from 'src/core/public';
describe('TelemetryManagementSectionComponent', () => {
const coreStart = coreMock.createStart();
const docLinks = {} as DocLinksStart['links'];
const docLinks = {
legal: { privacyStatement: 'https://some-host/some-url' },
} as unknown as DocLinksStart['links'];
const coreSetup = coreMock.createSetup();
it('renders as expected', () => {

View file

@ -13,7 +13,6 @@ import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
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 { LazyField } from '../../../advanced_settings/public';
import { TrackApplicationView } from '../../../usage_collection/public';
@ -131,7 +130,7 @@ export class TelemetryManagementSection extends Component<Props, State> {
isCustom: true,
}}
loading={processing}
dockLinks={this.props.docLinks}
docLinks={this.props.docLinks}
toasts={this.props.toasts}
handleChange={this.toggleOptIn}
enableSaving={this.props.enableSaving}
@ -174,6 +173,8 @@ export class TelemetryManagementSection extends Component<Props, State> {
};
renderDescription = () => {
const { docLinks } = this.props;
const clusterDataLink = (
<EuiLink onClick={this.toggleExample} data-test-id="cluster_data_example">
<FormattedMessage id="telemetry.clusterData" defaultMessage="cluster data" />
@ -199,7 +200,7 @@ export class TelemetryManagementSection extends Component<Props, State> {
See our {privacyStatementLink} for more details."
values={{
privacyStatementLink: (
<EuiLink href={PRIVACY_STATEMENT_URL} target="_blank">
<EuiLink href={docLinks.legal.privacyStatement} target="_blank">
<FormattedMessage
id="telemetry.readOurUsageDataPrivacyStatementLinkText"
defaultMessage="Privacy Statement"

View file

@ -9,22 +9,26 @@
import React, { lazy, Suspense } from 'react';
import { EuiLoadingSpinner } from '@elastic/eui';
import type { TelemetryPluginSetup } from 'src/plugins/telemetry/public';
import { DocLinksStart } from 'kibana/public';
import type TelemetryManagementSection from './telemetry_management_section';
export type TelemetryManagementSectionWrapperProps = Omit<
TelemetryManagementSection['props'],
'telemetryService' | 'showAppliesSettingMessage'
'telemetryService' | 'showAppliesSettingMessage' | 'docLinks'
>;
const TelemetryManagementSectionComponent = lazy(() => import('./telemetry_management_section'));
export function telemetryManagementSectionWrapper(
telemetryService: TelemetryPluginSetup['telemetryService']
telemetryService: TelemetryPluginSetup['telemetryService'],
docLinks: DocLinksStart['links']
) {
const TelemetryManagementSectionWrapper = (props: TelemetryManagementSectionWrapperProps) => (
<Suspense fallback={<EuiLoadingSpinner />}>
<TelemetryManagementSectionComponent
showAppliesSettingMessage={true}
telemetryService={telemetryService}
docLinks={docLinks}
{...props}
/>
</Suspense>

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 { CoreStart, CoreSetup, DocLinksStart } from 'src/core/public';
import {
telemetryManagementSectionWrapper,
@ -32,6 +32,12 @@ export class TelemetryManagementSectionPlugin {
usageCollection,
}: TelemetryManagementSectionPluginDepsSetup
) {
let docLinksLinks: DocLinksStart['links'];
core.getStartServices().then(([{ docLinks }]) => {
docLinksLinks = docLinks?.links;
});
const ApplicationUsageTrackingProvider =
usageCollection?.components.ApplicationUsageTrackingProvider ?? React.Fragment;
advancedSettings.component.register(
@ -39,9 +45,10 @@ export class TelemetryManagementSectionPlugin {
(props) => {
return (
<ApplicationUsageTrackingProvider>
{telemetryManagementSectionWrapper(telemetryService)(
props as TelemetryManagementSectionWrapperProps
)}
{telemetryManagementSectionWrapper(
telemetryService,
docLinksLinks
)(props as TelemetryManagementSectionWrapperProps)}
</ApplicationUsageTrackingProvider>
);
},

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { CoreStart } from 'kibana/public';
import { DocLinksStart } from 'kibana/public';
import Mustache from 'mustache';
const TEMPLATE_TAGS = ['{', '}'];
@ -15,7 +15,7 @@ export function renderMustache({
docLinks,
}: {
text: string | string[];
docLinks?: CoreStart['docLinks'];
docLinks?: DocLinksStart;
}) {
const template = Array.isArray(text) ? text.join('\n') : text;

View file

@ -22,7 +22,7 @@ const getUISetting = (setting: string) => uiSettings[setting];
export const platformServiceFactory: CanvasPlatformServiceFactory = () => ({
getBasePath: () => '/base/path',
getBasePathInterface: noop,
getDocLinkVersion: () => 'dockLinkVersion',
getDocLinkVersion: () => 'docLinkVersion',
getElasticWebsiteUrl: () => 'https://elastic.co',
getKibanaVersion: () => 'kibanaVersion',
getHasWriteAccess: () => true,

View file

@ -8,7 +8,14 @@
import { mountWithIntl } from '@kbn/test-jest-helpers';
import { SearchBar, SearchBarProps, SearchBarComponent, SearchBarStateProps } from './search_bar';
import React, { Component, ReactElement } from 'react';
import { CoreStart } from 'src/core/public';
import {
DocLinksStart,
HttpStart,
IUiSettingsClient,
NotificationsStart,
OverlayStart,
SavedObjectsStart,
} from 'kibana/public';
import { act } from 'react-dom/test-utils';
import { IndexPattern, QueryStringInput } from '../../../../../src/plugins/data/public';
@ -32,18 +39,18 @@ function getServiceMocks() {
get: (key: string) => {
return 10;
},
} as CoreStart['uiSettings'],
savedObjects: {} as CoreStart['savedObjects'],
notifications: {} as CoreStart['notifications'],
} as IUiSettingsClient,
savedObjects: {} as SavedObjectsStart,
notifications: {} as NotificationsStart,
docLinks: {
links: {
query: {
kueryQuerySyntax: '',
},
},
} as CoreStart['docLinks'],
http: {} as CoreStart['http'],
overlays: {} as CoreStart['overlays'],
} as DocLinksStart,
http: {} as HttpStart,
overlays: {} as OverlayStart,
storage: {
get: () => {},
},

View file

@ -10,7 +10,14 @@ import { Observable } from 'rxjs';
import SemVer from 'semver/classes/semver';
import { ManagementAppMountParams } from 'src/plugins/management/public';
import { UsageCollectionSetup } from 'src/plugins/usage_collection/public';
import { CoreSetup, CoreStart, CoreTheme, ScopedHistory } from 'src/core/public';
import {
ApplicationStart,
CoreTheme,
FatalErrorsStart,
ScopedHistory,
DocLinksStart,
IUiSettingsClient,
} from 'src/core/public';
import { SharePluginStart } from 'src/plugins/share/public';
import { ExtensionsService } from '../services';
@ -20,8 +27,8 @@ const AppContext = createContext<AppDependencies | undefined>(undefined);
export interface AppDependencies {
core: {
fatalErrors: CoreStart['fatalErrors'];
getUrlForApp: CoreStart['application']['getUrlForApp'];
fatalErrors: FatalErrorsStart;
getUrlForApp: ApplicationStart['getUrlForApp'];
};
plugins: {
usageCollection: UsageCollectionSetup;
@ -35,9 +42,9 @@ export interface AppDependencies {
};
history: ScopedHistory;
setBreadcrumbs: ManagementAppMountParams['setBreadcrumbs'];
uiSettings: CoreSetup['uiSettings'];
uiSettings: IUiSettingsClient;
url: SharePluginStart['url'];
docLinks: CoreStart['docLinks'];
docLinks: DocLinksStart;
kibanaVersion: SemVer;
theme$: Observable<CoreTheme>;
}

View file

@ -5,7 +5,17 @@
* 2.0.
*/
import { CoreStart, HttpSetup, IUiSettingsClient, AppMountParameters } from 'kibana/public';
import {
CoreStart,
HttpSetup,
IUiSettingsClient,
AppMountParameters,
NotificationsStart,
ApplicationStart,
DocLinksStart,
ChromeStart,
I18nStart,
} from 'kibana/public';
import { Observable } from 'rxjs';
import { HttpRequestInit } from '../../../../src/core/public';
import {
@ -41,17 +51,17 @@ export interface KFetchKibanaOptions {
}
export interface IShims {
toastNotifications: CoreStart['notifications']['toasts'];
capabilities: CoreStart['application']['capabilities'];
toastNotifications: NotificationsStart['toasts'];
capabilities: ApplicationStart['capabilities'];
getBasePath: () => string;
getInjected: (name: string, defaultValue?: unknown) => unknown;
breadcrumbs: {
set: (breadcrumbs: BreadcrumbItem[]) => void;
update: (breadcrumbs?: BreadcrumbItem[]) => void;
};
I18nContext: CoreStart['i18n']['Context'];
docLinks: CoreStart['docLinks'];
docTitle: CoreStart['chrome']['docTitle'];
I18nContext: I18nStart['Context'];
docLinks: DocLinksStart;
docTitle: ChromeStart['docTitle'];
timefilter: MonitoringStartPluginDependencies['data']['query']['timefilter']['timefilter'];
actionTypeRegistry: TypeRegistry<ActionTypeModel>;
ruleTypeRegistry: TypeRegistry<RuleTypeModel>;

View file

@ -9,11 +9,11 @@ import { EuiLink } from '@elastic/eui';
import type { FunctionComponent } from 'react';
import React, { useCallback } from 'react';
import type { CoreStart } from 'src/core/public';
import type { DocLinksStart } from 'kibana/public';
import { useKibana } from '../../../../../src/plugins/kibana_react/public';
export type DocLinks = CoreStart['docLinks']['links'];
export type DocLinks = DocLinksStart['links'];
export type GetDocLinkFunction = (app: string, doc: string) => string;
/**

View file

@ -5,9 +5,20 @@
* 2.0.
*/
import type { CoreSetup, CoreStart } from 'src/core/public';
import type {
ApplicationStart,
ChromeStart,
DocLinksStart,
HttpSetup,
I18nStart,
IUiSettingsClient,
NotificationsSetup,
OverlayStart,
SavedObjectsStart,
ThemeServiceStart,
} from 'kibana/public';
import type { SavedObjectsStart as SavedObjectsPluginStart } from 'src/plugins/saved_objects/public';
import type { DataPublicPluginStart } from 'src/plugins/data/public';
import type { SavedObjectsStart } from 'src/plugins/saved_objects/public';
import type { ScopedHistory } from 'kibana/public';
import type { SharePluginStart } from 'src/plugins/share/public';
import type { SpacesPluginStart } from '../../../spaces/public';
@ -19,20 +30,20 @@ import type { GetMlSharedImportsReturnType } from '../shared_imports';
import type { TriggersAndActionsUIPublicPluginStart } from '../../../triggers_actions_ui/public';
export interface AppDependencies {
application: CoreStart['application'];
chrome: CoreStart['chrome'];
application: ApplicationStart;
chrome: ChromeStart;
data: DataPublicPluginStart;
docLinks: CoreStart['docLinks'];
http: CoreSetup['http'];
i18n: CoreStart['i18n'];
notifications: CoreSetup['notifications'];
uiSettings: CoreStart['uiSettings'];
savedObjects: CoreStart['savedObjects'];
docLinks: DocLinksStart;
http: HttpSetup;
i18n: I18nStart;
notifications: NotificationsSetup;
uiSettings: IUiSettingsClient;
savedObjects: SavedObjectsStart;
storage: Storage;
overlays: CoreStart['overlays'];
theme: CoreStart['theme'];
overlays: OverlayStart;
theme: ThemeServiceStart;
history: ScopedHistory;
savedObjectsPlugin: SavedObjectsStart;
savedObjectsPlugin: SavedObjectsPluginStart;
share: SharePluginStart;
ml: GetMlSharedImportsReturnType;
spaces?: SpacesPluginStart;

View file

@ -5,15 +5,20 @@
* 2.0.
*/
import { CoreStart } from 'kibana/public';
import {
HttpStart,
DocLinksStart,
IUiSettingsClient,
ApplicationStart,
} from 'kibana/public';
import { useKibana } from '../../../../../src/plugins/kibana_react/public';
import { ApmPluginStartDeps } from '../plugin';
interface UxKibanaServices extends ApmPluginStartDeps {
http: CoreStart['http'];
docLinks: CoreStart['docLinks'];
uiSettings: CoreStart['uiSettings'];
application: CoreStart['application'];
http: HttpStart;
docLinks: DocLinksStart;
uiSettings: IUiSettingsClient;
application: ApplicationStart;
}
export function useKibanaServices() {