Telemetry/opt in welcome screen (#42110)
* refactor opt_in_message * welcome optin card * finish optin in welcome screen * add steps * disable current step * remove checkbox option * add metrics * fix typescript checks * hide in oss * update snapshots * only require TelemetryOptInProvider if telemetry is enabled * pass telemetry description from service * remove x-pack import * remove x-pack import * update image * update per design feedback * update props * fix in oss * await before moving to next screen * utlize bannerId in telemtry provider * keep export in 1 line * ts-ignore banner import * add test * update tests * update translations * update home tests * remove extra license header * showTelemetryOptIn -> shouldShowTelemetryOptIn * remote extra EuiTexts * update jest snapshot * unencrypted telemetry example
This commit is contained in:
parent
1d0c1c2196
commit
5917cd375f
BIN
src/legacy/core_plugins/kibana/public/assets/illo_telemetry.png
Normal file
BIN
src/legacy/core_plugins/kibana/public/assets/illo_telemetry.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 546 KiB |
|
@ -1135,7 +1135,10 @@ exports[`home welcome should show the normal home page if welcome screen is disa
|
|||
|
||||
exports[`home welcome should show the welcome screen if enabled, and there are no index patterns defined 1`] = `
|
||||
<Welcome
|
||||
fetchTelemetry={[MockFunction]}
|
||||
getTelemetryBannerId={[MockFunction]}
|
||||
onSkip={[Function]}
|
||||
setOptIn={[MockFunction]}
|
||||
urlBasePath="goober"
|
||||
/>
|
||||
`;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
|
||||
.homWelcome {
|
||||
@include kibanaFullScreenGraphics;
|
||||
@include kibanaFullScreenGraphics($euiZLevel6);
|
||||
}
|
||||
|
||||
.homWelcome__header {
|
||||
|
|
|
@ -225,6 +225,10 @@ export class Home extends Component {
|
|||
<Welcome
|
||||
onSkip={this.skipWelcome}
|
||||
urlBasePath={this.props.urlBasePath}
|
||||
shouldShowTelemetryOptIn={this.props.shouldShowTelemetryOptIn}
|
||||
fetchTelemetry={this.props.fetchTelemetry}
|
||||
setOptIn={this.props.setOptIn}
|
||||
getTelemetryBannerId={this.props.getTelemetryBannerId}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -247,6 +251,10 @@ export class Home extends Component {
|
|||
|
||||
Home.propTypes = {
|
||||
addBasePath: PropTypes.func.isRequired,
|
||||
fetchTelemetry: PropTypes.func.isRequired,
|
||||
getTelemetryBannerId: PropTypes.func.isRequired,
|
||||
setOptIn: PropTypes.func.isRequired,
|
||||
shouldShowTelemetryOptIn: PropTypes.bool.isRequired,
|
||||
directories: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
id: PropTypes.string.isRequired,
|
||||
|
|
|
@ -17,30 +17,14 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import './home.test.mocks';
|
||||
|
||||
import React from 'react';
|
||||
import sinon from 'sinon';
|
||||
import { shallow } from 'enzyme';
|
||||
import { Home } from './home';
|
||||
import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
|
||||
|
||||
jest.mock(
|
||||
'ui/chrome',
|
||||
() => ({
|
||||
getBasePath: jest.fn(() => 'path'),
|
||||
getInjected: jest.fn(() => ''),
|
||||
}),
|
||||
{ virtual: true }
|
||||
);
|
||||
|
||||
jest.mock(
|
||||
'ui/capabilities',
|
||||
() => ({
|
||||
catalogue: {},
|
||||
management: {},
|
||||
navLinks: {}
|
||||
})
|
||||
);
|
||||
|
||||
describe('home', () => {
|
||||
let defaultProps;
|
||||
|
||||
|
@ -50,6 +34,10 @@ describe('home', () => {
|
|||
apmUiEnabled: true,
|
||||
mlEnabled: true,
|
||||
kibanaVersion: '99.2.1',
|
||||
fetchTelemetry: jest.fn(),
|
||||
getTelemetryBannerId: jest.fn(),
|
||||
setOptIn: jest.fn(),
|
||||
showTelemetryOptIn: false,
|
||||
addBasePath(url) {
|
||||
return `base_path/${url}`;
|
||||
},
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { notificationServiceMock } from '../../../../../../core/public/mocks';
|
||||
|
||||
jest.doMock('ui/new_platform', () => {
|
||||
return {
|
||||
npSetup: {
|
||||
core: {
|
||||
notifications: notificationServiceMock.createSetupContract(),
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
jest.doMock(
|
||||
'ui/chrome',
|
||||
() => ({
|
||||
getBasePath: jest.fn(() => 'path'),
|
||||
getInjected: jest.fn(() => ''),
|
||||
}),
|
||||
{ virtual: true }
|
||||
);
|
||||
|
||||
jest.doMock('ui/capabilities', () => ({
|
||||
catalogue: {},
|
||||
management: {},
|
||||
navLinks: {},
|
||||
}));
|
|
@ -30,12 +30,10 @@ import {
|
|||
} from 'react-router-dom';
|
||||
import { getTutorial } from '../load_tutorials';
|
||||
import { replaceTemplateStrings } from './tutorial/replace_template_strings';
|
||||
import { telemetryOptInProvider, shouldShowTelemetryOptIn } from '../kibana_services';
|
||||
import chrome from 'ui/chrome';
|
||||
|
||||
export function HomeApp({
|
||||
directories,
|
||||
}) {
|
||||
|
||||
export function HomeApp({ directories }) {
|
||||
const isCloudEnabled = chrome.getInjected('isCloudEnabled', false);
|
||||
const apmUiEnabled = chrome.getInjected('apmUiEnabled', true);
|
||||
const mlEnabled = chrome.getInjected('mlEnabled', false);
|
||||
|
@ -94,6 +92,10 @@ export function HomeApp({
|
|||
find={savedObjectsClient.find}
|
||||
localStorage={localStorage}
|
||||
urlBasePath={chrome.getBasePath()}
|
||||
shouldShowTelemetryOptIn={shouldShowTelemetryOptIn}
|
||||
setOptIn={telemetryOptInProvider.setOptIn}
|
||||
fetchTelemetry={telemetryOptInProvider.fetchExample}
|
||||
getTelemetryBannerId={telemetryOptInProvider.getBannerId}
|
||||
/>
|
||||
</Route>
|
||||
</Switch>
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The UI and related logic for the welcome screen that *should* show only
|
||||
* when it is enabled (the default) and there is no Kibana-consumed data
|
||||
* in Elasticsearch.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
// @ts-ignore
|
||||
EuiCard,
|
||||
EuiButton,
|
||||
EuiButtonEmpty,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
interface Props {
|
||||
urlBasePath: string;
|
||||
onDecline: () => void;
|
||||
onConfirm: () => void;
|
||||
}
|
||||
|
||||
export function SampleDataCard({ urlBasePath, onDecline, onConfirm }: Props) {
|
||||
return (
|
||||
<EuiCard
|
||||
image={`${urlBasePath}/plugins/kibana/assets/illo_dashboard.png`}
|
||||
textAlign="left"
|
||||
title={<FormattedMessage id="kbn.home.letsStartTitle" defaultMessage="Let's get started" />}
|
||||
description={
|
||||
<FormattedMessage
|
||||
id="kbn.home.letsStartDescription"
|
||||
defaultMessage="We noticed that you don't have any data in your cluster.
|
||||
You can try our sample data and dashboards or jump in with your own data."
|
||||
/>
|
||||
}
|
||||
footer={
|
||||
<footer>
|
||||
<EuiButton fill className="homWelcome__footerAction" onClick={onConfirm}>
|
||||
<FormattedMessage id="kbn.home.tryButtonLabel" defaultMessage="Try our sample data" />
|
||||
</EuiButton>
|
||||
<EuiButtonEmpty
|
||||
className="homWelcome__footerAction"
|
||||
onClick={onDecline}
|
||||
data-test-subj="skipWelcomeScreen"
|
||||
>
|
||||
<FormattedMessage id="kbn.home.exploreButtonLabel" defaultMessage="Explore on my own" />
|
||||
</EuiButtonEmpty>
|
||||
</footer>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { renderTelemetryOptInCard, Props } from './telemetry_opt_in_card';
|
||||
|
||||
export const TelemetryOptInCard = (props: Props) => {
|
||||
return renderTelemetryOptInCard(props);
|
||||
};
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
import {
|
||||
EuiCallOut,
|
||||
EuiCodeBlock,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiFlyout,
|
||||
EuiFlyoutHeader,
|
||||
EuiFlyoutBody,
|
||||
EuiLoadingSpinner,
|
||||
EuiPortal, // EuiPortal is a temporary requirement to use EuiFlyout with "ownFocus"
|
||||
EuiText,
|
||||
EuiTextColor,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
interface Props {
|
||||
fetchTelemetry: () => Promise<any>;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
interface State {
|
||||
isLoading: boolean;
|
||||
hasPrivilegeToRead: boolean;
|
||||
data: any[] | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* React component for displaying the example data associated with the Telemetry opt-in banner.
|
||||
*/
|
||||
export class OptInExampleFlyout extends React.PureComponent<Props, State> {
|
||||
public readonly state: State = {
|
||||
data: null,
|
||||
isLoading: true,
|
||||
hasPrivilegeToRead: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.props
|
||||
.fetchTelemetry()
|
||||
.then(response =>
|
||||
this.setState({
|
||||
data: Array.isArray(response.data) ? response.data : null,
|
||||
isLoading: false,
|
||||
hasPrivilegeToRead: true,
|
||||
})
|
||||
)
|
||||
.catch(err => {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
hasPrivilegeToRead: err.status !== 403,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
renderBody({ data, isLoading, hasPrivilegeToRead }: State) {
|
||||
if (isLoading) {
|
||||
return (
|
||||
<EuiFlexGroup justifyContent="spaceAround">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiLoadingSpinner size="xl" />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
|
||||
if (!hasPrivilegeToRead) {
|
||||
return (
|
||||
<EuiCallOut
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="kbn.home.telemetry.callout.errorUnprivilegedUserTitle"
|
||||
defaultMessage="Error displaying cluster statistics"
|
||||
/>
|
||||
}
|
||||
color="danger"
|
||||
iconType="cross"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="kbn.home.telemetry.callout.errorUnprivilegedUserDescription"
|
||||
defaultMessage="You do not have access to see unencrypted cluster statistics."
|
||||
/>
|
||||
</EuiCallOut>
|
||||
);
|
||||
}
|
||||
|
||||
if (data === null) {
|
||||
return (
|
||||
<EuiCallOut
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="kbn.home.telemetry.callout.errorLoadingClusterStatisticsTitle"
|
||||
defaultMessage="Error loading cluster statistics"
|
||||
/>
|
||||
}
|
||||
color="danger"
|
||||
iconType="cross"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="kbn.home.telemetry.callout.errorLoadingClusterStatisticsDescription"
|
||||
defaultMessage="An unexpected error occured while attempting to fetch the cluster statistics.
|
||||
This can occur because Elasticsearch failed, Kibana failed, or there is a network error.
|
||||
Check Kibana, then reload the page and try again."
|
||||
/>
|
||||
</EuiCallOut>
|
||||
);
|
||||
}
|
||||
|
||||
return <EuiCodeBlock language="js">{JSON.stringify(data, null, 2)}</EuiCodeBlock>;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<EuiPortal>
|
||||
<EuiFlyout ownFocus onClose={this.props.onClose} maxWidth={true}>
|
||||
<EuiFlyoutHeader>
|
||||
<EuiTitle>
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="kbn.home.telemetry.callout.clusterStatisticsTitle"
|
||||
defaultMessage="Cluster statistics"
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
<EuiTextColor color="subdued">
|
||||
<EuiText>
|
||||
<FormattedMessage
|
||||
id="kbn.home.telemetry.callout.clusterStatisticsDescription"
|
||||
defaultMessage="This is an example of the basic cluster statistics that we'll collect.
|
||||
It includes the number of indices, shards, and nodes.
|
||||
It also includes high-level usage statistics, such as whether monitoring is turned on."
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiTextColor>
|
||||
</EuiFlyoutHeader>
|
||||
<EuiFlyoutBody>{this.renderBody(this.state)}</EuiFlyoutBody>
|
||||
</EuiFlyout>
|
||||
</EuiPortal>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import { EuiLink } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { OptInExampleFlyout } from './opt_in_details_component';
|
||||
|
||||
interface Props {
|
||||
fetchTelemetry: () => Promise<any[]>;
|
||||
}
|
||||
|
||||
interface State {
|
||||
showDetails: boolean;
|
||||
showExample: boolean;
|
||||
}
|
||||
|
||||
export class OptInMessage extends React.PureComponent<Props, State> {
|
||||
public readonly state: State = {
|
||||
showDetails: false,
|
||||
showExample: false,
|
||||
};
|
||||
|
||||
toggleShowExample = () => {
|
||||
this.setState(prevState => ({
|
||||
showExample: !prevState.showExample,
|
||||
}));
|
||||
};
|
||||
|
||||
render() {
|
||||
const { fetchTelemetry } = this.props;
|
||||
const { showDetails, showExample } = this.state;
|
||||
|
||||
const getDetails = () => (
|
||||
<FormattedMessage
|
||||
id="kbn.home.telemetry.optInMessage.detailsDescription"
|
||||
defaultMessage="No information about the data you process or store will be sent. This feature will periodically send basic feature usage statistics. See an {exampleLink} or read our {telemetryPrivacyStatementLink}. You can disable this feature at any time."
|
||||
values={{
|
||||
exampleLink: (
|
||||
<EuiLink onClick={this.toggleShowExample}>
|
||||
<FormattedMessage
|
||||
id="kbn.home.telemetry.optInMessage.detailsExampleLinkText"
|
||||
defaultMessage="example"
|
||||
/>
|
||||
</EuiLink>
|
||||
),
|
||||
telemetryPrivacyStatementLink: (
|
||||
<EuiLink
|
||||
href="https://www.elastic.co/legal/telemetry-privacy-statement"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="kbn.home.telemetry.optInMessage.detailsTelemetryPrivacyStatementLinkText"
|
||||
defaultMessage="telemetry privacy statement"
|
||||
/>
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const getFlyoutDetails = () => (
|
||||
<OptInExampleFlyout
|
||||
onClose={() => this.setState({ showExample: false })}
|
||||
fetchTelemetry={fetchTelemetry}
|
||||
/>
|
||||
);
|
||||
|
||||
const getReadMore = () => (
|
||||
<EuiLink onClick={() => this.setState({ showDetails: true })}>
|
||||
<FormattedMessage
|
||||
id="kbn.home.telemetry.optInMessage.readMoreLinkText"
|
||||
defaultMessage="Read more"
|
||||
/>
|
||||
</EuiLink>
|
||||
);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<FormattedMessage
|
||||
id="kbn.home.telemetry.optInMessageDescription"
|
||||
defaultMessage="Help us improve the Elastic Stack by providing usage statistics for basic features. We will not share this data outside of Elastic."
|
||||
/>{' '}
|
||||
{!showDetails && getReadMore()}
|
||||
{showDetails && getDetails()}
|
||||
{showDetails && showExample && getFlyoutDetails()}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import {
|
||||
// @ts-ignore
|
||||
EuiCard,
|
||||
EuiButton,
|
||||
} from '@elastic/eui';
|
||||
import { OptInMessage } from './opt_in_message';
|
||||
|
||||
export interface Props {
|
||||
urlBasePath: string;
|
||||
onConfirm: () => void;
|
||||
onDecline: () => void;
|
||||
fetchTelemetry: () => Promise<any[]>;
|
||||
}
|
||||
|
||||
export function renderTelemetryOptInCard({
|
||||
urlBasePath,
|
||||
fetchTelemetry,
|
||||
onConfirm,
|
||||
onDecline,
|
||||
}: Props) {
|
||||
return (
|
||||
<EuiCard
|
||||
image={`${urlBasePath}/plugins/kibana/assets/illo_telemetry.png`}
|
||||
textAlign="left"
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="kbn.home.telemtery.optInCardTitle"
|
||||
defaultMessage="Help us improve the Elastic Stack"
|
||||
/>
|
||||
}
|
||||
description={<OptInMessage fetchTelemetry={fetchTelemetry} />}
|
||||
footer={
|
||||
<footer>
|
||||
<EuiButton
|
||||
onClick={onConfirm}
|
||||
className="homWelcome__footerAction"
|
||||
data-test-subj="WelcomeScreenOptInConfirm"
|
||||
fill
|
||||
>
|
||||
<FormattedMessage
|
||||
id="kbn.home.telemtery.optInCardConfirmButtonLabel"
|
||||
defaultMessage="Yes"
|
||||
/>
|
||||
</EuiButton>
|
||||
<EuiButton
|
||||
className="homWelcome__footerAction"
|
||||
onClick={onDecline}
|
||||
data-test-subj="WelcomeScreenOptInCancel"
|
||||
fill
|
||||
>
|
||||
<FormattedMessage
|
||||
id="kbn.home.telemtery.optInCardDeclineButtonLabel"
|
||||
defaultMessage="No"
|
||||
/>
|
||||
</EuiButton>
|
||||
</footer>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The UI and related logic for the welcome screen that *should* show only
|
||||
* when it is enabled (the default) and there is no Kibana-consumed data
|
||||
* in Elasticsearch.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
EuiCard,
|
||||
EuiTitle,
|
||||
EuiSpacer,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiText,
|
||||
EuiIcon,
|
||||
EuiButton,
|
||||
EuiButtonEmpty,
|
||||
EuiPortal,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
/**
|
||||
* Shows a full-screen welcome page that gives helpful quick links to beginners.
|
||||
*/
|
||||
export class Welcome extends React.Component {
|
||||
hideOnEsc = e => {
|
||||
if (e.key === 'Escape') {
|
||||
this.props.onSkip();
|
||||
}
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
document.addEventListener('keydown', this.hideOnEsc);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener('keydown', this.hideOnEsc);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { urlBasePath, onSkip } = this.props;
|
||||
|
||||
return (
|
||||
<EuiPortal>
|
||||
<div className="homWelcome">
|
||||
<header className="homWelcome__header">
|
||||
<div className="homWelcome__content eui-textCenter">
|
||||
<EuiSpacer size="xxl" />
|
||||
<span className="homWelcome__logo">
|
||||
<EuiIcon type="logoKibana" size="xxl" />
|
||||
</span>
|
||||
<EuiTitle size="l" className="homWelcome__title">
|
||||
<h1>
|
||||
<FormattedMessage id="kbn.home.welcomeTitle" defaultMessage="Welcome to Kibana"/>
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
<EuiText size="s" color="subdued" className="homWelcome__subtitle">
|
||||
<p>
|
||||
<FormattedMessage id="kbn.home.welcomeDescription" defaultMessage="Your window into the Elastic Stack"/>
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer size="xl" />
|
||||
</div>
|
||||
</header>
|
||||
<div className="homWelcome__content homWelcome-body">
|
||||
<EuiFlexGroup gutterSize="l">
|
||||
<EuiFlexItem>
|
||||
<EuiCard
|
||||
image={`${urlBasePath}/plugins/kibana/assets/illo_dashboard.png`}
|
||||
textAlign="left"
|
||||
title={<FormattedMessage id="kbn.home.letsStartTitle" defaultMessage="Let's get started"/>}
|
||||
description={
|
||||
<FormattedMessage
|
||||
id="kbn.home.letsStartDescription"
|
||||
defaultMessage="We noticed that you don't have any data in your cluster.
|
||||
You can try our sample data and dashboards or jump in with your own data."
|
||||
/>}
|
||||
footer={
|
||||
<footer>
|
||||
<EuiButton
|
||||
fill
|
||||
className="homWelcome__footerAction"
|
||||
href="#/home/tutorial_directory/sampleData"
|
||||
>
|
||||
<FormattedMessage id="kbn.home.tryButtonLabel" defaultMessage="Try our sample data"/>
|
||||
</EuiButton>
|
||||
<EuiButtonEmpty
|
||||
className="homWelcome__footerAction"
|
||||
onClick={onSkip}
|
||||
data-test-subj="skipWelcomeScreen"
|
||||
>
|
||||
<FormattedMessage id="kbn.home.exploreButtonLabel" defaultMessage="Explore on my own"/>
|
||||
</EuiButtonEmpty>
|
||||
</footer>
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</div>
|
||||
</div>
|
||||
</EuiPortal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Welcome.propTypes = {
|
||||
urlBasePath: PropTypes.string.isRequired,
|
||||
onSkip: PropTypes.func.isRequired,
|
||||
};
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The UI and related logic for the welcome screen that *should* show only
|
||||
* when it is enabled (the default) and there is no Kibana-consumed data
|
||||
* in Elasticsearch.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
EuiTitle,
|
||||
EuiSpacer,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiText,
|
||||
EuiIcon,
|
||||
EuiPortal,
|
||||
} from '@elastic/eui';
|
||||
// @ts-ignore
|
||||
import { banners } from 'ui/notify';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import chrome from 'ui/chrome';
|
||||
import { SampleDataCard } from './sample_data';
|
||||
import { TelemetryOptInCard } from './telemetry_opt_in';
|
||||
// @ts-ignore
|
||||
import { trackUiMetric, METRIC_TYPE } from '../kibana_services';
|
||||
|
||||
interface Props {
|
||||
urlBasePath: string;
|
||||
onSkip: () => {};
|
||||
fetchTelemetry: () => Promise<any[]>;
|
||||
setOptIn: (enabled: boolean) => Promise<boolean>;
|
||||
getTelemetryBannerId: () => string;
|
||||
shouldShowTelemetryOptIn: boolean;
|
||||
}
|
||||
interface State {
|
||||
step: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a full-screen welcome page that gives helpful quick links to beginners.
|
||||
*/
|
||||
export class Welcome extends React.PureComponent<Props, State> {
|
||||
public readonly state: State = {
|
||||
step: 0,
|
||||
};
|
||||
|
||||
private hideOnEsc = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') {
|
||||
this.props.onSkip();
|
||||
}
|
||||
};
|
||||
|
||||
private redirecToSampleData() {
|
||||
const path = chrome.addBasePath('#/home/tutorial_directory/sampleData');
|
||||
window.location.href = path;
|
||||
}
|
||||
private async handleTelemetrySelection(confirm: boolean) {
|
||||
const metricName = `telemetryOptIn${confirm ? 'Confirm' : 'Decline'}`;
|
||||
trackUiMetric(METRIC_TYPE.CLICK, metricName);
|
||||
await this.props.setOptIn(confirm);
|
||||
const bannerId = this.props.getTelemetryBannerId();
|
||||
banners.remove(bannerId);
|
||||
this.setState(() => ({ step: 1 }));
|
||||
}
|
||||
|
||||
private onSampleDataDecline = () => {
|
||||
trackUiMetric(METRIC_TYPE.CLICK, 'sampleDataDecline');
|
||||
this.props.onSkip();
|
||||
};
|
||||
private onSampleDataConfirm = () => {
|
||||
trackUiMetric(METRIC_TYPE.CLICK, 'sampleDataConfirm');
|
||||
this.redirecToSampleData();
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
trackUiMetric(METRIC_TYPE.LOADED, 'welcomeScreenMount');
|
||||
if (this.props.shouldShowTelemetryOptIn) {
|
||||
trackUiMetric(METRIC_TYPE.COUNT, 'welcomeScreenWithTelemetryOptIn');
|
||||
}
|
||||
document.addEventListener('keydown', this.hideOnEsc);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener('keydown', this.hideOnEsc);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { urlBasePath, shouldShowTelemetryOptIn, fetchTelemetry } = this.props;
|
||||
const { step } = this.state;
|
||||
|
||||
return (
|
||||
<EuiPortal>
|
||||
<div className="homWelcome">
|
||||
<header className="homWelcome__header">
|
||||
<div className="homWelcome__content eui-textCenter">
|
||||
<EuiSpacer size="xl" />
|
||||
<span className="homWelcome__logo">
|
||||
<EuiIcon type="logoKibana" size="xxl" />
|
||||
</span>
|
||||
<EuiTitle size="l" className="homWelcome__title">
|
||||
<h1>
|
||||
<FormattedMessage id="kbn.home.welcomeTitle" defaultMessage="Welcome to Kibana" />
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
<EuiText size="s" color="subdued" className="homWelcome__subtitle">
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="kbn.home.welcomeDescription"
|
||||
defaultMessage="Your window into the Elastic Stack"
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer size="m" />
|
||||
</div>
|
||||
</header>
|
||||
<div className="homWelcome__content homWelcome-body">
|
||||
<EuiFlexGroup gutterSize="l">
|
||||
<EuiFlexItem>
|
||||
{shouldShowTelemetryOptIn && step === 0 && (
|
||||
<TelemetryOptInCard
|
||||
urlBasePath={urlBasePath}
|
||||
fetchTelemetry={fetchTelemetry}
|
||||
onConfirm={this.handleTelemetrySelection.bind(this, true)}
|
||||
onDecline={this.handleTelemetrySelection.bind(this, false)}
|
||||
/>
|
||||
)}
|
||||
{(!shouldShowTelemetryOptIn || step === 1) && (
|
||||
<SampleDataCard
|
||||
urlBasePath={urlBasePath}
|
||||
onConfirm={this.onSampleDataConfirm}
|
||||
onDecline={this.onSampleDataDecline}
|
||||
/>
|
||||
)}
|
||||
<EuiSpacer size="xs" />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</div>
|
||||
</div>
|
||||
</EuiPortal>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -18,9 +18,23 @@
|
|||
*/
|
||||
|
||||
import { uiModules } from 'ui/modules';
|
||||
import { npStart } from 'ui/new_platform';
|
||||
import { createUiStatsReporter, METRIC_TYPE } from '../../../ui_metric/public';
|
||||
import { TelemetryOptInProvider } from './telemetry_opt_in';
|
||||
|
||||
export let indexPatternService;
|
||||
export let shouldShowTelemetryOptIn;
|
||||
export let telemetryOptInProvider;
|
||||
|
||||
export const trackUiMetric = createUiStatsReporter('Kibana_home');
|
||||
export { METRIC_TYPE };
|
||||
|
||||
uiModules.get('kibana').run(($injector) => {
|
||||
const telemetryEnabled = npStart.core.injectedMetadata.getInjectedVar('telemetryEnabled');
|
||||
const telemetryBanner = npStart.core.injectedMetadata.getInjectedVar('telemetryBanner');
|
||||
const Private = $injector.get('Private');
|
||||
|
||||
telemetryOptInProvider = Private(TelemetryOptInProvider);
|
||||
shouldShowTelemetryOptIn = telemetryEnabled && telemetryBanner && !telemetryOptInProvider.getOptIn();
|
||||
indexPatternService = $injector.get('indexPatterns');
|
||||
});
|
||||
|
|
|
@ -1,20 +1,37 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import moment from 'moment';
|
||||
import { setCanTrackUiMetrics } from 'ui/ui_metric';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
import { npStart } from 'ui/new_platform';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export function TelemetryOptInProvider($injector, chrome) {
|
||||
let currentOptInStatus = $injector.get('telemetryOptedIn');
|
||||
setCanTrackUiMetrics(currentOptInStatus);
|
||||
let currentOptInStatus = npStart.core.injectedMetadata.getInjectedVar('telemetryOptedIn');
|
||||
let bannerId = null;
|
||||
|
||||
setCanTrackUiMetrics(currentOptInStatus);
|
||||
const provider = {
|
||||
getBannerId: () => bannerId,
|
||||
getOptIn: () => currentOptInStatus,
|
||||
setBannerId(id) { bannerId = id; },
|
||||
setOptIn: async (enabled) => {
|
||||
setCanTrackUiMetrics(enabled);
|
||||
const $http = $injector.get('$http');
|
||||
|
@ -24,10 +41,10 @@ export function TelemetryOptInProvider($injector, chrome) {
|
|||
currentOptInStatus = enabled;
|
||||
} catch (error) {
|
||||
toastNotifications.addError(error, {
|
||||
title: i18n.translate('xpack.telemetry.optInErrorToastTitle', {
|
||||
title: i18n.translate('kbn.home.telemetry.optInErrorToastTitle', {
|
||||
defaultMessage: 'Error',
|
||||
}),
|
||||
toastMessage: i18n.translate('xpack.telemetry.optInErrorToastText', {
|
||||
toastMessage: i18n.translate('kbn.home.telemetry.optInErrorToastText', {
|
||||
defaultMessage: 'An error occured while trying to set the usage statistics preference.',
|
||||
}),
|
||||
});
|
|
@ -55,13 +55,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
@mixin kibanaFullScreenGraphics() {
|
||||
@mixin kibanaFullScreenGraphics($euiZLevel: $euiZLevel9) {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: $euiZLevel9 + 1000;
|
||||
z-index: $euiZLevel + 1000;
|
||||
background: inherit;
|
||||
background-image: linear-gradient(0deg, $euiColorLightestShade 0%, $euiColorEmptyShade 100%);
|
||||
opacity: 0;
|
||||
|
|
|
@ -104,277 +104,7 @@ exports[`TelemetryOptIn should display when telemetry not opted in 1`] = `
|
|||
"timeZone": null,
|
||||
}
|
||||
}
|
||||
>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
>
|
||||
<div
|
||||
className="euiSpacer euiSpacer--s"
|
||||
/>
|
||||
</EuiSpacer>
|
||||
<EuiTitle
|
||||
size="s"
|
||||
>
|
||||
<h4
|
||||
className="euiTitle euiTitle--small"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Help Elastic support provide better service"
|
||||
id="xpack.licenseMgmt.telemetryOptIn.customersHelpSupportDescription"
|
||||
values={Object {}}
|
||||
>
|
||||
Help Elastic support provide better service
|
||||
</FormattedMessage>
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
>
|
||||
<div
|
||||
className="euiSpacer euiSpacer--s"
|
||||
/>
|
||||
</EuiSpacer>
|
||||
<EuiCheckbox
|
||||
checked={false}
|
||||
compressed={false}
|
||||
disabled={false}
|
||||
id="isOptingInToTelemetry"
|
||||
indeterminate={false}
|
||||
label={
|
||||
<span>
|
||||
<FormattedMessage
|
||||
defaultMessage="Send basic feature usage statistics to Elastic periodically. {popover}"
|
||||
id="xpack.licenseMgmt.telemetryOptIn.sendBasicFeatureStatisticsLabel"
|
||||
values={
|
||||
Object {
|
||||
"popover": <EuiPopover
|
||||
anchorPosition="downCenter"
|
||||
button={
|
||||
<EuiLink
|
||||
color="primary"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Read more"
|
||||
id="xpack.licenseMgmt.telemetryOptIn.readMoreLinkText"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiLink>
|
||||
}
|
||||
className="eui-AlignBaseline"
|
||||
closePopover={[Function]}
|
||||
display="inlineBlock"
|
||||
hasArrow={true}
|
||||
id="readMorePopover"
|
||||
isOpen={false}
|
||||
ownFocus={true}
|
||||
panelPaddingSize="m"
|
||||
>
|
||||
<EuiText
|
||||
className="licManagement__narrowText"
|
||||
>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="This feature periodically sends basic feature usage statistics. This information will not be shared outside of Elastic. See an {exampleLink} or read our {telemetryPrivacyStatementLink}. You can disable this feature any time."
|
||||
id="xpack.licenseMgmt.telemetryOptIn.featureUsageWarningMessage"
|
||||
values={
|
||||
Object {
|
||||
"exampleLink": <EuiLink
|
||||
color="primary"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="example"
|
||||
id="xpack.licenseMgmt.telemetryOptIn.exampleLinkText"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiLink>,
|
||||
"telemetryPrivacyStatementLink": <EuiLink
|
||||
color="primary"
|
||||
href="https://www.elastic.co/legal/telemetry-privacy-statement"
|
||||
target="_blank"
|
||||
type="button"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="telemetry privacy statement"
|
||||
id="xpack.licenseMgmt.telemetryOptIn.telemetryPrivacyStatementLinkText"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiLink>,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
</EuiPopover>,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
onChange={[Function]}
|
||||
>
|
||||
<div
|
||||
className="euiCheckbox"
|
||||
>
|
||||
<input
|
||||
checked={false}
|
||||
className="euiCheckbox__input"
|
||||
disabled={false}
|
||||
id="isOptingInToTelemetry"
|
||||
onChange={[Function]}
|
||||
type="checkbox"
|
||||
/>
|
||||
<div
|
||||
className="euiCheckbox__square"
|
||||
/>
|
||||
<label
|
||||
className="euiCheckbox__label"
|
||||
htmlFor="isOptingInToTelemetry"
|
||||
>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
defaultMessage="Send basic feature usage statistics to Elastic periodically. {popover}"
|
||||
id="xpack.licenseMgmt.telemetryOptIn.sendBasicFeatureStatisticsLabel"
|
||||
values={
|
||||
Object {
|
||||
"popover": <EuiPopover
|
||||
anchorPosition="downCenter"
|
||||
button={
|
||||
<EuiLink
|
||||
color="primary"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Read more"
|
||||
id="xpack.licenseMgmt.telemetryOptIn.readMoreLinkText"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiLink>
|
||||
}
|
||||
className="eui-AlignBaseline"
|
||||
closePopover={[Function]}
|
||||
display="inlineBlock"
|
||||
hasArrow={true}
|
||||
id="readMorePopover"
|
||||
isOpen={false}
|
||||
ownFocus={true}
|
||||
panelPaddingSize="m"
|
||||
>
|
||||
<EuiText
|
||||
className="licManagement__narrowText"
|
||||
>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="This feature periodically sends basic feature usage statistics. This information will not be shared outside of Elastic. See an {exampleLink} or read our {telemetryPrivacyStatementLink}. You can disable this feature any time."
|
||||
id="xpack.licenseMgmt.telemetryOptIn.featureUsageWarningMessage"
|
||||
values={
|
||||
Object {
|
||||
"exampleLink": <EuiLink
|
||||
color="primary"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="example"
|
||||
id="xpack.licenseMgmt.telemetryOptIn.exampleLinkText"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiLink>,
|
||||
"telemetryPrivacyStatementLink": <EuiLink
|
||||
color="primary"
|
||||
href="https://www.elastic.co/legal/telemetry-privacy-statement"
|
||||
target="_blank"
|
||||
type="button"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="telemetry privacy statement"
|
||||
id="xpack.licenseMgmt.telemetryOptIn.telemetryPrivacyStatementLinkText"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiLink>,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
</EuiPopover>,
|
||||
}
|
||||
}
|
||||
>
|
||||
Send basic feature usage statistics to Elastic periodically.
|
||||
<EuiPopover
|
||||
anchorPosition="downCenter"
|
||||
button={
|
||||
<EuiLink
|
||||
color="primary"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Read more"
|
||||
id="xpack.licenseMgmt.telemetryOptIn.readMoreLinkText"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiLink>
|
||||
}
|
||||
className="eui-AlignBaseline"
|
||||
closePopover={[Function]}
|
||||
display="inlineBlock"
|
||||
hasArrow={true}
|
||||
id="readMorePopover"
|
||||
isOpen={false}
|
||||
ownFocus={true}
|
||||
panelPaddingSize="m"
|
||||
>
|
||||
<EuiOutsideClickDetector
|
||||
isDisabled={true}
|
||||
onOutsideClick={[Function]}
|
||||
>
|
||||
<div
|
||||
className="euiPopover euiPopover--anchorDownCenter eui-AlignBaseline"
|
||||
id="readMorePopover"
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onMouseUp={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
>
|
||||
<div
|
||||
className="euiPopover__anchor"
|
||||
>
|
||||
<EuiLink
|
||||
color="primary"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<button
|
||||
className="euiLink euiLink--primary"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Read more"
|
||||
id="xpack.licenseMgmt.telemetryOptIn.readMoreLinkText"
|
||||
values={Object {}}
|
||||
>
|
||||
Read more
|
||||
</FormattedMessage>
|
||||
</button>
|
||||
</EuiLink>
|
||||
</div>
|
||||
</div>
|
||||
</EuiOutsideClickDetector>
|
||||
</EuiPopover>
|
||||
</FormattedMessage>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</EuiCheckbox>
|
||||
</TelemetryOptIn>
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`TelemetryOptIn should not display when telemetry is opted in 1`] = `
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
EuiTitle,
|
||||
EuiPopover
|
||||
} from '@elastic/eui';
|
||||
import { showTelemetryOptIn, getTelemetryFetcher, PRIVACY_STATEMENT_URL, OptInExampleFlyout } from '../../lib/telemetry';
|
||||
import { shouldShowTelemetryOptIn, getTelemetryFetcher, PRIVACY_STATEMENT_URL, OptInExampleFlyout } from '../../lib/telemetry';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
export class TelemetryOptIn extends React.Component {
|
||||
|
@ -127,7 +127,7 @@ export class TelemetryOptIn extends React.Component {
|
|||
</EuiPopover>
|
||||
);
|
||||
|
||||
return showTelemetryOptIn() ? (
|
||||
return shouldShowTelemetryOptIn() ? (
|
||||
<Fragment>
|
||||
{example}
|
||||
{toCurrentCustomers}
|
||||
|
|
|
@ -24,9 +24,9 @@ export const setTelemetryOptInService = (aTelemetryOptInService) => {
|
|||
export const optInToTelemetry = async (enableTelemetry) => {
|
||||
await telemetryOptInService.setOptIn(enableTelemetry);
|
||||
};
|
||||
export const showTelemetryOptIn = () => {
|
||||
export const shouldShowTelemetryOptIn = () => {
|
||||
return telemetryEnabled && !telemetryOptInService.getOptIn();
|
||||
};
|
||||
export const getTelemetryFetcher = () => {
|
||||
return fetchTelemetry(httpClient);
|
||||
return fetchTelemetry(httpClient, { unencrypted: true });
|
||||
};
|
||||
|
|
|
@ -4,5 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
// @ts-ignore
|
||||
export { TelemetryForm } from './telemetry_form';
|
||||
export { OptInExampleFlyout } from './opt_in_details_component';
|
||||
export { OptInBanner } from './opt_in_banner_component';
|
||||
export { OptInMessage } from './opt_in_message';
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
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';
|
||||
|
||||
interface Props {
|
||||
fetchTelemetry: () => Promise<any[]>;
|
||||
optInClick: (optIn: boolean) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* React component for displaying the Telemetry opt-in banner.
|
||||
*/
|
||||
export class OptInBanner extends React.PureComponent<Props> {
|
||||
render() {
|
||||
const title = (
|
||||
<FormattedMessage
|
||||
id="xpack.telemetry.welcomeBanner.title"
|
||||
defaultMessage="Help us improve the Elastic Stack!"
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<EuiCallOut iconType="questionInCircle" title={title}>
|
||||
<OptInMessage fetchTelemetry={this.props.fetchTelemetry} />
|
||||
<EuiSpacer size="s" />
|
||||
<EuiFlexGroup gutterSize="s" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton size="s" onClick={() => this.props.optInClick(true)}>
|
||||
<FormattedMessage
|
||||
id="xpack.telemetry.welcomeBanner.yesButtonLabel"
|
||||
defaultMessage="Yes"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton size="s" onClick={() => this.props.optInClick(false)}>
|
||||
<FormattedMessage
|
||||
id="xpack.telemetry.welcomeBanner.noButtonLabel"
|
||||
defaultMessage="No"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiCallOut>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -9,8 +9,13 @@ import { OptInExampleFlyout } from './opt_in_details_component';
|
|||
|
||||
describe('OptInDetailsComponent', () => {
|
||||
it('renders as expected', () => {
|
||||
expect(shallowWithIntl(
|
||||
<OptInExampleFlyout fetchTelemetry={jest.fn(async () => ({ data: [] }))} onClose={jest.fn()} />)
|
||||
expect(
|
||||
shallowWithIntl(
|
||||
<OptInExampleFlyout
|
||||
fetchTelemetry={jest.fn(async () => ({ data: [] }))}
|
||||
onClose={jest.fn()}
|
||||
/>
|
||||
)
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -4,8 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import * as React from 'react';
|
||||
|
||||
import {
|
||||
EuiCallOut,
|
||||
|
@ -24,39 +23,37 @@ import {
|
|||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
interface Props {
|
||||
fetchTelemetry: () => Promise<any>;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
interface State {
|
||||
isLoading: boolean;
|
||||
hasPrivilegeToRead: boolean;
|
||||
data: any[] | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* React component for displaying the example data associated with the Telemetry opt-in banner.
|
||||
*/
|
||||
export class OptInExampleFlyout extends Component {
|
||||
|
||||
static propTypes = {
|
||||
/**
|
||||
* Callback function with no parameters that returns a {@code Promise} containing the
|
||||
* telemetry data (expected to be an array).
|
||||
*/
|
||||
fetchTelemetry: PropTypes.func.isRequired,
|
||||
/**
|
||||
* Callback function with no parameters that closes this flyout.
|
||||
*/
|
||||
onClose: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
data: null,
|
||||
isLoading: true,
|
||||
hasPrivilegeToRead: false,
|
||||
};
|
||||
}
|
||||
export class OptInExampleFlyout extends React.PureComponent<Props, State> {
|
||||
public readonly state: State = {
|
||||
data: null,
|
||||
isLoading: true,
|
||||
hasPrivilegeToRead: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.props.fetchTelemetry()
|
||||
.then(response => this.setState({
|
||||
data: Array.isArray(response.data) ? response.data : null,
|
||||
isLoading: false,
|
||||
hasPrivilegeToRead: true,
|
||||
}))
|
||||
this.props
|
||||
.fetchTelemetry()
|
||||
.then(response =>
|
||||
this.setState({
|
||||
data: Array.isArray(response.data) ? response.data : null,
|
||||
isLoading: false,
|
||||
hasPrivilegeToRead: true,
|
||||
})
|
||||
)
|
||||
.catch(err => {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
|
@ -65,7 +62,7 @@ export class OptInExampleFlyout extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
renderBody({ data, isLoading, hasPrivilegeToRead }) {
|
||||
renderBody({ data, isLoading, hasPrivilegeToRead }: State) {
|
||||
if (isLoading) {
|
||||
return (
|
||||
<EuiFlexGroup justifyContent="spaceAround">
|
||||
|
@ -79,10 +76,12 @@ export class OptInExampleFlyout extends Component {
|
|||
if (!hasPrivilegeToRead) {
|
||||
return (
|
||||
<EuiCallOut
|
||||
title={<FormattedMessage
|
||||
id="xpack.telemetry.callout.errorUnprivilegedUserTitle"
|
||||
defaultMessage="Error displaying cluster statistics"
|
||||
/>}
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.telemetry.callout.errorUnprivilegedUserTitle"
|
||||
defaultMessage="Error displaying cluster statistics"
|
||||
/>
|
||||
}
|
||||
color="danger"
|
||||
iconType="cross"
|
||||
>
|
||||
|
@ -97,10 +96,12 @@ export class OptInExampleFlyout extends Component {
|
|||
if (data === null) {
|
||||
return (
|
||||
<EuiCallOut
|
||||
title={<FormattedMessage
|
||||
id="xpack.telemetry.callout.errorLoadingClusterStatisticsTitle"
|
||||
defaultMessage="Error loading cluster statistics"
|
||||
/>}
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.telemetry.callout.errorLoadingClusterStatisticsTitle"
|
||||
defaultMessage="Error loading cluster statistics"
|
||||
/>
|
||||
}
|
||||
color="danger"
|
||||
iconType="cross"
|
||||
>
|
||||
|
@ -114,21 +115,13 @@ export class OptInExampleFlyout extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiCodeBlock language="js">
|
||||
{JSON.stringify(data, null, 2)}
|
||||
</EuiCodeBlock>
|
||||
);
|
||||
return <EuiCodeBlock language="js">{JSON.stringify(data, null, 2)}</EuiCodeBlock>;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<EuiPortal>
|
||||
<EuiFlyout
|
||||
ownFocus
|
||||
onClose={this.props.onClose}
|
||||
maxWidth={true}
|
||||
>
|
||||
<EuiFlyout ownFocus onClose={this.props.onClose} maxWidth={true}>
|
||||
<EuiFlyoutHeader>
|
||||
<EuiTitle>
|
||||
<h2>
|
||||
|
@ -149,12 +142,9 @@ export class OptInExampleFlyout extends Component {
|
|||
</EuiText>
|
||||
</EuiTextColor>
|
||||
</EuiFlyoutHeader>
|
||||
<EuiFlyoutBody>
|
||||
{this.renderBody(this.state)}
|
||||
</EuiFlyoutBody>
|
||||
<EuiFlyoutBody>{this.renderBody(this.state)}</EuiFlyoutBody>
|
||||
</EuiFlyout>
|
||||
</EuiPortal>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import { EuiLink, EuiText } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { getConfigTelemetryDesc, PRIVACY_STATEMENT_URL } from '../../common/constants';
|
||||
import { OptInExampleFlyout } from './opt_in_details_component';
|
||||
|
||||
interface Props {
|
||||
fetchTelemetry: () => Promise<any[]>;
|
||||
}
|
||||
|
||||
interface State {
|
||||
showDetails: boolean;
|
||||
showExample: boolean;
|
||||
}
|
||||
|
||||
export class OptInMessage extends React.PureComponent<Props, State> {
|
||||
public readonly state: State = {
|
||||
showDetails: false,
|
||||
showExample: false,
|
||||
};
|
||||
|
||||
toggleShowExample = () => {
|
||||
this.setState(prevState => ({
|
||||
showExample: !prevState.showExample,
|
||||
}));
|
||||
};
|
||||
|
||||
render() {
|
||||
const { showDetails, showExample } = this.state;
|
||||
|
||||
const getDetails = () => (
|
||||
<EuiText size="s">
|
||||
<p tab-index="0">
|
||||
<FormattedMessage
|
||||
id="xpack.telemetry.welcomeBanner.telemetryConfigDetailsDescription"
|
||||
defaultMessage="No information about the data you process or store will be sent. This feature
|
||||
will periodically send basic feature usage statistics. See an {exampleLink} or read our {telemetryPrivacyStatementLink}.
|
||||
You can disable this feature at any time."
|
||||
values={{
|
||||
exampleLink: (
|
||||
<EuiLink onClick={this.toggleShowExample}>
|
||||
<FormattedMessage
|
||||
id="xpack.telemetry.welcomeBanner.telemetryConfigDetailsDescription.exampleLinkText"
|
||||
defaultMessage="example"
|
||||
/>
|
||||
</EuiLink>
|
||||
),
|
||||
telemetryPrivacyStatementLink: (
|
||||
<EuiLink href={PRIVACY_STATEMENT_URL} target="_blank">
|
||||
<FormattedMessage
|
||||
id="xpack.telemetry.welcomeBanner.telemetryConfigDetailsDescription.telemetryPrivacyStatementLinkText"
|
||||
defaultMessage="telemetry privacy statement"
|
||||
/>
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
);
|
||||
|
||||
const getFlyoutDetails = () => (
|
||||
<OptInExampleFlyout
|
||||
onClose={() => this.setState({ showExample: false })}
|
||||
fetchTelemetry={this.props.fetchTelemetry}
|
||||
/>
|
||||
);
|
||||
|
||||
const getReadMore = () => (
|
||||
<EuiLink onClick={() => this.setState({ showDetails: true })}>
|
||||
<FormattedMessage
|
||||
id="xpack.telemetry.welcomeBanner.telemetryConfigDescription.readMoreLinkText"
|
||||
defaultMessage="Read more"
|
||||
/>
|
||||
</EuiLink>
|
||||
);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<EuiText>
|
||||
<p tab-index="0">
|
||||
{getConfigTelemetryDesc()} {!showDetails && getReadMore()}
|
||||
</p>
|
||||
</EuiText>
|
||||
{showDetails && getDetails()}
|
||||
{showDetails && showExample && getFlyoutDetails()}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import '../services/telemetry_opt_in.test.mocks';
|
||||
import React from 'react';
|
||||
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import { TelemetryForm } from './telemetry_form';
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import { renderBanner } from '../render_banner';
|
||||
|
||||
describe('render_banner', () => {
|
||||
|
||||
it('adds a banner to banners with priority of 10000', () => {
|
||||
const config = { };
|
||||
const banners = {
|
||||
add: sinon.stub()
|
||||
};
|
||||
const fetchTelemetry = sinon.stub();
|
||||
banners.add.returns('brucer-banner');
|
||||
|
||||
renderBanner(config, fetchTelemetry, { _banners: banners });
|
||||
|
||||
expect(banners.add.calledOnce).to.be(true);
|
||||
expect(fetchTelemetry.called).to.be(false);
|
||||
|
||||
const bannerConfig = banners.add.getCall(0).args[0];
|
||||
|
||||
expect(bannerConfig.component).not.to.be(undefined);
|
||||
expect(bannerConfig.priority).to.be(10000);
|
||||
});
|
||||
|
||||
});
|
|
@ -16,18 +16,16 @@ import { FormattedMessage } from '@kbn/i18n/react';
|
|||
/**
|
||||
* Handle clicks from the user on the opt-in banner.
|
||||
*
|
||||
* @param {String} bannerId Banner ID to close upon success.
|
||||
* @param {Object} telemetryOptInProvider the telemetry opt-in provider
|
||||
* @param {Boolean} optIn {@code true} to opt into telemetry.
|
||||
* @param {Object} _banners Singleton banners. Can be overridden for tests.
|
||||
* @param {Object} _toastNotifications Singleton toast notifications. Can be overridden for tests.
|
||||
*/
|
||||
export async function clickBanner(
|
||||
bannerId,
|
||||
telemetryOptInProvider,
|
||||
optIn,
|
||||
{ _banners = banners, _toastNotifications = toastNotifications } = {}) {
|
||||
|
||||
const bannerId = telemetryOptInProvider.getBannerId();
|
||||
let set = false;
|
||||
|
||||
try {
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { mockInjectedMetadata } from '../../services/telemetry_opt_in.test.mocks';
|
||||
|
||||
import sinon from 'sinon';
|
||||
import { uiModules } from 'ui/modules';
|
||||
|
||||
|
@ -13,16 +14,12 @@ uiModules.get('kibana')
|
|||
// MockInjector used in these tests is not impacted
|
||||
.constant('telemetryOptedIn', null);
|
||||
|
||||
import {
|
||||
clickBanner,
|
||||
} from '../click_banner';
|
||||
import { TelemetryOptInProvider } from '../../../services/telemetry_opt_in';
|
||||
import { clickBanner } from './click_banner';
|
||||
import { TelemetryOptInProvider } from '../../services/telemetry_opt_in';
|
||||
|
||||
const getMockInjector = ({ simulateFailure }) => {
|
||||
const get = sinon.stub();
|
||||
|
||||
get.withArgs('telemetryOptedIn').returns(null);
|
||||
|
||||
const mockHttp = {
|
||||
post: sinon.stub()
|
||||
};
|
||||
|
@ -60,16 +57,18 @@ describe('click_banner', () => {
|
|||
remove: sinon.spy()
|
||||
};
|
||||
|
||||
const optIn = true;
|
||||
const bannerId = 'bruce-banner';
|
||||
mockInjectedMetadata({ telemetryOptedIn: optIn });
|
||||
const telemetryOptInProvider = getTelemetryOptInProvider();
|
||||
|
||||
const bannerId = 'bruce-banner';
|
||||
const optIn = true;
|
||||
telemetryOptInProvider.setBannerId(bannerId);
|
||||
|
||||
await clickBanner(bannerId, telemetryOptInProvider, optIn, { _banners: banners });
|
||||
await clickBanner(telemetryOptInProvider, optIn, { _banners: banners });
|
||||
|
||||
expect(telemetryOptInProvider.getOptIn()).to.be(optIn);
|
||||
expect(banners.remove.calledOnce).to.be(true);
|
||||
expect(banners.remove.calledWith(bannerId)).to.be(true);
|
||||
expect(telemetryOptInProvider.getOptIn()).toBe(optIn);
|
||||
expect(banners.remove.calledOnce).toBe(true);
|
||||
expect(banners.remove.calledWith(bannerId)).toBe(true);
|
||||
});
|
||||
|
||||
it('sets setting unsuccessfully, adds toast, and does not touch banner', async () => {
|
||||
|
@ -79,15 +78,15 @@ describe('click_banner', () => {
|
|||
const banners = {
|
||||
remove: sinon.spy()
|
||||
};
|
||||
const telemetryOptInProvider = getTelemetryOptInProvider({ simulateFailure: true });
|
||||
const bannerId = 'bruce-banner';
|
||||
const optIn = true;
|
||||
mockInjectedMetadata({ telemetryOptedIn: null });
|
||||
const telemetryOptInProvider = getTelemetryOptInProvider({ simulateFailure: true });
|
||||
|
||||
await clickBanner(bannerId, telemetryOptInProvider, optIn, { _banners: banners, _toastNotifications: toastNotifications });
|
||||
await clickBanner(telemetryOptInProvider, optIn, { _banners: banners, _toastNotifications: toastNotifications });
|
||||
|
||||
expect(telemetryOptInProvider.getOptIn()).to.be(null);
|
||||
expect(toastNotifications.addDanger.calledOnce).to.be(true);
|
||||
expect(banners.remove.notCalled).to.be(true);
|
||||
expect(telemetryOptInProvider.getOptIn()).toBe(null);
|
||||
expect(toastNotifications.addDanger.calledOnce).toBe(true);
|
||||
expect(banners.remove.notCalled).toBe(true);
|
||||
});
|
||||
|
||||
it('sets setting unsuccessfully with error, adds toast, and does not touch banner', async () => {
|
||||
|
@ -97,15 +96,15 @@ describe('click_banner', () => {
|
|||
const banners = {
|
||||
remove: sinon.spy()
|
||||
};
|
||||
const telemetryOptInProvider = getTelemetryOptInProvider({ simulateError: true });
|
||||
const bannerId = 'bruce-banner';
|
||||
const optIn = false;
|
||||
mockInjectedMetadata({ telemetryOptedIn: null });
|
||||
const telemetryOptInProvider = getTelemetryOptInProvider({ simulateError: true });
|
||||
|
||||
await clickBanner(bannerId, telemetryOptInProvider, optIn, { _banners: banners, _toastNotifications: toastNotifications });
|
||||
await clickBanner(telemetryOptInProvider, optIn, { _banners: banners, _toastNotifications: toastNotifications });
|
||||
|
||||
expect(telemetryOptInProvider.getOptIn()).to.be(null);
|
||||
expect(toastNotifications.addDanger.calledOnce).to.be(true);
|
||||
expect(banners.remove.notCalled).to.be(true);
|
||||
expect(telemetryOptInProvider.getOptIn()).toBe(null);
|
||||
expect(toastNotifications.addDanger.calledOnce).toBe(true);
|
||||
expect(banners.remove.notCalled).toBe(true);
|
||||
});
|
||||
|
||||
});
|
|
@ -4,12 +4,13 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { mockInjectedMetadata } from '../../services/telemetry_opt_in.test.mocks';
|
||||
|
||||
import sinon from 'sinon';
|
||||
|
||||
import { CONFIG_TELEMETRY } from '../../../../common/constants';
|
||||
import { handleOldSettings } from '../handle_old_settings';
|
||||
import { TelemetryOptInProvider } from '../../../services/telemetry_opt_in';
|
||||
import { CONFIG_TELEMETRY } from '../../../common/constants';
|
||||
import { handleOldSettings } from './handle_old_settings';
|
||||
import { TelemetryOptInProvider } from '../../services/telemetry_opt_in';
|
||||
|
||||
const getTelemetryOptInProvider = (enabled, { simulateFailure = false } = {}) => {
|
||||
const $http = {
|
||||
|
@ -24,15 +25,13 @@ const getTelemetryOptInProvider = (enabled, { simulateFailure = false } = {}) =>
|
|||
const chrome = {
|
||||
addBasePath: url => url
|
||||
};
|
||||
mockInjectedMetadata({ telemetryOptedIn: enabled });
|
||||
|
||||
const $injector = {
|
||||
get: (key) => {
|
||||
if (key === '$http') {
|
||||
return $http;
|
||||
}
|
||||
if (key === 'telemetryOptedIn') {
|
||||
return enabled;
|
||||
}
|
||||
throw new Error(`unexpected mock injector usage for ${key}`);
|
||||
}
|
||||
};
|
||||
|
@ -50,22 +49,22 @@ describe('handle_old_settings', () => {
|
|||
};
|
||||
|
||||
const telemetryOptInProvider = getTelemetryOptInProvider(null);
|
||||
expect(telemetryOptInProvider.getOptIn()).to.be(null);
|
||||
expect(telemetryOptInProvider.getOptIn()).toBe(null);
|
||||
|
||||
config.get.withArgs('xPackMonitoring:allowReport', null).returns(true);
|
||||
config.set.withArgs(CONFIG_TELEMETRY, true).returns(Promise.resolve(true));
|
||||
|
||||
expect(await handleOldSettings(config, telemetryOptInProvider)).to.be(false);
|
||||
expect(await handleOldSettings(config, telemetryOptInProvider)).toBe(false);
|
||||
|
||||
expect(config.get.calledTwice).to.be(true);
|
||||
expect(config.set.called).to.be(false);
|
||||
expect(config.get.calledTwice).toBe(true);
|
||||
expect(config.set.called).toBe(false);
|
||||
|
||||
expect(config.remove.calledThrice).to.be(true);
|
||||
expect(config.remove.getCall(0).args[0]).to.be('xPackMonitoring:allowReport');
|
||||
expect(config.remove.getCall(1).args[0]).to.be('xPackMonitoring:showBanner');
|
||||
expect(config.remove.getCall(2).args[0]).to.be(CONFIG_TELEMETRY);
|
||||
expect(config.remove.calledThrice).toBe(true);
|
||||
expect(config.remove.getCall(0).args[0]).toBe('xPackMonitoring:allowReport');
|
||||
expect(config.remove.getCall(1).args[0]).toBe('xPackMonitoring:showBanner');
|
||||
expect(config.remove.getCall(2).args[0]).toBe(CONFIG_TELEMETRY);
|
||||
|
||||
expect(telemetryOptInProvider.getOptIn()).to.be(true);
|
||||
expect(telemetryOptInProvider.getOptIn()).toBe(true);
|
||||
});
|
||||
|
||||
it('re-uses old "telemetry:optIn" setting and stays opted in', async () => {
|
||||
|
@ -76,22 +75,22 @@ describe('handle_old_settings', () => {
|
|||
};
|
||||
|
||||
const telemetryOptInProvider = getTelemetryOptInProvider(null);
|
||||
expect(telemetryOptInProvider.getOptIn()).to.be(null);
|
||||
expect(telemetryOptInProvider.getOptIn()).toBe(null);
|
||||
|
||||
config.get.withArgs('xPackMonitoring:allowReport', null).returns(false);
|
||||
config.get.withArgs(CONFIG_TELEMETRY, null).returns(true);
|
||||
|
||||
expect(await handleOldSettings(config, telemetryOptInProvider)).to.be(false);
|
||||
expect(await handleOldSettings(config, telemetryOptInProvider)).toBe(false);
|
||||
|
||||
expect(config.get.calledTwice).to.be(true);
|
||||
expect(config.set.called).to.be(false);
|
||||
expect(config.get.calledTwice).toBe(true);
|
||||
expect(config.set.called).toBe(false);
|
||||
|
||||
expect(config.remove.calledThrice).to.be(true);
|
||||
expect(config.remove.getCall(0).args[0]).to.be('xPackMonitoring:allowReport');
|
||||
expect(config.remove.getCall(1).args[0]).to.be('xPackMonitoring:showBanner');
|
||||
expect(config.remove.getCall(2).args[0]).to.be(CONFIG_TELEMETRY);
|
||||
expect(config.remove.calledThrice).toBe(true);
|
||||
expect(config.remove.getCall(0).args[0]).toBe('xPackMonitoring:allowReport');
|
||||
expect(config.remove.getCall(1).args[0]).toBe('xPackMonitoring:showBanner');
|
||||
expect(config.remove.getCall(2).args[0]).toBe(CONFIG_TELEMETRY);
|
||||
|
||||
expect(telemetryOptInProvider.getOptIn()).to.be(true);
|
||||
expect(telemetryOptInProvider.getOptIn()).toBe(true);
|
||||
});
|
||||
|
||||
it('re-uses old "allowReport" setting and stays opted out', async () => {
|
||||
|
@ -102,21 +101,21 @@ describe('handle_old_settings', () => {
|
|||
};
|
||||
|
||||
const telemetryOptInProvider = getTelemetryOptInProvider(null);
|
||||
expect(telemetryOptInProvider.getOptIn()).to.be(null);
|
||||
expect(telemetryOptInProvider.getOptIn()).toBe(null);
|
||||
|
||||
config.get.withArgs('xPackMonitoring:allowReport', null).returns(false);
|
||||
config.set.withArgs(CONFIG_TELEMETRY, false).returns(Promise.resolve(true));
|
||||
|
||||
expect(await handleOldSettings(config, telemetryOptInProvider)).to.be(false);
|
||||
expect(await handleOldSettings(config, telemetryOptInProvider)).toBe(false);
|
||||
|
||||
expect(config.get.calledTwice).to.be(true);
|
||||
expect(config.set.called).to.be(false);
|
||||
expect(config.remove.calledThrice).to.be(true);
|
||||
expect(config.remove.getCall(0).args[0]).to.be('xPackMonitoring:allowReport');
|
||||
expect(config.remove.getCall(1).args[0]).to.be('xPackMonitoring:showBanner');
|
||||
expect(config.remove.getCall(2).args[0]).to.be(CONFIG_TELEMETRY);
|
||||
expect(config.get.calledTwice).toBe(true);
|
||||
expect(config.set.called).toBe(false);
|
||||
expect(config.remove.calledThrice).toBe(true);
|
||||
expect(config.remove.getCall(0).args[0]).toBe('xPackMonitoring:allowReport');
|
||||
expect(config.remove.getCall(1).args[0]).toBe('xPackMonitoring:showBanner');
|
||||
expect(config.remove.getCall(2).args[0]).toBe(CONFIG_TELEMETRY);
|
||||
|
||||
expect(telemetryOptInProvider.getOptIn()).to.be(false);
|
||||
expect(telemetryOptInProvider.getOptIn()).toBe(false);
|
||||
});
|
||||
|
||||
it('re-uses old "telemetry:optIn" setting and stays opted out', async () => {
|
||||
|
@ -131,16 +130,16 @@ describe('handle_old_settings', () => {
|
|||
config.get.withArgs(CONFIG_TELEMETRY, null).returns(false);
|
||||
config.get.withArgs('xPackMonitoring:allowReport', null).returns(true);
|
||||
|
||||
expect(await handleOldSettings(config, telemetryOptInProvider)).to.be(false);
|
||||
expect(await handleOldSettings(config, telemetryOptInProvider)).toBe(false);
|
||||
|
||||
expect(config.get.calledTwice).to.be(true);
|
||||
expect(config.set.called).to.be(false);
|
||||
expect(config.remove.calledThrice).to.be(true);
|
||||
expect(config.remove.getCall(0).args[0]).to.be('xPackMonitoring:allowReport');
|
||||
expect(config.remove.getCall(1).args[0]).to.be('xPackMonitoring:showBanner');
|
||||
expect(config.remove.getCall(2).args[0]).to.be(CONFIG_TELEMETRY);
|
||||
expect(config.get.calledTwice).toBe(true);
|
||||
expect(config.set.called).toBe(false);
|
||||
expect(config.remove.calledThrice).toBe(true);
|
||||
expect(config.remove.getCall(0).args[0]).toBe('xPackMonitoring:allowReport');
|
||||
expect(config.remove.getCall(1).args[0]).toBe('xPackMonitoring:showBanner');
|
||||
expect(config.remove.getCall(2).args[0]).toBe(CONFIG_TELEMETRY);
|
||||
|
||||
expect(telemetryOptInProvider.getOptIn()).to.be(false);
|
||||
expect(telemetryOptInProvider.getOptIn()).toBe(false);
|
||||
});
|
||||
|
||||
it('acknowledges users old setting even if re-setting fails', async () => {
|
||||
|
@ -156,10 +155,10 @@ describe('handle_old_settings', () => {
|
|||
config.set.withArgs(CONFIG_TELEMETRY, false).returns(Promise.resolve(false));
|
||||
|
||||
// note: because it doesn't remove the old settings _and_ returns false, there's no risk of suddenly being opted in
|
||||
expect(await handleOldSettings(config, telemetryOptInProvider)).to.be(false);
|
||||
expect(await handleOldSettings(config, telemetryOptInProvider)).toBe(false);
|
||||
|
||||
expect(config.get.calledTwice).to.be(true);
|
||||
expect(config.set.called).to.be(false);
|
||||
expect(config.get.calledTwice).toBe(true);
|
||||
expect(config.set.called).toBe(false);
|
||||
});
|
||||
|
||||
it('removes show banner setting and presents user with choice', async () => {
|
||||
|
@ -173,11 +172,11 @@ describe('handle_old_settings', () => {
|
|||
config.get.withArgs('xPackMonitoring:allowReport', null).returns(null);
|
||||
config.get.withArgs('xPackMonitoring:showBanner', null).returns(false);
|
||||
|
||||
expect(await handleOldSettings(config, telemetryOptInProvider)).to.be(true);
|
||||
expect(await handleOldSettings(config, telemetryOptInProvider)).toBe(true);
|
||||
|
||||
expect(config.get.calledThrice).to.be(true);
|
||||
expect(config.remove.calledOnce).to.be(true);
|
||||
expect(config.remove.getCall(0).args[0]).to.be('xPackMonitoring:showBanner');
|
||||
expect(config.get.calledThrice).toBe(true);
|
||||
expect(config.remove.calledOnce).toBe(true);
|
||||
expect(config.remove.getCall(0).args[0]).toBe('xPackMonitoring:showBanner');
|
||||
});
|
||||
|
||||
it('is effectively ignored on fresh installs', async () => {
|
||||
|
@ -190,9 +189,9 @@ describe('handle_old_settings', () => {
|
|||
config.get.withArgs('xPackMonitoring:allowReport', null).returns(null);
|
||||
config.get.withArgs('xPackMonitoring:showBanner', null).returns(null);
|
||||
|
||||
expect(await handleOldSettings(config, telemetryOptInProvider)).to.be(true);
|
||||
expect(await handleOldSettings(config, telemetryOptInProvider)).toBe(true);
|
||||
|
||||
expect(config.get.calledThrice).to.be(true);
|
||||
expect(config.get.calledThrice).toBe(true);
|
||||
});
|
||||
|
||||
});
|
|
@ -1,147 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import {
|
||||
EuiButton,
|
||||
EuiCallOut,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiLink,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { getConfigTelemetryDesc, PRIVACY_STATEMENT_URL } from '../../../common/constants';
|
||||
import { OptInExampleFlyout } from '../../components';
|
||||
|
||||
/**
|
||||
* React component for displaying the Telemetry opt-in banner.
|
||||
*
|
||||
* TODO: When Jest tests become available in X-Pack, we should add one for this component.
|
||||
*/
|
||||
export class OptInBanner extends Component {
|
||||
static propTypes = {
|
||||
/**
|
||||
* Callback function with no parameters that returns a {@code Promise} containing the
|
||||
* telemetry data (expected to be an array).
|
||||
*/
|
||||
fetchTelemetry: PropTypes.func.isRequired,
|
||||
/**
|
||||
* Callback function passed a boolean to opt in ({@code true}) or out ({@code false}).
|
||||
*/
|
||||
optInClick: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
showDetails: false,
|
||||
showExample: false,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
let title = getConfigTelemetryDesc();
|
||||
let details;
|
||||
let flyoutDetails;
|
||||
|
||||
if (this.state.showDetails) {
|
||||
details = (
|
||||
<EuiText>
|
||||
<p tabIndex="0">
|
||||
<FormattedMessage
|
||||
id="xpack.telemetry.welcomeBanner.telemetryConfigDetailsDescription"
|
||||
defaultMessage="No information about the data you process or store will be sent. This feature
|
||||
will periodically send basic feature usage statistics. See an {exampleLink} or read our {telemetryPrivacyStatementLink}.
|
||||
You can disable this feature at any time."
|
||||
values={{
|
||||
exampleLink: (
|
||||
<EuiLink onClick={() => this.setState({ showExample: !this.state.showExample })}>
|
||||
<FormattedMessage
|
||||
id="xpack.telemetry.welcomeBanner.telemetryConfigDetailsDescription.exampleLinkText"
|
||||
defaultMessage="example"
|
||||
/>
|
||||
</EuiLink>
|
||||
),
|
||||
telemetryPrivacyStatementLink: (
|
||||
<EuiLink href={PRIVACY_STATEMENT_URL} target="_blank" >
|
||||
<FormattedMessage
|
||||
id="xpack.telemetry.welcomeBanner.telemetryConfigDetailsDescription.telemetryPrivacyStatementLinkText"
|
||||
defaultMessage="telemetry privacy statement"
|
||||
/>
|
||||
</EuiLink>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
);
|
||||
|
||||
if (this.state.showExample) {
|
||||
flyoutDetails = (
|
||||
<OptInExampleFlyout
|
||||
onClose={() => this.setState({ showExample: false })}
|
||||
fetchTelemetry={this.props.fetchTelemetry}
|
||||
/>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
title = (
|
||||
<Fragment>
|
||||
{getConfigTelemetryDesc()} {(
|
||||
<EuiLink onClick={() => this.setState({ showDetails: true })}>
|
||||
<FormattedMessage
|
||||
id="xpack.telemetry.welcomeBanner.telemetryConfigDescription.readMoreLinkText"
|
||||
defaultMessage="Read more"
|
||||
/>
|
||||
</EuiLink>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
const titleNode = (
|
||||
<span tabIndex="0">{title}</span>
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiCallOut iconType="questionInCircle" title={titleNode}>
|
||||
{ details }
|
||||
{ flyoutDetails }
|
||||
<EuiSpacer size="s" />
|
||||
<EuiFlexGroup gutterSize="s" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
size="s"
|
||||
onClick={() => this.props.optInClick(true)}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.telemetry.welcomeBanner.yesButtonLabel"
|
||||
defaultMessage="Yes"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
size="s"
|
||||
onClick={() => this.props.optInClick(false)}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.telemetry.welcomeBanner.noButtonLabel"
|
||||
defaultMessage="No"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiCallOut>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ import React from 'react';
|
|||
import { banners } from 'ui/notify';
|
||||
|
||||
import { clickBanner } from './click_banner';
|
||||
import { OptInBanner } from './opt_in_banner_component';
|
||||
import { OptInBanner } from '../../components/opt_in_banner_component';
|
||||
|
||||
/**
|
||||
* Render the Telemetry Opt-in banner.
|
||||
|
@ -22,10 +22,12 @@ export function renderBanner(telemetryOptInProvider, fetchTelemetry, { _banners
|
|||
const bannerId = _banners.add({
|
||||
component: (
|
||||
<OptInBanner
|
||||
optInClick={optIn => clickBanner(bannerId, telemetryOptInProvider, optIn)}
|
||||
optInClick={optIn => clickBanner(telemetryOptInProvider, optIn)}
|
||||
fetchTelemetry={fetchTelemetry}
|
||||
/>
|
||||
),
|
||||
priority: 10000
|
||||
});
|
||||
|
||||
telemetryOptInProvider.setBannerId(bannerId);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { renderBanner } from './render_banner';
|
||||
|
||||
describe('render_banner', () => {
|
||||
|
||||
it('adds a banner to banners with priority of 10000', () => {
|
||||
const bannerID = 'brucer-banner';
|
||||
|
||||
const telemetryOptInProvider = { setBannerId: jest.fn() };
|
||||
const banners = { add: jest.fn().mockReturnValue(bannerID) };
|
||||
const fetchTelemetry = jest.fn();
|
||||
|
||||
renderBanner(telemetryOptInProvider, fetchTelemetry, { _banners: banners });
|
||||
|
||||
expect(banners.add).toBeCalledTimes(1);
|
||||
expect(fetchTelemetry).toBeCalledTimes(0);
|
||||
expect(telemetryOptInProvider.setBannerId).toBeCalledWith(bannerID);
|
||||
|
||||
const bannerConfig = banners.add.mock.calls[0][0];
|
||||
|
||||
expect(bannerConfig.component).not.toBe(undefined);
|
||||
expect(bannerConfig.priority).toBe(10000);
|
||||
});
|
||||
|
||||
});
|
|
@ -4,18 +4,17 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { mockInjectedMetadata } from '../../services/telemetry_opt_in.test.mocks';
|
||||
|
||||
import sinon from 'sinon';
|
||||
|
||||
import { CONFIG_TELEMETRY } from '../../../../common/constants';
|
||||
import { shouldShowBanner } from '../should_show_banner';
|
||||
import { TelemetryOptInProvider } from '../../../services/telemetry_opt_in';
|
||||
import { CONFIG_TELEMETRY } from '../../../common/constants';
|
||||
import { shouldShowBanner } from './should_show_banner';
|
||||
import { TelemetryOptInProvider } from '../../services/telemetry_opt_in';
|
||||
|
||||
const getMockInjector = ({ telemetryEnabled }) => {
|
||||
const getMockInjector = () => {
|
||||
const get = sinon.stub();
|
||||
|
||||
get.withArgs('telemetryOptedIn').returns(telemetryEnabled);
|
||||
|
||||
const mockHttp = {
|
||||
post: sinon.stub()
|
||||
};
|
||||
|
@ -25,8 +24,9 @@ const getMockInjector = ({ telemetryEnabled }) => {
|
|||
return { get };
|
||||
};
|
||||
|
||||
const getTelemetryOptInProvider = ({ telemetryEnabled = null } = {}) => {
|
||||
const injector = getMockInjector({ telemetryEnabled });
|
||||
const getTelemetryOptInProvider = ({ telemetryOptedIn = null } = {}) => {
|
||||
mockInjectedMetadata({ telemetryOptedIn });
|
||||
const injector = getMockInjector();
|
||||
const chrome = {
|
||||
addBasePath: (url) => url
|
||||
};
|
||||
|
@ -49,28 +49,28 @@ describe('should_show_banner', () => {
|
|||
const showBannerTrue = await shouldShowBanner(telemetryOptInProvider, config, { _handleOldSettings: handleOldSettingsTrue });
|
||||
const showBannerFalse = await shouldShowBanner(telemetryOptInProvider, config, { _handleOldSettings: handleOldSettingsFalse });
|
||||
|
||||
expect(showBannerTrue).to.be(true);
|
||||
expect(showBannerFalse).to.be(false);
|
||||
expect(showBannerTrue).toBe(true);
|
||||
expect(showBannerFalse).toBe(false);
|
||||
|
||||
expect(config.get.callCount).to.be(0);
|
||||
expect(handleOldSettingsTrue.calledOnce).to.be(true);
|
||||
expect(handleOldSettingsFalse.calledOnce).to.be(true);
|
||||
expect(config.get.callCount).toBe(0);
|
||||
expect(handleOldSettingsTrue.calledOnce).toBe(true);
|
||||
expect(handleOldSettingsFalse.calledOnce).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false if telemetry opt-in setting is set to true', async () => {
|
||||
const config = { get: sinon.stub() };
|
||||
|
||||
const telemetryOptInProvider = getTelemetryOptInProvider({ telemetryEnabled: true });
|
||||
const telemetryOptInProvider = getTelemetryOptInProvider({ telemetryOptedIn: true });
|
||||
|
||||
expect(await shouldShowBanner(telemetryOptInProvider, config)).to.be(false);
|
||||
expect(await shouldShowBanner(telemetryOptInProvider, config)).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false if telemetry opt-in setting is set to false', async () => {
|
||||
const config = { get: sinon.stub() };
|
||||
|
||||
const telemetryOptInProvider = getTelemetryOptInProvider({ telemetryEnabled: false });
|
||||
const telemetryOptInProvider = getTelemetryOptInProvider({ telemetryOptedIn: false });
|
||||
|
||||
expect(await shouldShowBanner(telemetryOptInProvider, config)).to.be(false);
|
||||
expect(await shouldShowBanner(telemetryOptInProvider, config)).toBe(false);
|
||||
});
|
||||
|
||||
});
|
|
@ -3,6 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import { mockInjectedMetadata } from './telemetry_opt_in.test.mocks';
|
||||
import { TelemetryOptInProvider } from './telemetry_opt_in';
|
||||
|
||||
describe('TelemetryOptInProvider', () => {
|
||||
|
@ -19,12 +20,11 @@ describe('TelemetryOptInProvider', () => {
|
|||
addBasePath: (url) => url
|
||||
};
|
||||
|
||||
mockInjectedMetadata({ telemetryOptedIn: optedIn });
|
||||
|
||||
const mockInjector = {
|
||||
get: (key) => {
|
||||
switch (key) {
|
||||
case 'telemetryOptedIn': {
|
||||
return optedIn;
|
||||
}
|
||||
case '$http': {
|
||||
return mockHttp;
|
||||
}
|
||||
|
@ -77,4 +77,11 @@ describe('TelemetryOptInProvider', () => {
|
|||
// opt-in change should not be reflected
|
||||
expect(provider.getOptIn()).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return the current bannerId', () => {
|
||||
const { provider } = setup({});
|
||||
const bannerId = 'bruce-banner';
|
||||
provider.setBannerId(bannerId);
|
||||
expect(provider.getBannerId()).toEqual(bannerId);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { injectedMetadataServiceMock } from '../../../../../../src/core/public/mocks';
|
||||
const injectedMetadataMock = injectedMetadataServiceMock.createStartContract();
|
||||
|
||||
export function mockInjectedMetadata({ telemetryOptedIn }) {
|
||||
const mockGetInjectedVar = jest.fn().mockImplementation((key) => {
|
||||
switch (key) {
|
||||
case 'telemetryOptedIn': return telemetryOptedIn;
|
||||
default: throw new Error(`unexpected injectedVar ${key}`);
|
||||
}
|
||||
});
|
||||
|
||||
injectedMetadataMock.getInjectedVar = mockGetInjectedVar;
|
||||
}
|
||||
|
||||
jest.doMock('ui/new_platform', () => ({
|
||||
npStart: {
|
||||
core: {
|
||||
injectedMetadata: injectedMetadataMock
|
||||
},
|
||||
},
|
||||
}));
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
// @ts-ignore
|
||||
export { TelemetryOptInProvider } from '../../../../../../src/legacy/core_plugins/kibana/public/home/telemetry_opt_in'; // eslint-disable-line
|
|
@ -2432,6 +2432,8 @@
|
|||
"kbn.visualize.wizard.step1Breadcrumb": "作成",
|
||||
"kbn.visualize.wizard.step2Breadcrumb": "作成",
|
||||
"kbn.visualizeTitle": "可視化",
|
||||
"kbn.home.telemetry.optInErrorToastText": "使用状況統計設定の設定中にエラーが発生しました。",
|
||||
"kbn.home.telemetry.optInErrorToastTitle": "エラー",
|
||||
"kbnDocViews.table.fieldNamesBeginningWithUnderscoreUnsupportedTooltip": "{underscoreSign} で始まるフィールド名はサポートされていません",
|
||||
"kbnDocViews.table.filterForFieldPresentButtonAriaLabel": "現在のフィールドのフィルター",
|
||||
"kbnDocViews.table.filterForFieldPresentButtonTooltip": "現在のフィールドのフィルター",
|
||||
|
@ -10125,8 +10127,6 @@
|
|||
"xpack.telemetry.callout.errorLoadingClusterStatisticsTitle": "クラスター統計の読み込みエラー",
|
||||
"xpack.telemetry.callout.errorUnprivilegedUserDescription": "暗号化されていないクラスター統計を表示するアクセス権がありません。",
|
||||
"xpack.telemetry.callout.errorUnprivilegedUserTitle": "クラスター統計の表示エラー",
|
||||
"xpack.telemetry.optInErrorToastText": "使用状況統計設定の設定中にエラーが発生しました。",
|
||||
"xpack.telemetry.optInErrorToastTitle": "エラー",
|
||||
"xpack.telemetry.readOurUsageDataPrivacyStatementLinkText": "使用データのプライバシーステートメントをお読みください",
|
||||
"xpack.telemetry.seeExampleOfWhatWeCollectLinkText": "収集されるデータの例を見る",
|
||||
"xpack.telemetry.telemetryConfigDescription": "基本的な機能利用に関する統計情報を提供して Elastic Stack の改善にご協力ください。このデータは Elastic 社外と共有されません。",
|
||||
|
|
|
@ -2432,6 +2432,8 @@
|
|||
"kbn.visualize.wizard.step1Breadcrumb": "创建",
|
||||
"kbn.visualize.wizard.step2Breadcrumb": "创建",
|
||||
"kbn.visualizeTitle": "可视化",
|
||||
"kbn.home.telemetry.optInErrorToastText": "尝试设置使用统计信息首选项时发生错误。",
|
||||
"kbn.home.telemetry.optInErrorToastTitle": "错误",
|
||||
"kbnDocViews.table.fieldNamesBeginningWithUnderscoreUnsupportedTooltip": "不支持以 {underscoreSign} 开头的字段名称",
|
||||
"kbnDocViews.table.filterForFieldPresentButtonAriaLabel": "筛留存在的字段",
|
||||
"kbnDocViews.table.filterForFieldPresentButtonTooltip": "筛留存在的字段",
|
||||
|
@ -10267,8 +10269,6 @@
|
|||
"xpack.telemetry.callout.errorLoadingClusterStatisticsTitle": "加载集群统计信息时出错",
|
||||
"xpack.telemetry.callout.errorUnprivilegedUserDescription": "您无权查看未加密的集群统计信息。",
|
||||
"xpack.telemetry.callout.errorUnprivilegedUserTitle": "显示集群统计信息时出错",
|
||||
"xpack.telemetry.optInErrorToastText": "尝试设置使用统计信息首选项时发生错误。",
|
||||
"xpack.telemetry.optInErrorToastTitle": "错误",
|
||||
"xpack.telemetry.readOurUsageDataPrivacyStatementLinkText": "阅读我们的使用情况数据隐私声明",
|
||||
"xpack.telemetry.seeExampleOfWhatWeCollectLinkText": "查看我们收集的内容示例",
|
||||
"xpack.telemetry.telemetryConfigDescription": "通过提供基本功能的使用情况统计信息,来帮助我们改进 Elastic Stack。我们不会在 Elastic 之外共享此数据。",
|
||||
|
|
Loading…
Reference in a new issue