mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[Guided onboarding] Landing page updates (#143194)
* [Guided onboarding] Updated landing page * [Guided onboarding] Finished landing page changes * [Guided onboarding] Fixed card for completed guides * [Guided onboarding] Fixed types errors * [Guided onboarding] Fixed i18n issues * Update src/plugins/home/public/application/components/guided_onboarding/use_case_card.tsx Co-authored-by: Cindy Chang <cindyisachang@gmail.com> * Update src/plugins/home/public/application/components/guided_onboarding/use_case_card.tsx Co-authored-by: Cindy Chang <cindyisachang@gmail.com> * Update src/plugins/home/public/application/components/guided_onboarding/use_case_card.tsx Co-authored-by: Cindy Chang <cindyisachang@gmail.com> * [Guided onboarding] Added CR comments * [Guided onboarding] Added view guide button to the completed guide * [Guided onboarding] Fixed the typo in kibana services * [Guided onboarding] Started moving the components out of home plugin into the guided onboarding package * [Guided onboarding] Fix the imports in the plugin * [Guided onboarding] Fix the tests in the new package * [CI] Auto-commit changed files from 'node scripts/generate codeowners' * [Guided onboarding] Fix the package file and the yarn.lock file * [Guided onboarding] Fix the build * [Guided onboarding] More refactoring * [Guided onboarding] More refactoring * [Guided onboarding] More refactoring * [Guided onboarding] More refactoring of types * [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' * [Guided onboarding] More refactoring of types * [Guided onboarding] Fix the types issues * [Guided onboarding] Update the tests for the api * [Guided onboarding] Fixed the i18n errors * [Guided onboarding] Fixed the i18n errors * [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' * [Guided onboarding] Fixed the jest tests * [Guided onboarding] Home changes * Update packages/kbn-guided-onboarding/src/components/landing_page/observability_link_card.tsx Co-authored-by: Kelly Murphy <kelly.murphy@elastic.co> * [Guided onboarding] Address copy feedback * [Guided onboarding] Address CR feedback Co-authored-by: Cindy Chang <cindyisachang@gmail.com> Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kelly Murphy <kelly.murphy@elastic.co>
This commit is contained in:
parent
27f4f73623
commit
9c0dd18577
53 changed files with 1084 additions and 402 deletions
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -905,6 +905,7 @@ packages/kbn-ftr-common-functional-services @elastic/kibana-operations
|
|||
packages/kbn-ftr-screenshot-filename @elastic/kibana-operations
|
||||
packages/kbn-generate @elastic/kibana-operations
|
||||
packages/kbn-get-repo-files @elastic/kibana-operations
|
||||
packages/kbn-guided-onboarding @elastic/platform-onboarding
|
||||
packages/kbn-handlebars @elastic/kibana-security
|
||||
packages/kbn-hapi-mocks @elastic/kibana-core
|
||||
packages/kbn-i18n @elastic/kibana-core
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
"fieldFormats": "src/plugins/field_formats",
|
||||
"flot": "packages/kbn-flot-charts/lib",
|
||||
"guidedOnboarding": "src/plugins/guided_onboarding",
|
||||
"guidedOnboardingPackage": "packages/kbn-guided-onboarding",
|
||||
"home": "src/plugins/home",
|
||||
"homePackages": "packages/home",
|
||||
"indexPatternEditor": "src/plugins/data_view_editor",
|
||||
|
|
|
@ -25,13 +25,8 @@ import {
|
|||
EuiText,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import type {
|
||||
GuidedOnboardingPluginStart,
|
||||
GuideState,
|
||||
GuideStepIds,
|
||||
GuideId,
|
||||
GuideStep,
|
||||
} from '@kbn/guided-onboarding-plugin/public';
|
||||
import type { GuideState, GuideStepIds, GuideId, GuideStep } from '@kbn/guided-onboarding';
|
||||
import type { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public';
|
||||
import { guidesConfig } from '@kbn/guided-onboarding-plugin/public';
|
||||
|
||||
interface MainProps {
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public';
|
||||
import { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public/types';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
|
@ -16,6 +15,5 @@ export interface GuidedOnboardingExamplePluginSetup {}
|
|||
export interface GuidedOnboardingExamplePluginStart {}
|
||||
|
||||
export interface AppPluginStartDependencies {
|
||||
navigation: NavigationPublicPluginStart;
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
}
|
||||
|
|
|
@ -323,6 +323,7 @@
|
|||
"@kbn/es-types": "link:bazel-bin/packages/kbn-es-types",
|
||||
"@kbn/field-types": "link:bazel-bin/packages/kbn-field-types",
|
||||
"@kbn/flot-charts": "link:bazel-bin/packages/kbn-flot-charts",
|
||||
"@kbn/guided-onboarding": "link:bazel-bin/packages/kbn-guided-onboarding",
|
||||
"@kbn/handlebars": "link:bazel-bin/packages/kbn-handlebars",
|
||||
"@kbn/hapi-mocks": "link:bazel-bin/packages/kbn-hapi-mocks",
|
||||
"@kbn/home-sample-data-card": "link:bazel-bin/packages/home/sample_data_card",
|
||||
|
@ -1075,6 +1076,7 @@
|
|||
"@types/kbn__ftr-screenshot-filename": "link:bazel-bin/packages/kbn-ftr-screenshot-filename/npm_module_types",
|
||||
"@types/kbn__generate": "link:bazel-bin/packages/kbn-generate/npm_module_types",
|
||||
"@types/kbn__get-repo-files": "link:bazel-bin/packages/kbn-get-repo-files/npm_module_types",
|
||||
"@types/kbn__guided-onboarding": "link:bazel-bin/packages/kbn-guided-onboarding/npm_module_types",
|
||||
"@types/kbn__handlebars": "link:bazel-bin/packages/kbn-handlebars/npm_module_types",
|
||||
"@types/kbn__hapi-mocks": "link:bazel-bin/packages/kbn-hapi-mocks/npm_module_types",
|
||||
"@types/kbn__home-sample-data-card": "link:bazel-bin/packages/home/sample_data_card/npm_module_types",
|
||||
|
|
|
@ -231,6 +231,7 @@ filegroup(
|
|||
"//packages/kbn-ftr-screenshot-filename:build",
|
||||
"//packages/kbn-generate:build",
|
||||
"//packages/kbn-get-repo-files:build",
|
||||
"//packages/kbn-guided-onboarding:build",
|
||||
"//packages/kbn-handlebars:build",
|
||||
"//packages/kbn-hapi-mocks:build",
|
||||
"//packages/kbn-i18n:build",
|
||||
|
@ -569,6 +570,7 @@ filegroup(
|
|||
"//packages/kbn-ftr-screenshot-filename:build_types",
|
||||
"//packages/kbn-generate:build_types",
|
||||
"//packages/kbn-get-repo-files:build_types",
|
||||
"//packages/kbn-guided-onboarding:build_types",
|
||||
"//packages/kbn-handlebars:build_types",
|
||||
"//packages/kbn-hapi-mocks:build_types",
|
||||
"//packages/kbn-i18n:build_types",
|
||||
|
|
152
packages/kbn-guided-onboarding/BUILD.bazel
Normal file
152
packages/kbn-guided-onboarding/BUILD.bazel
Normal file
|
@ -0,0 +1,152 @@
|
|||
load("@npm//@bazel/typescript:index.bzl", "ts_config")
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
|
||||
load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project")
|
||||
|
||||
PKG_DIRNAME = "kbn-guided-onboarding"
|
||||
PKG_REQUIRE_NAME = "@kbn/guided-onboarding"
|
||||
|
||||
SOURCE_FILES = glob(
|
||||
[
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
],
|
||||
exclude = [
|
||||
"**/*.config.js",
|
||||
"**/*.mock.*",
|
||||
"**/*.test.*",
|
||||
"**/*.stories.*",
|
||||
"**/__snapshots__/**",
|
||||
"**/integration_tests/**",
|
||||
"**/mocks/**",
|
||||
"**/scripts/**",
|
||||
"**/storybook/**",
|
||||
"**/test_fixtures/**",
|
||||
"**/test_helpers/**",
|
||||
],
|
||||
)
|
||||
|
||||
SRCS = SOURCE_FILES
|
||||
|
||||
filegroup(
|
||||
name = "srcs",
|
||||
srcs = SRCS,
|
||||
)
|
||||
|
||||
NPM_MODULE_EXTRA_FILES = [
|
||||
"package.json",
|
||||
]
|
||||
|
||||
# In this array place runtime dependencies, including other packages and NPM packages
|
||||
# which must be available for this code to run.
|
||||
#
|
||||
# To reference other packages use:
|
||||
# "//repo/relative/path/to/package"
|
||||
# eg. "//packages/kbn-utils"
|
||||
#
|
||||
# To reference a NPM package use:
|
||||
# "@npm//name-of-package"
|
||||
# eg. "@npm//lodash"
|
||||
RUNTIME_DEPS = [
|
||||
"@npm//@elastic/eui",
|
||||
"@npm//enzyme",
|
||||
"@npm//react",
|
||||
"//packages/kbn-i18n-react",
|
||||
"//packages/kbn-i18n",
|
||||
"//packages/core/http/core-http-browser",
|
||||
"//packages/core/ui-settings/core-ui-settings-browser",
|
||||
]
|
||||
|
||||
# In this array place dependencies necessary to build the types, which will include the
|
||||
# :npm_module_types target of other packages and packages from NPM, including @types/*
|
||||
# packages.
|
||||
#
|
||||
# To reference the types for another package use:
|
||||
# "//repo/relative/path/to/package:npm_module_types"
|
||||
# eg. "//packages/kbn-utils:npm_module_types"
|
||||
#
|
||||
# References to NPM packages work the same as RUNTIME_DEPS
|
||||
TYPES_DEPS = [
|
||||
"@npm//@types/node",
|
||||
"@npm//@types/jest",
|
||||
"@npm//@elastic/eui",
|
||||
"@npm//@types/enzyme",
|
||||
"@npm//@types/react",
|
||||
"//packages/kbn-i18n-react:npm_module_types",
|
||||
"//packages/kbn-i18n:npm_module_types",
|
||||
"//packages/core/http/core-http-browser:npm_module_types",
|
||||
"//packages/core/ui-settings/core-ui-settings-browser:npm_module_types",
|
||||
"//packages/core/application/core-application-browser:npm_module_types",
|
||||
]
|
||||
|
||||
jsts_transpiler(
|
||||
name = "target_node",
|
||||
srcs = SRCS,
|
||||
build_pkg_name = package_name(),
|
||||
)
|
||||
|
||||
jsts_transpiler(
|
||||
name = "target_web",
|
||||
srcs = SRCS,
|
||||
build_pkg_name = package_name(),
|
||||
web = True,
|
||||
additional_args = [
|
||||
"--copy-files",
|
||||
"--quiet"
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
ts_config(
|
||||
name = "tsconfig",
|
||||
src = "tsconfig.json",
|
||||
deps = [
|
||||
"//:tsconfig.base.json",
|
||||
"//:tsconfig.bazel.json",
|
||||
],
|
||||
)
|
||||
|
||||
ts_project(
|
||||
name = "tsc_types",
|
||||
args = ['--pretty'],
|
||||
srcs = SRCS,
|
||||
deps = TYPES_DEPS,
|
||||
declaration = True,
|
||||
declaration_map = True,
|
||||
emit_declaration_only = True,
|
||||
out_dir = "target_types",
|
||||
tsconfig = ":tsconfig",
|
||||
)
|
||||
|
||||
js_library(
|
||||
name = PKG_DIRNAME,
|
||||
srcs = NPM_MODULE_EXTRA_FILES,
|
||||
deps = RUNTIME_DEPS + [":target_node", ":target_web"],
|
||||
package_name = PKG_REQUIRE_NAME,
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
pkg_npm(
|
||||
name = "npm_module",
|
||||
deps = [":" + PKG_DIRNAME],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "build",
|
||||
srcs = [":npm_module"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
pkg_npm_types(
|
||||
name = "npm_module_types",
|
||||
srcs = SRCS,
|
||||
deps = [":tsc_types"],
|
||||
package_name = PKG_REQUIRE_NAME,
|
||||
tsconfig = ":tsconfig",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "build_types",
|
||||
srcs = [":npm_module_types"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
3
packages/kbn-guided-onboarding/README.md
Normal file
3
packages/kbn-guided-onboarding/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# @kbn/guided-onboarding
|
||||
|
||||
Empty package generated by @kbn/generate
|
11
packages/kbn-guided-onboarding/index.ts
Normal file
11
packages/kbn-guided-onboarding/index.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export type { GuideState, GuideId } from './src/types';
|
||||
export { GuideCard, ObservabilityLinkCard } from './src/components/landing_page';
|
||||
export type { UseCase } from './src/components/landing_page';
|
13
packages/kbn-guided-onboarding/jest.config.js
Normal file
13
packages/kbn-guided-onboarding/jest.config.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
preset: '@kbn/test',
|
||||
rootDir: '../..',
|
||||
roots: ['<rootDir>/packages/kbn-guided-onboarding'],
|
||||
};
|
7
packages/kbn-guided-onboarding/kibana.jsonc
Normal file
7
packages/kbn-guided-onboarding/kibana.jsonc
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"type": "shared-common",
|
||||
"id": "@kbn/guided-onboarding",
|
||||
"owner": "@elastic/platform-onboarding",
|
||||
"runtimeDeps": [],
|
||||
"typeDeps": [],
|
||||
}
|
8
packages/kbn-guided-onboarding/package.json
Normal file
8
packages/kbn-guided-onboarding/package.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"name": "@kbn/guided-onboarding",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"main": "./target_node/index.js",
|
||||
"browser": "./target_web/index.js",
|
||||
"license": "SSPL-1.0 OR Elastic License 2.0"
|
||||
}
|
52
packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_card.test.tsx.snap
generated
Normal file
52
packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_card.test.tsx.snap
generated
Normal file
|
@ -0,0 +1,52 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`guide card snapshots should render use case card component for observability 1`] = `
|
||||
<UseCaseCard
|
||||
addBasePath={[MockFunction]}
|
||||
description="Monitor your Kubernetes infrastructure by consolidating your logs and metrics."
|
||||
footer={
|
||||
<GuideCardFooter
|
||||
activateGuide={[MockFunction]}
|
||||
guides={Array []}
|
||||
useCase="observability"
|
||||
/>
|
||||
}
|
||||
isDarkTheme={false}
|
||||
title="Observe my Kubernetes infrastructure"
|
||||
useCase="observability"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`guide card snapshots should render use case card component for search 1`] = `
|
||||
<UseCaseCard
|
||||
addBasePath={[MockFunction]}
|
||||
description="Create a search experience for your websites, applications, workplace content, or anything in between."
|
||||
footer={
|
||||
<GuideCardFooter
|
||||
activateGuide={[MockFunction]}
|
||||
guides={Array []}
|
||||
useCase="search"
|
||||
/>
|
||||
}
|
||||
isDarkTheme={false}
|
||||
title="Search my data"
|
||||
useCase="search"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`guide card snapshots should render use case card component for security 1`] = `
|
||||
<UseCaseCard
|
||||
addBasePath={[MockFunction]}
|
||||
description="Defend your environment against threats by unifying SIEM, endpoint security, and cloud security."
|
||||
footer={
|
||||
<GuideCardFooter
|
||||
activateGuide={[MockFunction]}
|
||||
guides={Array []}
|
||||
useCase="security"
|
||||
/>
|
||||
}
|
||||
isDarkTheme={false}
|
||||
title="Protect my environment"
|
||||
useCase="security"
|
||||
/>
|
||||
`;
|
107
packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_card_footer.test.tsx.snap
generated
Normal file
107
packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_card_footer.test.tsx.snap
generated
Normal file
|
@ -0,0 +1,107 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`guide card footer snapshots should render the footer when the guide has been completed 1`] = `
|
||||
<Fragment>
|
||||
<EuiProgress
|
||||
label="Completed"
|
||||
max={2}
|
||||
size="s"
|
||||
value={1}
|
||||
valueText="1/2 steps"
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="l"
|
||||
/>
|
||||
<div
|
||||
className="eui-textCenter"
|
||||
>
|
||||
<EuiButton
|
||||
data-test-subj="onboarding--guideCard--view--search"
|
||||
fill={true}
|
||||
onClick={[Function]}
|
||||
>
|
||||
View guide
|
||||
</EuiButton>
|
||||
</div>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`guide card footer snapshots should render the footer when the guide has not started yet 1`] = `
|
||||
<div
|
||||
className="eui-textCenter"
|
||||
>
|
||||
<EuiButton
|
||||
data-test-subj="onboarding--guideCard--view--search"
|
||||
fill={true}
|
||||
onClick={[Function]}
|
||||
>
|
||||
View guide
|
||||
</EuiButton>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`guide card footer snapshots should render the footer when the guide is in progress 1`] = `
|
||||
<Fragment>
|
||||
<EuiProgress
|
||||
label="In progress"
|
||||
max={2}
|
||||
size="s"
|
||||
value={1}
|
||||
valueText="1/2 steps"
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="l"
|
||||
/>
|
||||
<div
|
||||
className="eui-textCenter"
|
||||
>
|
||||
<EuiButton
|
||||
data-test-subj="onboarding--guideCard--continue--search"
|
||||
fill={true}
|
||||
onClick={[Function]}
|
||||
>
|
||||
Continue
|
||||
</EuiButton>
|
||||
</div>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`guide card footer snapshots should render the footer when the guide is ready to complete 1`] = `
|
||||
<Fragment>
|
||||
<EuiProgress
|
||||
label="In progress"
|
||||
max={2}
|
||||
size="s"
|
||||
value={1}
|
||||
valueText="1/2 steps"
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="l"
|
||||
/>
|
||||
<div
|
||||
className="eui-textCenter"
|
||||
>
|
||||
<EuiButton
|
||||
data-test-subj="onboarding--guideCard--continue--search"
|
||||
fill={true}
|
||||
onClick={[Function]}
|
||||
>
|
||||
Continue
|
||||
</EuiButton>
|
||||
</div>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`guide card footer snapshots should render the footer when the guided onboarding has not started yet 1`] = `
|
||||
<div
|
||||
className="eui-textCenter"
|
||||
>
|
||||
<EuiButton
|
||||
data-test-subj="onboarding--guideCard--view--search"
|
||||
fill={true}
|
||||
onClick={[Function]}
|
||||
>
|
||||
View guide
|
||||
</EuiButton>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,28 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`observability link card snapshots should render link card for observability 1`] = `
|
||||
<UseCaseCard
|
||||
addBasePath={[MockFunction]}
|
||||
description="Add application, infrastructure, and user data through our pre-built integrations."
|
||||
footer={
|
||||
<EuiFlexGroup
|
||||
justifyContent="center"
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiButton
|
||||
data-test-subj="onboarding--linkCard--observability"
|
||||
fill={true}
|
||||
onClick={[Function]}
|
||||
>
|
||||
View integrations
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
}
|
||||
isDarkTheme={false}
|
||||
title="Observe my data"
|
||||
useCase="observability"
|
||||
/>
|
||||
`;
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { GuideCard, GuideCardProps } from './guide_card';
|
||||
|
||||
const defaultProps: GuideCardProps = {
|
||||
useCase: 'search',
|
||||
guides: [],
|
||||
activateGuide: jest.fn(),
|
||||
isDarkTheme: false,
|
||||
addBasePath: jest.fn(),
|
||||
};
|
||||
|
||||
describe('guide card', () => {
|
||||
describe('snapshots', () => {
|
||||
test('should render use case card component for search', async () => {
|
||||
const component = await shallow(<GuideCard {...defaultProps} useCase="search" />);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
test('should render use case card component for observability', async () => {
|
||||
const component = await shallow(<GuideCard {...defaultProps} useCase="observability" />);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
test('should render use case card component for security', async () => {
|
||||
const component = await shallow(<GuideCard {...defaultProps} useCase="security" />);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { GuideState } from '../../types';
|
||||
import { GuideCardFooter } from './guide_card_footer';
|
||||
import { UseCase, UseCaseCard } from './use_case_card';
|
||||
|
||||
type GuideCardConstants = {
|
||||
[key in UseCase]: {
|
||||
i18nTexts: {
|
||||
title: string;
|
||||
description: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
const constants: GuideCardConstants = {
|
||||
search: {
|
||||
i18nTexts: {
|
||||
title: i18n.translate('guidedOnboardingPackage.gettingStarted.guideCard.search.cardTitle', {
|
||||
defaultMessage: 'Search my data',
|
||||
}),
|
||||
description: i18n.translate(
|
||||
'guidedOnboardingPackage.gettingStarted.guideCard.search.cardDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'Create a search experience for your websites, applications, workplace content, or anything in between.',
|
||||
}
|
||||
),
|
||||
},
|
||||
},
|
||||
observability: {
|
||||
i18nTexts: {
|
||||
title: i18n.translate(
|
||||
'guidedOnboardingPackage.gettingStarted.guideCard.observability.cardTitle',
|
||||
{
|
||||
defaultMessage: 'Observe my Kubernetes infrastructure',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'guidedOnboardingPackage.gettingStarted.guideCard.observability.cardDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'Monitor your Kubernetes infrastructure by consolidating your logs and metrics.',
|
||||
}
|
||||
),
|
||||
},
|
||||
},
|
||||
security: {
|
||||
i18nTexts: {
|
||||
title: i18n.translate('guidedOnboardingPackage.gettingStarted.guideCard.security.cardTitle', {
|
||||
defaultMessage: 'Protect my environment',
|
||||
}),
|
||||
description: i18n.translate(
|
||||
'guidedOnboardingPackage.gettingStarted.guideCard.security.cardDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'Defend your environment against threats by unifying SIEM, endpoint security, and cloud security.',
|
||||
}
|
||||
),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export interface GuideCardProps {
|
||||
useCase: UseCase;
|
||||
guides: GuideState[];
|
||||
activateGuide: (useCase: UseCase, guide?: GuideState) => Promise<void>;
|
||||
isDarkTheme: boolean;
|
||||
addBasePath: (url: string) => string;
|
||||
}
|
||||
export const GuideCard = ({
|
||||
useCase,
|
||||
guides,
|
||||
activateGuide,
|
||||
isDarkTheme,
|
||||
addBasePath,
|
||||
}: GuideCardProps) => {
|
||||
return (
|
||||
<UseCaseCard
|
||||
useCase={useCase}
|
||||
title={constants[useCase].i18nTexts.title}
|
||||
description={constants[useCase].i18nTexts.description}
|
||||
footer={<GuideCardFooter guides={guides} activateGuide={activateGuide} useCase={useCase} />}
|
||||
isDarkTheme={isDarkTheme}
|
||||
addBasePath={addBasePath}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { GuideCardFooter, GuideCardFooterProps } from './guide_card_footer';
|
||||
import { GuideState } from '../../types';
|
||||
|
||||
const defaultProps: GuideCardFooterProps = {
|
||||
guides: [],
|
||||
useCase: 'search',
|
||||
activateGuide: jest.fn(),
|
||||
};
|
||||
|
||||
const searchGuideState: GuideState = {
|
||||
guideId: 'search',
|
||||
status: 'not_started',
|
||||
steps: [
|
||||
{ id: 'add_data', status: 'complete' },
|
||||
{ id: 'browse_docs', status: 'in_progress' },
|
||||
],
|
||||
isActive: true,
|
||||
};
|
||||
describe('guide card footer', () => {
|
||||
describe('snapshots', () => {
|
||||
test('should render the footer when the guided onboarding has not started yet', async () => {
|
||||
const component = await shallow(<GuideCardFooter {...defaultProps} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render the footer when the guide has not started yet', async () => {
|
||||
const component = await shallow(
|
||||
<GuideCardFooter {...defaultProps} guides={[searchGuideState]} />
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render the footer when the guide is in progress', async () => {
|
||||
const component = await shallow(
|
||||
<GuideCardFooter
|
||||
{...defaultProps}
|
||||
guides={[{ ...searchGuideState, status: 'in_progress' }]}
|
||||
/>
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render the footer when the guide is ready to complete', async () => {
|
||||
const component = await shallow(
|
||||
<GuideCardFooter
|
||||
{...defaultProps}
|
||||
guides={[{ ...searchGuideState, status: 'ready_to_complete' }]}
|
||||
/>
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render the footer when the guide has been completed', async () => {
|
||||
const component = await shallow(
|
||||
<GuideCardFooter {...defaultProps} guides={[{ ...searchGuideState, status: 'complete' }]} />
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiButton, EuiProgress, EuiSpacer } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { GuideId, GuideState } from '../../types';
|
||||
import { UseCase } from './use_case_card';
|
||||
|
||||
const viewGuideLabel = i18n.translate(
|
||||
'guidedOnboardingPackage.gettingStarted.guideCard.startGuide.buttonLabel',
|
||||
{
|
||||
defaultMessage: 'View guide',
|
||||
}
|
||||
);
|
||||
|
||||
const continueGuideLabel = i18n.translate(
|
||||
'guidedOnboardingPackage.gettingStarted.guideCard.continueGuide.buttonLabel',
|
||||
{
|
||||
defaultMessage: 'Continue',
|
||||
}
|
||||
);
|
||||
|
||||
const completedLabel = i18n.translate(
|
||||
'guidedOnboardingPackage.gettingStarted.guideCard.progress.completedLabel',
|
||||
{
|
||||
defaultMessage: 'Completed',
|
||||
}
|
||||
);
|
||||
|
||||
const inProgressLabel = i18n.translate(
|
||||
'guidedOnboardingPackage.gettingStarted.guideCard.progress.inProgressLabel',
|
||||
{
|
||||
defaultMessage: 'In progress',
|
||||
}
|
||||
);
|
||||
|
||||
export interface GuideCardFooterProps {
|
||||
guides: GuideState[];
|
||||
useCase: UseCase;
|
||||
activateGuide: (useCase: UseCase, guideState?: GuideState) => void;
|
||||
}
|
||||
export const GuideCardFooter = ({ guides, useCase, activateGuide }: GuideCardFooterProps) => {
|
||||
const guideState = guides.find((guide) => guide.guideId === (useCase as GuideId));
|
||||
const viewGuideButton = (
|
||||
<div className="eui-textCenter">
|
||||
<EuiButton
|
||||
// Used for FS tracking
|
||||
data-test-subj={`onboarding--guideCard--view--${useCase}`}
|
||||
fill
|
||||
onClick={() => activateGuide(useCase, guideState)}
|
||||
>
|
||||
{viewGuideLabel}
|
||||
</EuiButton>
|
||||
</div>
|
||||
);
|
||||
// guide has not started yet
|
||||
if (!guideState || guideState.status === 'not_started') {
|
||||
return viewGuideButton;
|
||||
}
|
||||
const { status, steps } = guideState;
|
||||
const numberSteps = steps.length;
|
||||
const numberCompleteSteps = steps.filter((step) => step.status === 'complete').length;
|
||||
const stepsLabel = i18n.translate('guidedOnboardingPackage.gettingStarted.guideCard.stepsLabel', {
|
||||
defaultMessage: '{progress} steps',
|
||||
values: {
|
||||
progress: `${numberCompleteSteps}/${numberSteps}`,
|
||||
},
|
||||
});
|
||||
// guide is completed
|
||||
if (status === 'complete') {
|
||||
return (
|
||||
<>
|
||||
<EuiProgress
|
||||
valueText={stepsLabel}
|
||||
value={numberCompleteSteps}
|
||||
max={numberSteps}
|
||||
size="s"
|
||||
label={completedLabel}
|
||||
/>
|
||||
<EuiSpacer size="l" />
|
||||
{viewGuideButton}
|
||||
</>
|
||||
);
|
||||
}
|
||||
// guide is in progress or ready to complete
|
||||
return (
|
||||
<>
|
||||
<EuiProgress
|
||||
valueText={stepsLabel}
|
||||
value={numberCompleteSteps}
|
||||
max={numberSteps}
|
||||
size="s"
|
||||
label={inProgressLabel}
|
||||
/>
|
||||
<EuiSpacer size="l" />
|
||||
<div className="eui-textCenter">
|
||||
<EuiButton
|
||||
// Used for FS tracking
|
||||
data-test-subj={`onboarding--guideCard--continue--${useCase}`}
|
||||
fill
|
||||
onClick={() => activateGuide(useCase, guideState)}
|
||||
>
|
||||
{continueGuideLabel}
|
||||
</EuiButton>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { GuideCard } from './guide_card';
|
||||
export { ObservabilityLinkCard } from './observability_link_card';
|
||||
export type { UseCase } from './use_case_card';
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { ObservabilityLinkCard } from './observability_link_card';
|
||||
|
||||
const defaultProps = {
|
||||
navigateToApp: jest.fn(),
|
||||
isDarkTheme: false,
|
||||
addBasePath: jest.fn(),
|
||||
};
|
||||
|
||||
describe('observability link card', () => {
|
||||
describe('snapshots', () => {
|
||||
test('should render link card for observability', async () => {
|
||||
const component = await shallow(<ObservabilityLinkCard {...defaultProps} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import type { NavigateToAppOptions } from '@kbn/core-application-browser';
|
||||
import { UseCaseCard } from './use_case_card';
|
||||
|
||||
interface LinkCardConstants {
|
||||
observability: {
|
||||
i18nTexts: {
|
||||
title: string;
|
||||
description: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const constants: LinkCardConstants = {
|
||||
observability: {
|
||||
i18nTexts: {
|
||||
title: i18n.translate(
|
||||
'guidedOnboardingPackage.gettingStarted.linkCard.observability.cardTitle',
|
||||
{
|
||||
defaultMessage: 'Observe my data',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'guidedOnboardingPackage.gettingStarted.linkCard.observability.cardDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'Add application, infrastructure, and user data through our pre-built integrations.',
|
||||
}
|
||||
),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const ObservabilityLinkCard = ({
|
||||
navigateToApp,
|
||||
isDarkTheme,
|
||||
addBasePath,
|
||||
}: {
|
||||
navigateToApp: (appId: string, options?: NavigateToAppOptions) => Promise<void>;
|
||||
isDarkTheme: boolean;
|
||||
addBasePath: (url: string) => string;
|
||||
}) => {
|
||||
const navigateToIntegrations = () => {
|
||||
navigateToApp('integrations', {
|
||||
path: '/browse/infrastructure',
|
||||
});
|
||||
};
|
||||
const button = (
|
||||
<EuiFlexGroup justifyContent="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
// Used for FS tracking
|
||||
data-test-subj={`onboarding--linkCard--observability`}
|
||||
fill
|
||||
onClick={navigateToIntegrations}
|
||||
>
|
||||
{i18n.translate('guidedOnboardingPackage.gettingStarted.linkCard.buttonLabel', {
|
||||
defaultMessage: 'View integrations',
|
||||
})}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
return (
|
||||
<UseCaseCard
|
||||
useCase={'observability'}
|
||||
title={constants.observability.i18nTexts.title}
|
||||
description={constants.observability.i18nTexts.description}
|
||||
footer={button}
|
||||
isDarkTheme={isDarkTheme}
|
||||
addBasePath={addBasePath}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React, { ReactNode } from 'react';
|
||||
import { EuiCard, EuiText, EuiImage } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { GuideId } from '../../types';
|
||||
|
||||
type UseCaseConstants = {
|
||||
[key in UseCase]: {
|
||||
logAltText: string;
|
||||
betaBadgeLabel: string;
|
||||
};
|
||||
};
|
||||
const constants: UseCaseConstants = {
|
||||
search: {
|
||||
logAltText: i18n.translate('guidedOnboardingPackage.gettingStarted.search.iconName', {
|
||||
defaultMessage: 'Enterprise Search logo',
|
||||
}),
|
||||
betaBadgeLabel: i18n.translate('guidedOnboardingPackage.gettingStarted.search.betaBadgeLabel', {
|
||||
defaultMessage: 'search',
|
||||
}),
|
||||
},
|
||||
observability: {
|
||||
logAltText: i18n.translate('guidedOnboardingPackage.gettingStarted.observability.iconName', {
|
||||
defaultMessage: 'Observability logo',
|
||||
}),
|
||||
betaBadgeLabel: i18n.translate(
|
||||
'guidedOnboardingPackage.gettingStarted.observability.betaBadgeLabel',
|
||||
{
|
||||
defaultMessage: 'observe',
|
||||
}
|
||||
),
|
||||
},
|
||||
security: {
|
||||
logAltText: i18n.translate('guidedOnboardingPackage.gettingStarted.security.iconName', {
|
||||
defaultMessage: 'Security logo',
|
||||
}),
|
||||
betaBadgeLabel: i18n.translate(
|
||||
'guidedOnboardingPackage.gettingStarted.security.betaBadgeLabel',
|
||||
{
|
||||
defaultMessage: 'security',
|
||||
}
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
export type UseCase = 'search' | 'observability' | 'security';
|
||||
|
||||
export interface UseCaseCardProps {
|
||||
useCase: GuideId;
|
||||
title: string;
|
||||
description: string;
|
||||
footer: ReactNode;
|
||||
isDarkTheme: boolean;
|
||||
addBasePath: (url: string) => string;
|
||||
}
|
||||
|
||||
export const UseCaseCard = ({
|
||||
useCase,
|
||||
title,
|
||||
description,
|
||||
footer,
|
||||
isDarkTheme,
|
||||
addBasePath,
|
||||
}: UseCaseCardProps) => {
|
||||
const getImageUrl = (imageName: UseCase) => {
|
||||
const imagePath = `/plugins/home/assets/solution_logos/${imageName}${
|
||||
isDarkTheme ? '_dark' : ''
|
||||
}.png`;
|
||||
|
||||
return addBasePath(imagePath);
|
||||
};
|
||||
|
||||
const titleElement = (
|
||||
<EuiText textAlign="center">
|
||||
<h4>
|
||||
<strong>{title}</strong>
|
||||
</h4>
|
||||
</EuiText>
|
||||
);
|
||||
const descriptionElement = (
|
||||
<EuiText size="s" textAlign="center">
|
||||
<p>{description}</p>
|
||||
</EuiText>
|
||||
);
|
||||
return (
|
||||
<EuiCard
|
||||
display="subdued"
|
||||
textAlign="left"
|
||||
image={<EuiImage src={getImageUrl(useCase)} alt={constants[useCase].logAltText} />}
|
||||
title={titleElement}
|
||||
description={descriptionElement}
|
||||
footer={footer}
|
||||
betaBadgeProps={{
|
||||
label: constants[useCase].betaBadgeLabel,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -14,13 +14,21 @@ export type SearchStepIds = 'add_data' | 'browse_docs' | 'search_experience';
|
|||
|
||||
export type GuideStepIds = ObservabilityStepIds | SecurityStepIds | SearchStepIds;
|
||||
|
||||
export interface GuideState {
|
||||
guideId: GuideId;
|
||||
status: GuideStatus;
|
||||
isActive?: boolean; // Drives the current guide shown in the dropdown panel
|
||||
steps: GuideStep[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Allowed states for a guide:
|
||||
* in_progress: Guide has been started
|
||||
* not_started: Guide has not been started
|
||||
* in_progress: At least one step in the guide has been started
|
||||
* ready_to_complete: All steps have been completed, but the "Continue using Elastic" button has not been clicked
|
||||
* complete: All steps and the guide have been completed
|
||||
*/
|
||||
export type GuideStatus = 'in_progress' | 'ready_to_complete' | 'complete';
|
||||
export type GuideStatus = 'not_started' | 'in_progress' | 'ready_to_complete' | 'complete';
|
||||
|
||||
/**
|
||||
* Allowed states for each step in a guide:
|
||||
|
@ -36,10 +44,3 @@ export interface GuideStep {
|
|||
id: GuideStepIds;
|
||||
status: StepStatus;
|
||||
}
|
||||
|
||||
export interface GuideState {
|
||||
guideId: GuideId;
|
||||
status: GuideStatus;
|
||||
isActive?: boolean; // Drives the current guide shown in the dropdown panel
|
||||
steps: GuideStep[];
|
||||
}
|
18
packages/kbn-guided-onboarding/tsconfig.json
Normal file
18
packages/kbn-guided-onboarding/tsconfig.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"extends": "../../tsconfig.bazel.json",
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"outDir": "target_types",
|
||||
"stripInternal": false,
|
||||
"types": [
|
||||
"jest",
|
||||
"node",
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.tsx"
|
||||
]
|
||||
}
|
|
@ -9,7 +9,8 @@
|
|||
import React from 'react';
|
||||
import { EuiButton } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { GuideState } from '../../common/types';
|
||||
import type { GuideState } from '@kbn/guided-onboarding';
|
||||
|
||||
import { getStepConfig } from '../services/helpers';
|
||||
import { GuideButtonPopover } from './guide_button_popover';
|
||||
|
||||
|
|
|
@ -12,9 +12,9 @@ import React from 'react';
|
|||
import { applicationServiceMock } from '@kbn/core-application-browser-mocks';
|
||||
import { httpServiceMock } from '@kbn/core/public/mocks';
|
||||
import { HttpSetup } from '@kbn/core/public';
|
||||
import type { GuideState } from '@kbn/guided-onboarding';
|
||||
|
||||
import { guidesConfig } from '../constants/guides_config';
|
||||
import type { GuideState } from '../../common/types';
|
||||
import { apiService } from '../services/api';
|
||||
import { GuidePanel } from './guide_panel';
|
||||
import { registerTestBed, TestBed } from '@kbn/test-jest-helpers';
|
||||
|
|
|
@ -30,8 +30,8 @@ import { i18n } from '@kbn/i18n';
|
|||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
import { ApplicationStart } from '@kbn/core/public';
|
||||
import type { GuideState, GuideStep as GuideStepStatus } from '@kbn/guided-onboarding';
|
||||
|
||||
import type { GuideState, GuideStep as GuideStepStatus } from '../../common/types';
|
||||
import type { GuideConfig, StepConfig } from '../types';
|
||||
|
||||
import type { ApiService } from '../services/api';
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import { EuiThemeComputed } from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
import { StepStatus } from '../../common/types';
|
||||
import type { StepStatus } from '@kbn/guided-onboarding';
|
||||
|
||||
export const getGuidePanelStepStyles = (euiTheme: EuiThemeComputed, stepStatus: StepStatus) => ({
|
||||
stepNumber: css`
|
||||
|
|
|
@ -21,7 +21,7 @@ import {
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import type { StepStatus } from '../../common/types';
|
||||
import type { StepStatus } from '@kbn/guided-onboarding';
|
||||
import type { StepConfig } from '../types';
|
||||
import { getGuidePanelStepStyles } from './guide_panel_step.styles';
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import React, { useState } from 'react';
|
|||
|
||||
import { EuiText, EuiConfirmModal } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { GuideState } from '../../common/types';
|
||||
import type { GuideState } from '@kbn/guided-onboarding';
|
||||
import { apiService } from '../services/api';
|
||||
|
||||
interface QuitGuideModalProps {
|
||||
|
|
|
@ -12,8 +12,10 @@ import { GuidedOnboardingPlugin } from './plugin';
|
|||
export function plugin(ctx: PluginInitializerContext) {
|
||||
return new GuidedOnboardingPlugin(ctx);
|
||||
}
|
||||
export type { GuidedOnboardingPluginSetup, GuidedOnboardingPluginStart } from './types';
|
||||
|
||||
export type { GuideId, GuideStepIds, GuideState, GuideStep } from '../common/types';
|
||||
export type {
|
||||
GuidedOnboardingPluginSetup,
|
||||
GuidedOnboardingPluginStart,
|
||||
GuidedOnboardingApi,
|
||||
} from './types';
|
||||
|
||||
export { guidesConfig } from './constants/guides_config';
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { GuideState } from '../../common/types';
|
||||
import type { GuideState } from '@kbn/guided-onboarding';
|
||||
|
||||
export const searchAddDataActiveState: GuideState = {
|
||||
guideId: 'search',
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
import { HttpSetup } from '@kbn/core/public';
|
||||
import { httpServiceMock } from '@kbn/core/public/mocks';
|
||||
import type { GuideState } from '@kbn/guided-onboarding';
|
||||
import { firstValueFrom, Subscription } from 'rxjs';
|
||||
|
||||
import { API_BASE_PATH } from '../../common/constants';
|
||||
import { guidesConfig } from '../constants/guides_config';
|
||||
import type { GuideState } from '../../common/types';
|
||||
import { ApiService } from './api';
|
||||
import {
|
||||
noGuideActiveState,
|
||||
|
@ -57,7 +57,7 @@ describe('GuidedOnboarding ApiService', () => {
|
|||
});
|
||||
|
||||
it('broadcasts the updated state', async () => {
|
||||
await apiService.activateGuide(searchGuide);
|
||||
await apiService.activateGuide(searchGuide, searchAddDataActiveState);
|
||||
|
||||
const state = await firstValueFrom(apiService.fetchActiveGuideState$());
|
||||
expect(state).toEqual(searchAddDataActiveState);
|
||||
|
@ -151,7 +151,7 @@ describe('GuidedOnboarding ApiService', () => {
|
|||
expect(httpClient.put).toHaveBeenCalledWith(`${API_BASE_PATH}/state`, {
|
||||
body: JSON.stringify({
|
||||
isActive: true,
|
||||
status: 'in_progress',
|
||||
status: 'not_started',
|
||||
steps: [
|
||||
{
|
||||
id: 'add_data',
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import { HttpSetup } from '@kbn/core/public';
|
||||
import { BehaviorSubject, map, from, concatMap, of, Observable, firstValueFrom } from 'rxjs';
|
||||
import type { GuideState, GuideId, GuideStep, GuideStepIds } from '@kbn/guided-onboarding';
|
||||
|
||||
import { GuidedOnboardingApi } from '../types';
|
||||
import {
|
||||
|
@ -21,7 +22,6 @@ import {
|
|||
isStepReadyToComplete,
|
||||
} from './helpers';
|
||||
import { API_BASE_PATH } from '../../common/constants';
|
||||
import type { GuideState, GuideId, GuideStep, GuideStepIds } from '../../common/types';
|
||||
|
||||
export class ApiService implements GuidedOnboardingApi {
|
||||
private client: HttpSetup | undefined;
|
||||
|
@ -148,7 +148,7 @@ export class ApiService implements GuidedOnboardingApi {
|
|||
|
||||
const updatedGuide: GuideState = {
|
||||
isActive: true,
|
||||
status: 'in_progress',
|
||||
status: 'not_started',
|
||||
steps: updatedSteps,
|
||||
guideId,
|
||||
};
|
||||
|
|
|
@ -6,10 +6,9 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { GuideId, GuideState, GuideStepIds } from '../../common/types';
|
||||
import type { GuideId, GuideStepIds, GuideState, GuideStep } from '@kbn/guided-onboarding';
|
||||
import { guidesConfig } from '../constants/guides_config';
|
||||
import { GuideConfig, StepConfig } from '../types';
|
||||
import { GuideStep } from '../../common/types';
|
||||
|
||||
export const getGuideConfig = (guideId?: GuideId): GuideConfig | undefined => {
|
||||
if (guideId && Object.keys(guidesConfig).includes(guideId)) {
|
||||
|
|
|
@ -7,9 +7,8 @@
|
|||
*/
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public';
|
||||
import { HttpSetup } from '@kbn/core/public';
|
||||
import { GuideId, GuideState, GuideStepIds, StepStatus } from '../common/types';
|
||||
import type { GuideState, GuideId, GuideStepIds, StepStatus } from '@kbn/guided-onboarding';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface GuidedOnboardingPluginSetup {}
|
||||
|
@ -18,10 +17,6 @@ export interface GuidedOnboardingPluginStart {
|
|||
guidedOnboardingApi?: GuidedOnboardingApi;
|
||||
}
|
||||
|
||||
export interface AppPluginStartDependencies {
|
||||
navigation: NavigationPublicPluginStart;
|
||||
}
|
||||
|
||||
export interface ClientConfigType {
|
||||
ui: boolean;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import type { IRouter, SavedObjectsClient } from '@kbn/core/server';
|
||||
import type { GuideState } from '@kbn/guided-onboarding';
|
||||
import { API_BASE_PATH } from '../../common/constants';
|
||||
import type { GuideState } from '../../common/types';
|
||||
import { guidedSetupSavedObjectsType } from '../saved_objects';
|
||||
|
||||
const findGuideById = async (savedObjectsClient: SavedObjectsClient, guideId: string) => {
|
||||
|
|
|
@ -12,9 +12,6 @@
|
|||
{
|
||||
"path": "../../core/tsconfig.json"
|
||||
},
|
||||
{
|
||||
"path": "../navigation/tsconfig.json"
|
||||
},
|
||||
{
|
||||
"path": "../kibana_react/tsconfig.json"
|
||||
},
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
"server": true,
|
||||
"ui": true,
|
||||
"requiredPlugins": ["dataViews", "share", "urlForwarding"],
|
||||
"optionalPlugins": ["usageCollection", "customIntegrations", "cloud"],
|
||||
"optionalPlugins": ["usageCollection", "customIntegrations", "cloud", "guidedOnboarding"],
|
||||
"requiredBundles": ["kibanaReact"]
|
||||
}
|
||||
|
|
|
@ -35,12 +35,11 @@ exports[`getting started should render getting started component 1`] = `
|
|||
size="s"
|
||||
/>
|
||||
<EuiText
|
||||
color="subdued"
|
||||
size="s"
|
||||
size="m"
|
||||
textAlign="center"
|
||||
>
|
||||
<p>
|
||||
Select a starting point for a quick tour of how Elastic can help you do even more with your data.
|
||||
Select a guide to help you make the most of your data.
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer
|
||||
|
@ -50,21 +49,40 @@ exports[`getting started should render getting started component 1`] = `
|
|||
size="xxl"
|
||||
/>
|
||||
<EuiFlexGrid
|
||||
columns={3}
|
||||
gutterSize="xl"
|
||||
columns={4}
|
||||
gutterSize="l"
|
||||
>
|
||||
<EuiFlexItem>
|
||||
<UseCaseCard
|
||||
<GuideCard
|
||||
activateGuide={[Function]}
|
||||
addBasePath={[MockFunction]}
|
||||
guides={Array []}
|
||||
isDarkTheme={false}
|
||||
useCase="search"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<UseCaseCard
|
||||
<GuideCard
|
||||
activateGuide={[Function]}
|
||||
addBasePath={[MockFunction]}
|
||||
guides={Array []}
|
||||
isDarkTheme={false}
|
||||
useCase="observability"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<UseCaseCard
|
||||
<ObservabilityLinkCard
|
||||
addBasePath={[MockFunction]}
|
||||
isDarkTheme={false}
|
||||
navigateToApp={[MockFunction]}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<GuideCard
|
||||
activateGuide={[Function]}
|
||||
addBasePath={[MockFunction]}
|
||||
guides={Array []}
|
||||
isDarkTheme={false}
|
||||
useCase="security"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
|
@ -79,7 +97,7 @@ exports[`getting started should render getting started component 1`] = `
|
|||
data-test-subj="onboarding--skipUseCaseTourLink"
|
||||
onClick={[Function]}
|
||||
>
|
||||
No thanks, I’ll explore on my own.
|
||||
I’d like to do something else (skip)
|
||||
</EuiLink>
|
||||
</div>
|
||||
</EuiPanel>
|
||||
|
|
|
@ -1,109 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`use case card should render use case card component for observability 1`] = `
|
||||
<EuiCard
|
||||
data-test-subj="onboarding--observabilityUseCaseCard"
|
||||
description={
|
||||
<EuiText
|
||||
color="subdued"
|
||||
size="xs"
|
||||
>
|
||||
<p>
|
||||
Get end-to-end observability into your environments by consolidating your logs, metrics, and traces.
|
||||
</p>
|
||||
</EuiText>
|
||||
}
|
||||
display="subdued"
|
||||
image={
|
||||
<EuiImage
|
||||
alt="Observability logo"
|
||||
src="/plugins/home/assets/solution_logos/observability.png"
|
||||
/>
|
||||
}
|
||||
onClick={[Function]}
|
||||
textAlign="left"
|
||||
title={
|
||||
<EuiTitle
|
||||
size="xs"
|
||||
>
|
||||
<h4>
|
||||
<strong>
|
||||
Monitor my environments
|
||||
</strong>
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`use case card should render use case card component for search 1`] = `
|
||||
<EuiCard
|
||||
data-test-subj="onboarding--searchUseCaseCard"
|
||||
description={
|
||||
<EuiText
|
||||
color="subdued"
|
||||
size="xs"
|
||||
>
|
||||
<p>
|
||||
Create a finely-tuned search experience for your websites, applications, workplace content, and more.
|
||||
</p>
|
||||
</EuiText>
|
||||
}
|
||||
display="subdued"
|
||||
image={
|
||||
<EuiImage
|
||||
alt="Enterprise Search logo"
|
||||
src="/plugins/home/assets/solution_logos/search.png"
|
||||
/>
|
||||
}
|
||||
onClick={[Function]}
|
||||
textAlign="left"
|
||||
title={
|
||||
<EuiTitle
|
||||
size="xs"
|
||||
>
|
||||
<h4>
|
||||
<strong>
|
||||
Search my data
|
||||
</strong>
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`use case card should render use case card component for security 1`] = `
|
||||
<EuiCard
|
||||
data-test-subj="onboarding--securityUseCaseCard"
|
||||
description={
|
||||
<EuiText
|
||||
color="subdued"
|
||||
size="xs"
|
||||
>
|
||||
<p>
|
||||
Protect your environment against threats by unifying SIEM, endpoint security, and cloud security in one place.
|
||||
</p>
|
||||
</EuiText>
|
||||
}
|
||||
display="subdued"
|
||||
image={
|
||||
<EuiImage
|
||||
alt="Security logo"
|
||||
src="/plugins/home/assets/solution_logos/security.png"
|
||||
/>
|
||||
}
|
||||
onClick={[Function]}
|
||||
textAlign="left"
|
||||
title={
|
||||
<EuiTitle
|
||||
size="xs"
|
||||
>
|
||||
<h4>
|
||||
<strong>
|
||||
Protect my environment
|
||||
</strong>
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
}
|
||||
/>
|
||||
`;
|
|
@ -31,6 +31,9 @@ jest.mock('../../kibana_services', () => {
|
|||
prepend: jest.fn(),
|
||||
},
|
||||
},
|
||||
guidedOnboardingService: {
|
||||
fetchAllGuidesState: jest.fn(),
|
||||
},
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import {
|
||||
EuiFlexGrid,
|
||||
EuiFlexItem,
|
||||
|
@ -24,28 +24,30 @@ import { css } from '@emotion/react';
|
|||
import { METRIC_TYPE } from '@kbn/analytics';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
|
||||
import type { GuideState, GuideId, UseCase } from '@kbn/guided-onboarding';
|
||||
import { GuideCard, ObservabilityLinkCard } from '@kbn/guided-onboarding';
|
||||
|
||||
import { getServices } from '../../kibana_services';
|
||||
import { KEY_ENABLE_WELCOME } from '../home';
|
||||
import { UseCaseCard } from './use_case_card';
|
||||
|
||||
const homeBreadcrumb = i18n.translate('home.breadcrumbs.homeTitle', { defaultMessage: 'Home' });
|
||||
const gettingStartedBreadcrumb = i18n.translate('home.breadcrumbs.gettingStartedTitle', {
|
||||
defaultMessage: 'Getting Started',
|
||||
defaultMessage: 'Guided setup',
|
||||
});
|
||||
const title = i18n.translate('home.guidedOnboarding.gettingStarted.useCaseSelectionTitle', {
|
||||
defaultMessage: 'What would you like to do first?',
|
||||
});
|
||||
const subtitle = i18n.translate('home.guidedOnboarding.gettingStarted.useCaseSelectionSubtitle', {
|
||||
defaultMessage:
|
||||
'Select a starting point for a quick tour of how Elastic can help you do even more with your data.',
|
||||
defaultMessage: 'Select a guide to help you make the most of your data.',
|
||||
});
|
||||
const skipText = i18n.translate('home.guidedOnboarding.gettingStarted.skip.buttonLabel', {
|
||||
defaultMessage: `No thanks, I’ll explore on my own.`,
|
||||
defaultMessage: `I’d like to do something else (skip)`,
|
||||
});
|
||||
|
||||
export const GettingStarted = () => {
|
||||
const { application, trackUiMetric, chrome } = getServices();
|
||||
const { application, trackUiMetric, chrome, guidedOnboardingService, http, uiSettings } =
|
||||
getServices();
|
||||
const [guidesState, setGuidesState] = useState<GuideState[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
chrome.setBreadcrumbs([
|
||||
|
@ -63,6 +65,17 @@ export const GettingStarted = () => {
|
|||
]);
|
||||
}, [chrome, trackUiMetric]);
|
||||
|
||||
const fetchGuidesState = useCallback(async () => {
|
||||
const allGuides = await guidedOnboardingService?.fetchAllGuidesState();
|
||||
if (allGuides) {
|
||||
setGuidesState(allGuides.state);
|
||||
}
|
||||
}, [guidedOnboardingService]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchGuidesState();
|
||||
}, [fetchGuidesState]);
|
||||
|
||||
const onSkip = () => {
|
||||
trackUiMetric(METRIC_TYPE.CLICK, 'guided_onboarding__skipped');
|
||||
// disable welcome screen on the home page
|
||||
|
@ -73,6 +86,12 @@ export const GettingStarted = () => {
|
|||
const paddingCss = css`
|
||||
padding: calc(${euiTheme.size.base}*3) calc(${euiTheme.size.base}*4);
|
||||
`;
|
||||
|
||||
const isDarkTheme = uiSettings.get<boolean>('theme:darkMode');
|
||||
const activateGuide = async (useCase: UseCase, guideState?: GuideState) => {
|
||||
await guidedOnboardingService?.activateGuide(useCase as GuideId, guideState);
|
||||
// TODO error handling https://github.com/elastic/kibana/issues/139798
|
||||
};
|
||||
return (
|
||||
<KibanaPageTemplate panelled={false} grow>
|
||||
<EuiPageTemplate.Section alignment="center">
|
||||
|
@ -81,21 +100,36 @@ export const GettingStarted = () => {
|
|||
<h1>{title}</h1>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiText color="subdued" size="s" textAlign="center">
|
||||
<EuiText size="m" textAlign="center">
|
||||
<p>{subtitle}</p>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiSpacer size="xxl" />
|
||||
<EuiFlexGrid columns={3} gutterSize="xl">
|
||||
<EuiFlexItem>
|
||||
<UseCaseCard useCase="search" />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<UseCaseCard useCase="observability" />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<UseCaseCard useCase="security" />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexGrid columns={4} gutterSize="l">
|
||||
{['search', 'observability', 'observabilityLink', 'security'].map((useCase) => {
|
||||
if (useCase === 'observabilityLink') {
|
||||
return (
|
||||
<EuiFlexItem>
|
||||
<ObservabilityLinkCard
|
||||
navigateToApp={application.navigateToApp}
|
||||
isDarkTheme={isDarkTheme}
|
||||
addBasePath={http.basePath.prepend}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<EuiFlexItem>
|
||||
<GuideCard
|
||||
useCase={useCase as UseCase}
|
||||
guides={guidesState}
|
||||
activateGuide={activateGuide}
|
||||
isDarkTheme={isDarkTheme}
|
||||
addBasePath={http.basePath.prepend}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
})}
|
||||
</EuiFlexGrid>
|
||||
<EuiSpacer />
|
||||
<EuiHorizontalRule />
|
||||
|
|
|
@ -1,42 +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
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { UseCaseCard } from './use_case_card';
|
||||
|
||||
jest.mock('../../kibana_services', () => {
|
||||
const { applicationServiceMock, uiSettingsServiceMock, httpServiceMock } =
|
||||
jest.requireActual('@kbn/core/public/mocks');
|
||||
return {
|
||||
getServices: () => ({
|
||||
application: applicationServiceMock.createStartContract(),
|
||||
trackUiMetric: jest.fn(),
|
||||
uiSettings: uiSettingsServiceMock.createStartContract(),
|
||||
http: httpServiceMock.createStartContract(),
|
||||
}),
|
||||
};
|
||||
});
|
||||
describe('use case card', () => {
|
||||
test('should render use case card component for search', async () => {
|
||||
const component = await shallow(<UseCaseCard useCase="search" />);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
test('should render use case card component for observability', async () => {
|
||||
const component = await shallow(<UseCaseCard useCase="observability" />);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
test('should render use case card component for security', async () => {
|
||||
const component = await shallow(<UseCaseCard useCase="security" />);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -1,149 +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
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiCard, EuiText, EuiTitle, EuiImage } from '@elastic/eui';
|
||||
|
||||
import { METRIC_TYPE } from '@kbn/analytics';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { getServices } from '../../kibana_services';
|
||||
|
||||
type UseCaseConstants = {
|
||||
[key in UseCase]: {
|
||||
i18nTexts: {
|
||||
title: string;
|
||||
description: string;
|
||||
};
|
||||
logo: {
|
||||
altText: string;
|
||||
};
|
||||
navigateOptions: {
|
||||
appId: string;
|
||||
path?: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
const constants: UseCaseConstants = {
|
||||
search: {
|
||||
i18nTexts: {
|
||||
title: i18n.translate('home.guidedOnboarding.gettingStarted.search.cardTitle', {
|
||||
defaultMessage: 'Search my data',
|
||||
}),
|
||||
description: i18n.translate('home.guidedOnboarding.gettingStarted.search.cardDescription', {
|
||||
defaultMessage:
|
||||
'Create a finely-tuned search experience for your websites, applications, workplace content, and more.',
|
||||
}),
|
||||
},
|
||||
logo: {
|
||||
altText: i18n.translate('home.guidedOnboarding.gettingStarted.search.iconName', {
|
||||
defaultMessage: 'Enterprise Search logo',
|
||||
}),
|
||||
},
|
||||
navigateOptions: {
|
||||
appId: 'enterpriseSearch',
|
||||
// when navigating to ent search, do not provide path
|
||||
},
|
||||
},
|
||||
observability: {
|
||||
i18nTexts: {
|
||||
title: i18n.translate('home.guidedOnboarding.gettingStarted.observability.cardTitle', {
|
||||
defaultMessage: 'Monitor my environments',
|
||||
}),
|
||||
description: i18n.translate(
|
||||
'home.guidedOnboarding.gettingStarted.observability.cardDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'Get end-to-end observability into your environments by consolidating your logs, metrics, and traces.',
|
||||
}
|
||||
),
|
||||
},
|
||||
logo: {
|
||||
altText: i18n.translate('home.guidedOnboarding.gettingStarted.observability.iconName', {
|
||||
defaultMessage: 'Observability logo',
|
||||
}),
|
||||
},
|
||||
navigateOptions: {
|
||||
appId: 'observability',
|
||||
path: '/overview',
|
||||
},
|
||||
},
|
||||
security: {
|
||||
i18nTexts: {
|
||||
title: i18n.translate('home.guidedOnboarding.gettingStarted.security.cardTitle', {
|
||||
defaultMessage: 'Protect my environment',
|
||||
}),
|
||||
description: i18n.translate('home.guidedOnboarding.gettingStarted.security.cardDescription', {
|
||||
defaultMessage:
|
||||
'Protect your environment against threats by unifying SIEM, endpoint security, and cloud security in one place.',
|
||||
}),
|
||||
},
|
||||
logo: {
|
||||
altText: i18n.translate('home.guidedOnboarding.gettingStarted.security.iconName', {
|
||||
defaultMessage: 'Security logo',
|
||||
}),
|
||||
},
|
||||
navigateOptions: {
|
||||
appId: 'securitySolutionUI',
|
||||
path: '/overview',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export type UseCase = 'search' | 'observability' | 'security';
|
||||
export interface UseCaseProps {
|
||||
useCase: UseCase;
|
||||
}
|
||||
|
||||
export const UseCaseCard = ({ useCase }: UseCaseProps) => {
|
||||
const { application, trackUiMetric, uiSettings, http } = getServices();
|
||||
|
||||
const isDarkTheme = uiSettings.get('theme:darkMode');
|
||||
|
||||
const getImageUrl = (imageName: UseCase) => {
|
||||
const imagePath = `/plugins/home/assets/solution_logos/${imageName}${
|
||||
isDarkTheme ? '_dark' : ''
|
||||
}.png`;
|
||||
|
||||
return http.basePath.prepend(imagePath);
|
||||
};
|
||||
|
||||
const onUseCaseSelection = () => {
|
||||
trackUiMetric(METRIC_TYPE.CLICK, `guided_onboarding__use_case__${useCase}`);
|
||||
|
||||
localStorage.setItem(`guidedOnboarding.${useCase}.tourActive`, JSON.stringify(true));
|
||||
application.navigateToApp(constants[useCase].navigateOptions.appId, {
|
||||
path: constants[useCase].navigateOptions.path,
|
||||
});
|
||||
};
|
||||
|
||||
const title = (
|
||||
<EuiTitle size="xs">
|
||||
<h4>
|
||||
<strong>{constants[useCase].i18nTexts.title}</strong>
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
);
|
||||
const description = (
|
||||
<EuiText color="subdued" size="xs">
|
||||
<p>{constants[useCase].i18nTexts.description}</p>
|
||||
</EuiText>
|
||||
);
|
||||
return (
|
||||
<EuiCard
|
||||
display="subdued"
|
||||
textAlign="left"
|
||||
image={<EuiImage src={getImageUrl(useCase)} alt={constants[useCase].logo.altText} />}
|
||||
title={title}
|
||||
description={description}
|
||||
// Used for FS tracking
|
||||
data-test-subj={`onboarding--${useCase}UseCaseCard`}
|
||||
onClick={onUseCaseSelection}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -20,6 +20,7 @@ import { UiCounterMetricType } from '@kbn/analytics';
|
|||
import { UrlForwardingStart } from '@kbn/url-forwarding-plugin/public';
|
||||
import { DataViewsContract } from '@kbn/data-views-plugin/public';
|
||||
import { SharePluginSetup } from '@kbn/share-plugin/public';
|
||||
import { GuidedOnboardingApi } from '@kbn/guided-onboarding-plugin/public';
|
||||
import { TutorialService } from '../services/tutorials';
|
||||
import { AddDataService } from '../services/add_data';
|
||||
import { FeatureCatalogueRegistry } from '../services/feature_catalogue';
|
||||
|
@ -49,6 +50,7 @@ export interface HomeKibanaServices {
|
|||
tutorialService: TutorialService;
|
||||
addDataService: AddDataService;
|
||||
welcomeService: WelcomeService;
|
||||
guidedOnboardingService?: GuidedOnboardingApi;
|
||||
}
|
||||
|
||||
let services: HomeKibanaServices | null = null;
|
||||
|
|
|
@ -18,6 +18,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';
|
||||
import { UrlForwardingSetup, UrlForwardingStart } from '@kbn/url-forwarding-plugin/public';
|
||||
import type { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public';
|
||||
import { AppNavLinkStatus } from '@kbn/core/public';
|
||||
import { SharePluginSetup } from '@kbn/share-plugin/public';
|
||||
import type { CloudSetup } from '@kbn/cloud-plugin/public';
|
||||
|
@ -40,6 +41,7 @@ import {
|
|||
export interface HomePluginStartDependencies {
|
||||
dataViews: DataViewsPublicPluginStart;
|
||||
urlForwarding: UrlForwardingStart;
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
}
|
||||
|
||||
export interface HomePluginSetupDependencies {
|
||||
|
@ -78,7 +80,7 @@ export class HomePublicPlugin
|
|||
const trackUiMetric = usageCollection
|
||||
? usageCollection.reportUiCounter.bind(usageCollection, 'Kibana_home')
|
||||
: () => {};
|
||||
const [coreStart, { dataViews, urlForwarding: urlForwardingStart }] =
|
||||
const [coreStart, { dataViews, urlForwarding: urlForwardingStart, guidedOnboarding }] =
|
||||
await core.getStartServices();
|
||||
setServices({
|
||||
share,
|
||||
|
@ -102,6 +104,7 @@ export class HomePublicPlugin
|
|||
addDataService: this.addDataService,
|
||||
featureCatalogue: this.featuresCatalogueRegistry,
|
||||
welcomeService: this.welcomeService,
|
||||
guidedOnboardingService: guidedOnboarding.guidedOnboardingApi,
|
||||
});
|
||||
coreStart.chrome.docTitle.change(
|
||||
i18n.translate('home.pageTitle', { defaultMessage: 'Home' })
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
{ "path": "../share/tsconfig.json" },
|
||||
{ "path": "../url_forwarding/tsconfig.json" },
|
||||
{ "path": "../usage_collection/tsconfig.json" },
|
||||
{ "path": "../../../x-pack/plugins/cloud/tsconfig.json" }
|
||||
{ "path": "../guided_onboarding/tsconfig.json" },
|
||||
{ "path": "../../../x-pack/plugins/cloud/tsconfig.json" },
|
||||
]
|
||||
}
|
||||
|
|
|
@ -3102,15 +3102,6 @@
|
|||
"home.breadcrumbs.integrationsAppTitle": "Intégrations",
|
||||
"home.exploreButtonLabel": "Explorer par moi-même",
|
||||
"home.exploreYourDataDescription": "Une fois toutes les étapes terminées, vous êtes prêt à explorer vos données.",
|
||||
"home.guidedOnboarding.gettingStarted.observability.cardDescription": "Obtenez une observabilité de bout en bout de vos environnements en consolidant vos journaux, vos indicateurs et vos traces.",
|
||||
"home.guidedOnboarding.gettingStarted.observability.cardTitle": "Monitorer mes environnements",
|
||||
"home.guidedOnboarding.gettingStarted.observability.iconName": "Logo Observability",
|
||||
"home.guidedOnboarding.gettingStarted.search.cardDescription": "Créez une expérience de recherche fine pour vos sites web, vos applications, votre contenu workplace, etc.",
|
||||
"home.guidedOnboarding.gettingStarted.search.cardTitle": "Rechercher dans mes données",
|
||||
"home.guidedOnboarding.gettingStarted.search.iconName": "Logo Entreprise Search",
|
||||
"home.guidedOnboarding.gettingStarted.security.cardDescription": "Protégez votre environnement contre les menaces en unifiant SIEM, la sécurité des points de terminaison et la sécurité cloud en un seul endroit.",
|
||||
"home.guidedOnboarding.gettingStarted.security.cardTitle": "Protéger mon environnement",
|
||||
"home.guidedOnboarding.gettingStarted.security.iconName": "Logo Security",
|
||||
"home.guidedOnboarding.gettingStarted.skip.buttonLabel": "Non merci, je vais explorer par moi-même.",
|
||||
"home.guidedOnboarding.gettingStarted.useCaseSelectionSubtitle": "Sélectionnez un point de départ pour une visite rapide de la façon dont Elastic peut vous aider à faire encore plus avec vos données.",
|
||||
"home.guidedOnboarding.gettingStarted.useCaseSelectionTitle": "Par quoi voulez-vous commencer ?",
|
||||
|
|
|
@ -3097,15 +3097,6 @@
|
|||
"home.breadcrumbs.integrationsAppTitle": "統合",
|
||||
"home.exploreButtonLabel": "独りで閲覧",
|
||||
"home.exploreYourDataDescription": "すべてのステップを終えたら、データ閲覧準備の完了です。",
|
||||
"home.guidedOnboarding.gettingStarted.observability.cardDescription": "ログ、メトリック、トレースを統合し、環境に対するエンドツーエンドのオブザーバビリティを実現します。",
|
||||
"home.guidedOnboarding.gettingStarted.observability.cardTitle": "環境を監視",
|
||||
"home.guidedOnboarding.gettingStarted.observability.iconName": "オブザーバビリティロゴ",
|
||||
"home.guidedOnboarding.gettingStarted.search.cardDescription": "Webサイト、アプリケーション、workplaceコンテンツなどに合った、微調整された検索エクスペリエンスを作成します。",
|
||||
"home.guidedOnboarding.gettingStarted.search.cardTitle": "データを検索",
|
||||
"home.guidedOnboarding.gettingStarted.search.iconName": "エンタープライズ サーチロゴ",
|
||||
"home.guidedOnboarding.gettingStarted.security.cardDescription": "SIEM、エンドポイントセキュリティ、クラウドセキュリティを一元化して統合することで、環境を脅威から守ります。",
|
||||
"home.guidedOnboarding.gettingStarted.security.cardTitle": "環境を保護",
|
||||
"home.guidedOnboarding.gettingStarted.security.iconName": "セキュリティロゴ",
|
||||
"home.guidedOnboarding.gettingStarted.skip.buttonLabel": "いいえ、結構です。自分で探します。",
|
||||
"home.guidedOnboarding.gettingStarted.useCaseSelectionSubtitle": "まず、スタートとしてクイックガイドを表示すると、どのようにElasticでデータに対して高度な操作を実行するのかを確認できます。",
|
||||
"home.guidedOnboarding.gettingStarted.useCaseSelectionTitle": "最初に何をしたいですか?",
|
||||
|
|
|
@ -3102,15 +3102,6 @@
|
|||
"home.breadcrumbs.integrationsAppTitle": "集成",
|
||||
"home.exploreButtonLabel": "自己浏览",
|
||||
"home.exploreYourDataDescription": "完成所有步骤后,您便可以随时浏览自己的数据。",
|
||||
"home.guidedOnboarding.gettingStarted.observability.cardDescription": "通过整合您的日志、指标和跟踪,在您的环境中实现端到端可观测性。",
|
||||
"home.guidedOnboarding.gettingStarted.observability.cardTitle": "监测我的环境",
|
||||
"home.guidedOnboarding.gettingStarted.observability.iconName": "Observability 徽标",
|
||||
"home.guidedOnboarding.gettingStarted.search.cardDescription": "为您的网站、应用程序、工作区内容等创建经过优化的搜索体验。",
|
||||
"home.guidedOnboarding.gettingStarted.search.cardTitle": "搜索我的数据",
|
||||
"home.guidedOnboarding.gettingStarted.search.iconName": "Enterprise Search 徽标",
|
||||
"home.guidedOnboarding.gettingStarted.security.cardDescription": "通过在一个位置整合 SIEM、Endpoint Security 和云安全来保护您的环境,防止其受到威胁。",
|
||||
"home.guidedOnboarding.gettingStarted.security.cardTitle": "保护我的环境",
|
||||
"home.guidedOnboarding.gettingStarted.security.iconName": "安全徽标",
|
||||
"home.guidedOnboarding.gettingStarted.skip.buttonLabel": "不用了,谢谢,我会自己浏览。",
|
||||
"home.guidedOnboarding.gettingStarted.useCaseSelectionSubtitle": "选择快速教程的起点,了解 Elastic 如何帮助您利用数据完成更多任务。",
|
||||
"home.guidedOnboarding.gettingStarted.useCaseSelectionTitle": "您希望先做什么?",
|
||||
|
|
|
@ -3493,6 +3493,10 @@
|
|||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/guided-onboarding@link:bazel-bin/packages/kbn-guided-onboarding":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/handlebars@link:bazel-bin/packages/kbn-handlebars":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
@ -7665,6 +7669,10 @@
|
|||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@types/kbn__guided-onboarding@link:bazel-bin/packages/kbn-guided-onboarding/npm_module_types":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@types/kbn__handlebars@link:bazel-bin/packages/kbn-handlebars/npm_module_types":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue