[Guided onboarding] Disable guided onboarding (#147649)

This commit is contained in:
Alison Goryachev 2022-12-16 11:30:50 -05:00 committed by GitHub
parent 74baee4a17
commit 49a1e9b2e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 57 additions and 183 deletions

View file

@ -10,5 +10,6 @@
"server": true,
"ui": true,
"requiredBundles": ["kibanaReact"],
"optionalPlugins": ["cloud"]
"optionalPlugins": ["cloud"],
"configPath": ["guidedOnboarding"]
}

View file

@ -6,10 +6,11 @@
* Side Public License, v 1.
*/
import { PluginInitializerContext } from '@kbn/core/public';
import { GuidedOnboardingPlugin } from './plugin';
export function plugin() {
return new GuidedOnboardingPlugin();
export function plugin(ctx: PluginInitializerContext) {
return new GuidedOnboardingPlugin(ctx);
}
export type {
GuidedOnboardingPluginSetup,

View file

@ -17,6 +17,7 @@ import {
CoreTheme,
ApplicationStart,
NotificationsStart,
PluginInitializerContext,
} from '@kbn/core/public';
import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public';
@ -24,6 +25,7 @@ import type {
AppPluginStartDependencies,
GuidedOnboardingPluginSetup,
GuidedOnboardingPluginStart,
ClientConfigType,
} from './types';
import { GuidePanel } from './components';
import { ApiService, apiService } from './services/api';
@ -31,7 +33,8 @@ import { ApiService, apiService } from './services/api';
export class GuidedOnboardingPlugin
implements Plugin<GuidedOnboardingPluginSetup, GuidedOnboardingPluginStart>
{
constructor() {}
constructor(private ctx: PluginInitializerContext) {}
public setup(core: CoreSetup): GuidedOnboardingPluginSetup {
return {};
}
@ -41,12 +44,13 @@ export class GuidedOnboardingPlugin
{ cloud }: AppPluginStartDependencies
): GuidedOnboardingPluginStart {
const { chrome, http, theme, application, notifications } = core;
const { ui: isGuidedOnboardingUiEnabled } = this.ctx.config.get<ClientConfigType>();
// Initialize services
apiService.setup(http, !!cloud?.isCloudEnabled);
apiService.setup(http, !!cloud?.isCloudEnabled && isGuidedOnboardingUiEnabled);
// Guided onboarding UI is only available on cloud
if (cloud?.isCloudEnabled) {
// Guided onboarding UI is only available if enabled and the user is running on cloud
if (isGuidedOnboardingUiEnabled && cloud?.isCloudEnabled) {
chrome.navControls.registerExtension({
order: 1000,
mount: (target) =>

View file

@ -477,7 +477,7 @@ describe('GuidedOnboarding ApiService', () => {
});
});
describe('no API requests are sent on self-managed deployments', () => {
describe('no API requests are sent when the guided onboarding is disabled', () => {
beforeEach(() => {
apiService.setup(httpClient, false);
});

View file

@ -26,14 +26,14 @@ import {
} from './helpers';
export class ApiService implements GuidedOnboardingApi {
private isCloudEnabled: boolean | undefined;
private isEnabled: boolean | undefined;
private client: HttpSetup | undefined;
private pluginState$!: BehaviorSubject<PluginState | undefined>;
private isPluginStateLoading: boolean | undefined;
public isGuidePanelOpen$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public setup(httpClient: HttpSetup, isCloudEnabled: boolean) {
this.isCloudEnabled = isCloudEnabled;
public setup(httpClient: HttpSetup, isEnabled: boolean) {
this.isEnabled = isEnabled;
this.client = httpClient;
this.pluginState$ = new BehaviorSubject<PluginState | undefined>(undefined);
this.isGuidePanelOpen$ = new BehaviorSubject<boolean>(false);
@ -76,7 +76,7 @@ export class ApiService implements GuidedOnboardingApi {
* Subsequently, the observable is updated automatically, when the state changes.
*/
public fetchPluginState$(): Observable<PluginState | undefined> {
if (!this.isCloudEnabled) {
if (!this.isEnabled) {
return of(undefined);
}
if (!this.client) {
@ -100,7 +100,7 @@ export class ApiService implements GuidedOnboardingApi {
* where all guides are displayed with their corresponding status.
*/
public async fetchAllGuidesState(): Promise<{ state: GuideState[] } | undefined> {
if (!this.isCloudEnabled) {
if (!this.isEnabled) {
return undefined;
}
if (!this.client) {
@ -125,7 +125,7 @@ export class ApiService implements GuidedOnboardingApi {
state: { status?: PluginStatus; guide?: GuideState },
panelState: boolean
): Promise<{ pluginState: PluginState } | undefined> {
if (!this.isCloudEnabled) {
if (!this.isEnabled) {
return undefined;
}
if (!this.client) {

View file

@ -24,8 +24,12 @@ export interface AppPluginStartDependencies {
cloud?: CloudStart;
}
export interface ClientConfigType {
ui: boolean;
}
export interface GuidedOnboardingApi {
setup: (httpClient: HttpSetup, isCloudEnabled: boolean) => void;
setup: (httpClient: HttpSetup, isEnabled: boolean) => void;
fetchPluginState$: () => Observable<PluginState | undefined>;
fetchAllGuidesState: () => Promise<{ state: GuideState[] } | undefined>;
updatePluginState: (

View file

@ -0,0 +1,25 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { PluginConfigDescriptor } from '@kbn/core/server';
import { schema, TypeOf } from '@kbn/config-schema';
// By default, hide any guided onboarding UI. Change it with guidedOnboarding.ui:true in kibana.dev.yml
const configSchema = schema.object({
ui: schema.boolean({ defaultValue: false }),
});
export type GuidedOnboardingConfig = TypeOf<typeof configSchema>;
export const config: PluginConfigDescriptor<GuidedOnboardingConfig> = {
// define which config properties should be available in the client side plugin
exposeToBrowser: {
ui: true,
},
schema: configSchema,
};

View file

@ -14,3 +14,5 @@ export function plugin(initializerContext: PluginInitializerContext) {
}
export type { GuidedOnboardingPluginSetup, GuidedOnboardingPluginStart } from './types';
export { config } from './config';

View file

@ -28,10 +28,8 @@ exports[`home change home route should render a link to change the default route
"integrations": true,
},
},
"navigateToUrl": [MockFunction],
}
}
isCloudEnabled={false}
isDarkMode={false}
/>
<ManageData
@ -43,7 +41,6 @@ exports[`home change home route should render a link to change the default route
"integrations": true,
},
},
"navigateToUrl": [MockFunction],
}
}
features={Array []}
@ -85,10 +82,8 @@ exports[`home directories should not render directory entry when showOnHomePage
"integrations": true,
},
},
"navigateToUrl": [MockFunction],
}
}
isCloudEnabled={false}
isDarkMode={false}
/>
<ManageData
@ -100,7 +95,6 @@ exports[`home directories should not render directory entry when showOnHomePage
"integrations": true,
},
},
"navigateToUrl": [MockFunction],
}
}
features={Array []}
@ -142,10 +136,8 @@ exports[`home directories should render ADMIN directory entry in "Manage your da
"integrations": true,
},
},
"navigateToUrl": [MockFunction],
}
}
isCloudEnabled={false}
isDarkMode={false}
/>
<ManageData
@ -157,7 +149,6 @@ exports[`home directories should render ADMIN directory entry in "Manage your da
"integrations": true,
},
},
"navigateToUrl": [MockFunction],
}
}
features={
@ -246,10 +237,8 @@ exports[`home directories should render solutions in the "solution section" 1`]
"integrations": true,
},
},
"navigateToUrl": [MockFunction],
}
}
isCloudEnabled={false}
isDarkMode={false}
/>
<ManageData
@ -261,7 +250,6 @@ exports[`home directories should render solutions in the "solution section" 1`]
"integrations": true,
},
},
"navigateToUrl": [MockFunction],
}
}
features={Array []}
@ -303,22 +291,8 @@ exports[`home isNewKibanaInstance should safely handle exceptions 1`] = `
"integrations": true,
},
},
"navigateToUrl": [MockFunction] {
"calls": Array [
Array [
"./home#/getting_started",
],
],
"results": Array [
Object {
"type": "return",
"value": undefined,
},
],
},
}
}
isCloudEnabled={false}
isDarkMode={false}
/>
<ManageData
@ -330,19 +304,6 @@ exports[`home isNewKibanaInstance should safely handle exceptions 1`] = `
"integrations": true,
},
},
"navigateToUrl": [MockFunction] {
"calls": Array [
Array [
"./home#/getting_started",
],
],
"results": Array [
Object {
"type": "return",
"value": undefined,
},
],
},
}
}
features={Array []}
@ -384,22 +345,8 @@ exports[`home isNewKibanaInstance should set isNewKibanaInstance to false when t
"integrations": true,
},
},
"navigateToUrl": [MockFunction] {
"calls": Array [
Array [
"./home#/getting_started",
],
],
"results": Array [
Object {
"type": "return",
"value": undefined,
},
],
},
}
}
isCloudEnabled={false}
isDarkMode={false}
/>
<ManageData
@ -411,19 +358,6 @@ exports[`home isNewKibanaInstance should set isNewKibanaInstance to false when t
"integrations": true,
},
},
"navigateToUrl": [MockFunction] {
"calls": Array [
Array [
"./home#/getting_started",
],
],
"results": Array [
Object {
"type": "return",
"value": undefined,
},
],
},
}
}
features={Array []}
@ -472,10 +406,8 @@ exports[`home should render home component 1`] = `
"integrations": true,
},
},
"navigateToUrl": [MockFunction],
}
}
isCloudEnabled={false}
isDarkMode={false}
/>
<ManageData
@ -487,7 +419,6 @@ exports[`home should render home component 1`] = `
"integrations": true,
},
},
"navigateToUrl": [MockFunction],
}
}
features={Array []}

View file

@ -40,7 +40,6 @@ describe('AddData', () => {
addBasePath={addBasePathMock}
application={applicationStartMock}
isDarkMode={false}
isCloudEnabled={false}
/>
);
expect(component).toMatchSnapshot();

View file

@ -29,10 +29,9 @@ interface Props {
addBasePath: (path: string) => string;
application: ApplicationStart;
isDarkMode: boolean;
isCloudEnabled: boolean;
}
export const AddData: FC<Props> = ({ addBasePath, application, isDarkMode, isCloudEnabled }) => {
export const AddData: FC<Props> = ({ addBasePath, application, isDarkMode }) => {
const { trackUiMetric } = getServices();
const canAccessIntegrations = application.capabilities.navLinks.integrations;
if (canAccessIntegrations) {
@ -68,32 +67,12 @@ export const AddData: FC<Props> = ({ addBasePath, application, isDarkMode, isClo
<EuiSpacer />
<EuiFlexGroup gutterSize="m">
{isCloudEnabled && (
<EuiFlexItem grow={false}>
{/* eslint-disable-next-line @elastic/eui/href-or-on-click */}
<EuiButton
data-test-subj="guidedOnboardingLink"
fill
href={addBasePath('#/getting_started')}
onClick={(event: MouseEvent) => {
trackUiMetric(METRIC_TYPE.CLICK, 'guided_onboarding_link');
}}
>
<FormattedMessage
id="home.addData.guidedOnboardingLinkLabel"
defaultMessage="Setup guides"
/>
</EuiButton>
</EuiFlexItem>
)}
<EuiFlexItem grow={false}>
<RedirectAppLinks application={application}>
{/* eslint-disable-next-line @elastic/eui/href-or-on-click */}
<EuiButton
data-test-subj="homeAddData"
// on self managed this button is primary
// on Cloud this button is secondary, because there is a "guided onboarding" button
fill={!isCloudEnabled}
fill={true}
href={addBasePath('/app/integrations/browse')}
iconType="plusInCircle"
onClick={(event: MouseEvent) => {

View file

@ -14,7 +14,6 @@ import { Home } from './home';
import { Welcome } from './welcome';
let mockHasIntegrationsPermission = true;
const mockNavigateToUrl = jest.fn();
jest.mock('../kibana_services', () => ({
getServices: () => ({
getBasePath: () => 'path',
@ -24,7 +23,6 @@ jest.mock('../kibana_services', () => ({
setBreadcrumbs: () => {},
},
application: {
navigateToUrl: mockNavigateToUrl,
capabilities: {
navLinks: {
integrations: mockHasIntegrationsPermission,
@ -61,7 +59,6 @@ describe('home', () => {
return `base_path/${url}`;
},
hasUserDataView: jest.fn(async () => true),
isCloudEnabled: false,
};
});
@ -233,16 +230,6 @@ describe('home', () => {
expect(component.find(Welcome).exists()).toBe(false);
});
test('should redirect to guided onboarding on Cloud instead of welcome screen', async () => {
const isCloudEnabled = true;
const hasUserDataView = jest.fn(async () => false);
const component = await renderHome({ isCloudEnabled, hasUserDataView });
expect(component.find(Welcome).exists()).toBe(false);
expect(mockNavigateToUrl).toHaveBeenCalledTimes(1);
});
});
describe('isNewKibanaInstance', () => {

View file

@ -33,7 +33,6 @@ export interface HomeProps {
localStorage: Storage;
urlBasePath: string;
hasUserDataView: () => Promise<boolean>;
isCloudEnabled: boolean;
}
interface State {
@ -127,7 +126,7 @@ export class Home extends Component<HomeProps, State> {
}
private renderNormal() {
const { addBasePath, solutions, isCloudEnabled } = this.props;
const { addBasePath, solutions } = this.props;
const { application, trackUiMetric } = getServices();
const isDarkMode = getServices().uiSettings?.get('theme:darkMode') || false;
const devTools = this.findDirectoryById('console');
@ -149,12 +148,7 @@ export class Home extends Component<HomeProps, State> {
>
<SolutionsSection addBasePath={addBasePath} solutions={solutions} />
<AddData
addBasePath={addBasePath}
application={application}
isDarkMode={isDarkMode}
isCloudEnabled={isCloudEnabled}
/>
<AddData addBasePath={addBasePath} application={application} isDarkMode={isDarkMode} />
<ManageData
addBasePath={addBasePath}
@ -188,18 +182,12 @@ export class Home extends Component<HomeProps, State> {
public render() {
const { isLoading, isWelcomeEnabled, isNewKibanaInstance } = this.state;
const { isCloudEnabled } = this.props;
const { application } = getServices();
if (isWelcomeEnabled) {
if (isLoading) {
return this.renderLoading();
}
if (isNewKibanaInstance) {
if (isCloudEnabled) {
application.navigateToUrl('./home#/getting_started');
return null;
}
return this.renderWelcome();
}
}

View file

@ -16,7 +16,6 @@ import { HashRouter as Router, Switch, Route, Redirect } from 'react-router-dom'
import { getTutorial } from '../load_tutorials';
import { replaceTemplateStrings } from './tutorial/replace_template_strings';
import { getServices } from '../kibana_services';
import { GettingStarted } from './guided_onboarding';
const REDIRECT_TO_INTEGRATIONS_TAB_IDS = ['all', 'logging', 'metrics', 'security'];
@ -68,9 +67,6 @@ export function HomeApp({ directories, solutions }) {
<Switch>
<Route path="/tutorial/:id" render={renderTutorial} />
<Route path="/tutorial_directory/:tab?" render={renderTutorialDirectory} />
<Route path="/getting_started">
<GettingStarted />
</Route>
<Route exact path="/">
<Home
addBasePath={addBasePath}
@ -79,7 +75,6 @@ export function HomeApp({ directories, solutions }) {
localStorage={localStorage}
urlBasePath={getBasePath()}
hasUserDataView={() => dataViewsService.hasUserDataView()}
isCloudEnabled={isCloudEnabled}
/>
</Route>
<Redirect to="/" />

View file

@ -104,6 +104,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
'data.search.sessions.maxUpdateRetries (number)',
'data.search.sessions.notTouchedTimeout (duration)',
'enterpriseSearch.host (string)',
'guidedOnboarding.ui (boolean)',
'home.disableWelcomeScreen (boolean)',
'map.emsFileApiUrl (string)',
'map.emsFontLibraryUrl (string)',

View file

@ -31,31 +31,6 @@ describe('Cloud Links Plugin - public', () => {
plugin.stop();
});
describe('Onboarding Setup Guide link registration', () => {
test('registers the Onboarding Setup Guide link when cloud is enabled and it is an authenticated page', () => {
const coreStart = coreMock.createStart();
coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(false);
const cloud = { ...cloudMock.createStart(), isCloudEnabled: true };
plugin.start(coreStart, { cloud });
expect(coreStart.chrome.registerGlobalHelpExtensionMenuLink).toHaveBeenCalledTimes(1);
});
test('does not register the Onboarding Setup Guide link when cloud is enabled but it is an unauthenticated page', () => {
const coreStart = coreMock.createStart();
coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(true);
const cloud = { ...cloudMock.createStart(), isCloudEnabled: true };
plugin.start(coreStart, { cloud });
expect(coreStart.chrome.registerGlobalHelpExtensionMenuLink).not.toHaveBeenCalled();
});
test('does not register the Onboarding Setup Guide link when cloud is not enabled', () => {
const coreStart = coreMock.createStart();
const cloud = { ...cloudMock.createStart(), isCloudEnabled: false };
plugin.start(coreStart, { cloud });
expect(coreStart.chrome.registerGlobalHelpExtensionMenuLink).not.toHaveBeenCalled();
});
});
describe('maybeAddCloudLinks', () => {
test('calls maybeAddCloudLinks when cloud and security are enabled and it is an authenticated page', () => {
const coreStart = coreMock.createStart();

View file

@ -5,8 +5,6 @@
* 2.0.
*/
import React from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import type { CoreStart, Plugin } from '@kbn/core/public';
import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public';
import type { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/public';
@ -29,16 +27,6 @@ export class CloudLinksPlugin
public start(core: CoreStart, { cloud, security }: CloudLinksDepsStart) {
if (cloud?.isCloudEnabled && !core.http.anonymousPaths.isAnonymous(window.location.pathname)) {
core.chrome.registerGlobalHelpExtensionMenuLink({
linkType: 'custom',
href: core.http.basePath.prepend('/app/home#/getting_started'),
content: (
<FormattedMessage id="xpack.cloudLinks.setupGuide" defaultMessage="Setup guides" />
),
'data-test-subj': 'cloudOnboardingSetupGuideLink',
priority: 1000, // We want this link to be at the very top.
});
if (security) {
maybeAddCloudLinks({ security, chrome: core.chrome, cloud });
}

View file

@ -3439,7 +3439,6 @@
"home.tutorials.zookeeperMetrics.longDescription": "Le module Metricbeat \"{moduleName}\" récupère des indicateurs depuis un serveur Zookeeper. [En savoir plus]({learnMoreLink}).",
"home.tutorials.zscalerLogs.longDescription": "Ce module permet de recevoir des logs Zscaler NSS par le biais de Syslog ou d'un fichier. [En savoir plus]({learnMoreLink}).",
"home.addData.addDataButtonLabel": "Ajouter des intégrations",
"home.addData.guidedOnboardingLinkLabel": "Guides de configuration",
"home.addData.sampleDataButtonLabel": "Utiliser un exemple de données",
"home.addData.sectionTitle": "Ajoutez des intégrations pour commencer",
"home.addData.text": "Vous avez plusieurs options pour commencer à exploiter vos données. Vous pouvez collecter des données à partir d'une application ou d'un service, ou bien charger un fichier. Et si vous n'êtes pas encore prêt à utiliser vos propres données, testez un exemple d'ensemble de données.",
@ -36976,7 +36975,6 @@
"xpack.cloudChat.chatFrameTitle": "Chat",
"xpack.cloudChat.hideChatButtonLabel": "Masquer le chat",
"xpack.cloudLinks.deploymentLinkLabel": "Gérer ce déploiement",
"xpack.cloudLinks.setupGuide": "Guides de configuration",
"xpack.cloudLinks.userMenuLinks.accountLinkText": "Compte et facturation",
"xpack.cloudLinks.userMenuLinks.profileLinkText": "Modifier le profil",
"xpack.dashboard.components.DashboardDrilldownConfig.chooseDestinationDashboard": "Choisir le tableau de bord de destination",

View file

@ -3436,7 +3436,6 @@
"home.tutorials.zookeeperMetrics.longDescription": "「{moduleName}」Metricbeat モジュールは、Zookeeper サーバーからメトリックを取得します。 [詳細]{learnMoreLink})。",
"home.tutorials.zscalerLogs.longDescription": "これは、Syslog またはファイルで Zscaler NSS ログを受信するためのモジュールです。[詳細]{learnMoreLink})。",
"home.addData.addDataButtonLabel": "統合の追加",
"home.addData.guidedOnboardingLinkLabel": "セットアップガイド",
"home.addData.sampleDataButtonLabel": "サンプルデータを試す",
"home.addData.sectionTitle": "統合を追加して開始する",
"home.addData.text": "データの操作を開始するには、多数の取り込みオプションのいずれかを使用します。アプリまたはサービスからデータを収集するか、ファイルをアップロードします。独自のデータを使用する準備ができていない場合は、サンプルデータセットを利用してください。",
@ -36948,7 +36947,6 @@
"xpack.cloudChat.chatFrameTitle": "チャット",
"xpack.cloudChat.hideChatButtonLabel": "グラフを非表示",
"xpack.cloudLinks.deploymentLinkLabel": "このデプロイの管理",
"xpack.cloudLinks.setupGuide": "セットアップガイド",
"xpack.cloudLinks.userMenuLinks.accountLinkText": "会計・請求",
"xpack.cloudLinks.userMenuLinks.profileLinkText": "プロフィールを編集",
"xpack.dashboard.components.DashboardDrilldownConfig.chooseDestinationDashboard": "対象ダッシュボードを選択",

View file

@ -3441,7 +3441,6 @@
"home.tutorials.zookeeperMetrics.longDescription": "Metricbeat 模块 `{moduleName}` 从 Zookeeper 服务器提取指标。[了解详情]({learnMoreLink})。",
"home.tutorials.zscalerLogs.longDescription": "这是用于通过 Syslog 或文件接收 Zscaler NSS 日志的模块。[了解详情]({learnMoreLink})。",
"home.addData.addDataButtonLabel": "添加集成",
"home.addData.guidedOnboardingLinkLabel": "设置指南",
"home.addData.sampleDataButtonLabel": "试用样例数据",
"home.addData.sectionTitle": "通过添加集成开始使用",
"home.addData.text": "要开始使用您的数据,请使用我们众多采集选项中的一个选项。从应用或服务收集数据,或上传文件。如果未准备好使用自己的数据,请采用示例数据集。",
@ -36984,7 +36983,6 @@
"xpack.cloudChat.chatFrameTitle": "聊天",
"xpack.cloudChat.hideChatButtonLabel": "隐藏聊天",
"xpack.cloudLinks.deploymentLinkLabel": "管理此部署",
"xpack.cloudLinks.setupGuide": "设置指南",
"xpack.cloudLinks.userMenuLinks.accountLinkText": "帐户和帐单",
"xpack.cloudLinks.userMenuLinks.profileLinkText": "编辑配置文件",
"xpack.dashboard.components.DashboardDrilldownConfig.chooseDestinationDashboard": "选择目标仪表板",