mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Disable guided onboarding on serverless (#168303)
This commit is contained in:
parent
ef67add16c
commit
2b1cd4d080
39 changed files with 209 additions and 156 deletions
|
@ -51,9 +51,12 @@ xpack.index_management.enableDataStreamsStorageColumn: false
|
|||
dev_tools.deeplinks.navLinkStatus: visible
|
||||
management.deeplinks.navLinkStatus: visible
|
||||
|
||||
# Onboarding team UI configurations
|
||||
xpack.cloud_integrations.data_migration.enabled: false
|
||||
guided_onboarding.enabled: false
|
||||
|
||||
# Other disabled plugins
|
||||
xpack.canvas.enabled: false
|
||||
xpack.cloud_integrations.data_migration.enabled: false
|
||||
data.search.sessions.enabled: false
|
||||
advanced_settings.enabled: false
|
||||
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
"server": true,
|
||||
"browser": true,
|
||||
"requiredPlugins": [
|
||||
"navigation",
|
||||
"navigation"
|
||||
],
|
||||
"optionalPlugins": [
|
||||
"guidedOnboarding"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ export const GuidedOnboardingExampleApp = (props: GuidedOnboardingExampleAppDeps
|
|||
/>
|
||||
}
|
||||
/>
|
||||
{guidedOnboarding.guidedOnboardingApi?.isEnabled ? (
|
||||
{guidedOnboarding?.guidedOnboardingApi?.isEnabled ? (
|
||||
<EuiPageTemplate.Section>
|
||||
<Router history={history}>
|
||||
<Routes>
|
||||
|
|
|
@ -31,7 +31,7 @@ import type { GuideState, GuideStepIds, GuideId, GuideStep } from '@kbn/guided-o
|
|||
import type { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public';
|
||||
|
||||
interface MainProps {
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
guidedOnboarding?: GuidedOnboardingPluginStart;
|
||||
notifications: CoreStart['notifications'];
|
||||
}
|
||||
|
||||
|
@ -48,10 +48,7 @@ const selectOptions: EuiSelectOption[] = exampleGuideIds.map((guideId) => ({
|
|||
text: guideId,
|
||||
}));
|
||||
export const Main = (props: MainProps) => {
|
||||
const {
|
||||
guidedOnboarding: { guidedOnboardingApi },
|
||||
notifications,
|
||||
} = props;
|
||||
const { guidedOnboarding, notifications } = props;
|
||||
const history = useHistory();
|
||||
const [guidesState, setGuidesState] = useState<GuideState[] | undefined>(undefined);
|
||||
const [activeGuide, setActiveGuide] = useState<GuideState | undefined>(undefined);
|
||||
|
@ -61,12 +58,12 @@ export const Main = (props: MainProps) => {
|
|||
|
||||
useEffect(() => {
|
||||
const fetchGuidesState = async () => {
|
||||
const newGuidesState = await guidedOnboardingApi?.fetchAllGuidesState();
|
||||
const newGuidesState = await guidedOnboarding?.guidedOnboardingApi?.fetchAllGuidesState();
|
||||
setGuidesState(newGuidesState ? newGuidesState.state : []);
|
||||
};
|
||||
|
||||
fetchGuidesState();
|
||||
}, [guidedOnboardingApi]);
|
||||
}, [guidedOnboarding]);
|
||||
|
||||
useEffect(() => {
|
||||
const newActiveGuide = guidesState?.find((guide) => guide.isActive === true);
|
||||
|
@ -76,7 +73,10 @@ export const Main = (props: MainProps) => {
|
|||
}, [guidesState, setActiveGuide]);
|
||||
|
||||
const activateGuide = async (guideId: GuideId, guideState?: GuideState) => {
|
||||
const response = await guidedOnboardingApi?.activateGuide(guideId, guideState);
|
||||
const response = await guidedOnboarding?.guidedOnboardingApi?.activateGuide(
|
||||
guideId,
|
||||
guideState
|
||||
);
|
||||
|
||||
if (response) {
|
||||
notifications.toasts.addSuccess(
|
||||
|
@ -92,7 +92,9 @@ export const Main = (props: MainProps) => {
|
|||
return;
|
||||
}
|
||||
|
||||
const selectedGuideConfig = await guidedOnboardingApi?.getGuideConfig(selectedGuide);
|
||||
const selectedGuideConfig = await guidedOnboarding?.guidedOnboardingApi?.getGuideConfig(
|
||||
selectedGuide
|
||||
);
|
||||
|
||||
if (!selectedGuideConfig) {
|
||||
return;
|
||||
|
@ -134,7 +136,7 @@ export const Main = (props: MainProps) => {
|
|||
guideId: selectedGuide!,
|
||||
};
|
||||
|
||||
const response = await guidedOnboardingApi?.updatePluginState(
|
||||
const response = await guidedOnboarding?.guidedOnboardingApi?.updatePluginState(
|
||||
{ status: 'in_progress', guide: updatedGuideState },
|
||||
true
|
||||
);
|
||||
|
@ -170,7 +172,7 @@ export const Main = (props: MainProps) => {
|
|||
<p>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.guidesSelection.state.explanation"
|
||||
defaultMessage="The guide state on this page is updated automatically via an Observable,
|
||||
defaultMessage="The guide state on this page is updated automatically via an Observable subscription,
|
||||
so there is no need to 'load' the state from the server."
|
||||
/>
|
||||
</p>
|
||||
|
|
|
@ -16,24 +16,22 @@ import { EuiPageHeader, EuiPageSection, EuiCode } from '@elastic/eui';
|
|||
import { useParams } from 'react-router-dom';
|
||||
|
||||
interface StepFourProps {
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
guidedOnboarding?: GuidedOnboardingPluginStart;
|
||||
}
|
||||
|
||||
export const StepFour: React.FC<StepFourProps> = ({
|
||||
guidedOnboarding: { guidedOnboardingApi },
|
||||
}) => {
|
||||
export const StepFour: React.FC<StepFourProps> = ({ guidedOnboarding }) => {
|
||||
const { indexName } = useParams<{ indexName: string }>();
|
||||
|
||||
const [, setIsTourStepOpen] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = guidedOnboardingApi
|
||||
const subscription = guidedOnboarding?.guidedOnboardingApi
|
||||
?.isGuideStepActive$('testGuide', 'step4')
|
||||
.subscribe((isStepActive) => {
|
||||
setIsTourStepOpen(isStepActive);
|
||||
});
|
||||
return () => subscription?.unsubscribe();
|
||||
}, [guidedOnboardingApi]);
|
||||
}, [guidedOnboarding]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -65,7 +63,7 @@ export const StepFour: React.FC<StepFourProps> = ({
|
|||
|
||||
<EuiButton
|
||||
onClick={async () => {
|
||||
await guidedOnboardingApi?.completeGuideStep('testGuide', 'step4');
|
||||
await guidedOnboarding?.guidedOnboardingApi?.completeGuideStep('testGuide', 'step4');
|
||||
}}
|
||||
>
|
||||
Complete step 4
|
||||
|
|
|
@ -23,27 +23,25 @@ import {
|
|||
EuiFormRow,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import useObservable from 'react-use/lib/useObservable';
|
||||
|
||||
import { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public/types';
|
||||
|
||||
interface GuidedOnboardingExampleAppDeps {
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
guidedOnboarding?: GuidedOnboardingPluginStart;
|
||||
}
|
||||
|
||||
export const StepOne = ({ guidedOnboarding }: GuidedOnboardingExampleAppDeps) => {
|
||||
const { guidedOnboardingApi } = guidedOnboarding;
|
||||
|
||||
const [isTourStepOpen, setIsTourStepOpen] = useState<boolean>(false);
|
||||
const [indexName, setIndexName] = useState('test1234');
|
||||
|
||||
const isTourActive = useObservable(
|
||||
guidedOnboardingApi!.isGuideStepActive$('testGuide', 'step1'),
|
||||
false
|
||||
);
|
||||
useEffect(() => {
|
||||
setIsTourStepOpen(isTourActive);
|
||||
}, [isTourActive]);
|
||||
const subscription = guidedOnboarding?.guidedOnboardingApi
|
||||
?.isGuideStepActive$('testGuide', 'step1')
|
||||
.subscribe((isStepActive) => {
|
||||
setIsTourStepOpen(isStepActive);
|
||||
});
|
||||
return () => subscription?.unsubscribe();
|
||||
}, [guidedOnboarding]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiPageHeader>
|
||||
|
@ -107,9 +105,13 @@ export const StepOne = ({ guidedOnboarding }: GuidedOnboardingExampleAppDeps) =>
|
|||
>
|
||||
<EuiButton
|
||||
onClick={async () => {
|
||||
await guidedOnboardingApi?.completeGuideStep('testGuide', 'step1', {
|
||||
indexName,
|
||||
});
|
||||
await guidedOnboarding?.guidedOnboardingApi?.completeGuideStep(
|
||||
'testGuide',
|
||||
'step1',
|
||||
{
|
||||
indexName,
|
||||
}
|
||||
);
|
||||
}}
|
||||
>
|
||||
Complete step 1
|
||||
|
|
|
@ -11,7 +11,7 @@ import { PluginInitializerContext, CoreSetup, Plugin, Logger } from '@kbn/core/s
|
|||
import { testGuideId, testGuideConfig } from '@kbn/guided-onboarding';
|
||||
|
||||
interface PluginsSetup {
|
||||
guidedOnboarding: GuidedOnboardingPluginSetup;
|
||||
guidedOnboarding?: GuidedOnboardingPluginSetup;
|
||||
}
|
||||
|
||||
export class GuidedOnboardingExamplePlugin implements Plugin {
|
||||
|
@ -23,7 +23,7 @@ export class GuidedOnboardingExamplePlugin implements Plugin {
|
|||
|
||||
public setup(coreSetup: CoreSetup, { guidedOnboarding }: PluginsSetup) {
|
||||
this.logger.debug('guidedOnboardingExample: Setup');
|
||||
guidedOnboarding.registerGuideConfig(testGuideId, testGuideConfig);
|
||||
guidedOnboarding?.registerGuideConfig(testGuideId, testGuideConfig);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
# Guided Onboarding
|
||||
|
||||
This plugin contains the code for the Guided Onboarding project. Guided onboarding consists of guides for Solutions (Enterprise Search, Observability, Security) that can be completed as a checklist of steps. The guides help users to ingest their data and to navigate to the correct Solutions pages.
|
||||
This plugin contains the code for the Guided Onboarding project. Guided onboarding consists of guides for Solutions (Enterprise Search, Observability, Security) that can be completed as a checklist of steps. The guides help users to ingest their data and to navigate to the correct Solutions pages.
|
||||
|
||||
The guided onboarding plugin includes a client-side code for the UI and the server-side code for the internal API.
|
||||
The guided onboarding plugin includes a client-side code for the UI and the server-side code for the internal API.
|
||||
|
||||
The client-side code registers a button in the Kibana header that controls the guided onboarding panel (checklist) depending on the current state. There is also an API service exposed from the client-side start contract. The API service is intended for external use by other plugins that need to react to the guided onboarding state, for example hide or display UI elements if a guide step is active.
|
||||
|
||||
Besides the internal API routes, the server-side code also exposes a function to register guide configs from the server-side setup start contract. This function is intended for external use by any plugin that need to add a new guide or modify an existing one.
|
||||
Besides the internal API routes, the server-side code also exposes a function to register guide configs from the server-side setup start contract. This function is intended for external use by any plugin that need to add a new guide or modify an existing one.
|
||||
|
||||
---
|
||||
|
||||
## Current functionality
|
||||
|
||||
The solution plugins register their config that specifies the title, the description and the steps of a guide. The config is fetched via an http request to a guided onboarding endpoint. This endpoint should only be used internally by the guided onboarding API service. The configs are basically just `js` objects that are loaded into the Kibana server memory on startup. Because configs are not expected to be changed by the user, we don’t need to use saved objects.
|
||||
|
@ -20,6 +21,7 @@ A step is completed on the solution page code by calling a function in the guide
|
|||
The plugin’s state keeps track of which guide has been started and its current progress. The state also includes the information if the user has started any guide, has completed any guide or if they skipped the guided onboarding, or if they quit the guide before completion. We also store the date when the user first looked at the landing page and if they haven't started any guide, the header button is displayed for the first 30 days. When clicked, the button redirects the user back to the landing page to start a guide.
|
||||
|
||||
## Architecture description
|
||||
|
||||
The guided onboarding is currently implemented in a separate `guided_onboarding` plugin that contains the code for the header button ([link](https://github.com/elastic/kibana/blob/main/src/plugins/guided_onboarding/public/components/guide_button.tsx)), the dropdown panel ([link](https://github.com/elastic/kibana/blob/main/src/plugins/guided_onboarding/public/components/guide_panel.tsx)) and the API service ([link](https://github.com/elastic/kibana/blob/main/src/plugins/guided_onboarding/public/services/api.service.ts)) exposed out of the client side that can be used by other plugins to get/update the state of the guided onboarding.
|
||||
|
||||
For example, when a user goes through the SIEM guide they are first taken to the integrations page where they follow some EUI tour steps and install the Elastic Agent and the Elastic Defend integration. The code on the integrations page uses the guided onboarding API service to check if a guide for the Elastic Defend integration is currently in progress. If yes, the page will display the EUI tour steps to guide the user. The page will also use the API service to update the guided onboarding state to the next step when the user completes the installation.
|
||||
|
@ -35,27 +37,33 @@ When starting Kibana with `yarn start --run-examples` the `guided_onboarding_exa
|
|||
|
||||
1. Guided onboarding is only enabled on cloud. Update your `kibana.dev.yml` file with `xpack.cloud.id: 'testID'` to imitate the Cloud environment.
|
||||
|
||||
2. Start Kibana with the example plugins enabled: `yarn start --run-examples`.
|
||||
2. Start Kibana with the example plugins enabled: `yarn start --run-examples`.
|
||||
|
||||
3. Navigate to `/app/home#/getting_started` to view the onboarding landing page and start a guide. Alternatively, you can also start a guide within the guided onboarding example plugin at `/app/guidedOnboardingExample`. The example plugin includes a sample guide that showcases the framework's capabilities. It also provides a form to dynamically start a guide at a specific step.
|
||||
|
||||
## Client side: API service
|
||||
*Also see `KIBANA_FOLDER/examples/guided_onboarding_example` for code examples.*
|
||||
|
||||
The guided onboarding plugin exposes an API service from its start contract that is intended to be used by other plugins. The API service allows consumers to access the current state of the guided onboarding process and manipulate it.
|
||||
_Also see `KIBANA_FOLDER/examples/guided_onboarding_example` for code examples._
|
||||
|
||||
The guided onboarding plugin exposes an API service from its start contract that is intended to be used by other plugins. The API service allows consumers to access the current state of the guided onboarding process and manipulate it.
|
||||
|
||||
To use the API service in your plugin, declare the guided onboarding plugin as a dependency in the file `kibana.json` of your plugin. Add the API service to your plugin's start dependencies to rely on the provided TypeScript interface:
|
||||
|
||||
```js
|
||||
export interface AppPluginStartDependencies {
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
guidedOnboarding?: GuidedOnboardingPluginStart;
|
||||
}
|
||||
```
|
||||
|
||||
The API service is now available to your plugin in the setup lifecycle function of your plugin
|
||||
|
||||
```js
|
||||
// startDependencies is of type AppPluginStartDependencies
|
||||
const [coreStart, startDependencies] = await core.getStartServices();
|
||||
```
|
||||
|
||||
or in the start lifecycle function of your plugin.
|
||||
|
||||
```js
|
||||
public start(core: CoreStart, startDependencies: AppPluginStartDependencies) {
|
||||
...
|
||||
|
@ -63,35 +71,30 @@ public start(core: CoreStart, startDependencies: AppPluginStartDependencies) {
|
|||
```
|
||||
|
||||
### isGuideStepActive$(guideId: GuideId, stepId: GuideStepIds): Observable\<boolean\>
|
||||
*Also see `KIBANA_FOLDER/examples/guided_onboarding_example/public/components/step_one.tsx`.*
|
||||
|
||||
The API service exposes an Observable that contains a boolean value for the state of a specific guide step. For example, if your plugin needs to check if the "Add data" step of the SIEM guide is currently active, you could use the following code snippet.
|
||||
_Also see `KIBANA_FOLDER/examples/guided_onboarding_example/public/components/step_one.tsx`._
|
||||
|
||||
The API service exposes an Observable that contains a boolean value for the state of a specific guide step. For example, if your plugin needs to check if the "Add data" step of the SIEM guide is currently active, you could use the following code snippet.
|
||||
|
||||
```js
|
||||
const { guidedOnboardingApi } = guidedOnboarding;
|
||||
const isDataStepActive = useObservable(guidedOnboardingApi!.isGuideStepActive$('siem', 'add_data'));
|
||||
useEffect(() => {
|
||||
// do some logic depending on the step state
|
||||
}, [isDataStepActive]);
|
||||
```
|
||||
|
||||
Alternatively, you can subscribe to the Observable directly.
|
||||
```js
|
||||
useEffect(() => {
|
||||
const subscription = guidedOnboardingApi?.isGuideStepActive$('siem', 'add_data').subscribe((isDataStepACtive) => {
|
||||
// do some logic depending on the step state
|
||||
const subscription = guidedOnboardingApi
|
||||
?.isGuideStepActive$('siem', 'add_data')
|
||||
.subscribe((isDataStepActive) => {
|
||||
// do some logic depending on the step state
|
||||
});
|
||||
return () => subscription?.unsubscribe();
|
||||
return () => subscription?.unsubscribe();
|
||||
}, [guidedOnboardingApi]);
|
||||
```
|
||||
|
||||
### isGuideStepReadyToComplete$(guideId: GuideId, stepId: GuideStepIds): Observable\<boolean\>
|
||||
Similar to `isGuideStepActive$`, the observable `isGuideStepReadyToComplete$` can be used to track the state of a step that is configured for manual completion. The observable broadcasts `true` when the manual completion popover is displayed and the user can mark the step "done". In this state the step is not in progress anymore but is not yet fully completed.
|
||||
|
||||
Similar to `isGuideStepActive$`, the observable `isGuideStepReadyToComplete$` can be used to track the state of a step that is configured for manual completion. The observable broadcasts `true` when the manual completion popover is displayed and the user can mark the step "done". In this state the step is not in progress anymore but is not yet fully completed.
|
||||
|
||||
### completeGuideStep(guideId: GuideId, stepId: GuideStepIds, params?: GuideParams): Promise\<{ pluginState: PluginState } | undefined\>
|
||||
The API service exposes an async function to mark a guide step as completed.
|
||||
If the specified guide step is not currently active, the function is a noop. In that case the return value is `undefined`,
|
||||
|
||||
The API service exposes an async function to mark a guide step as completed.
|
||||
If the specified guide step is not currently active, the function is a noop. In that case the return value is `undefined`,
|
||||
otherwise an updated `PluginState` is returned.
|
||||
|
||||
```
|
||||
|
@ -99,34 +102,39 @@ await guidedOnboardingApi?.completeGuideStep('siem', 'add_data');
|
|||
```
|
||||
|
||||
The function also accepts an optional argument `params` that will be saved in the state and later used for step URLs with dynamic parameters. For example, step 2 of the guide has a dynamic parameter `indexID` in its location path:
|
||||
|
||||
```js
|
||||
const step2Config = {
|
||||
id: 'step2',
|
||||
description: 'Step with dynamic url',
|
||||
location: {
|
||||
appID: 'test', path: 'testPath/{indexID}'
|
||||
}
|
||||
id: 'step2',
|
||||
description: 'Step with dynamic url',
|
||||
location: {
|
||||
appID: 'test',
|
||||
path: 'testPath/{indexID}',
|
||||
},
|
||||
};
|
||||
```
|
||||
The value of the parameter `indexID` needs to be passed to the API service when completing step 1: `completeGuideStep('testGuide', 'step1', { indexID: 'testIndex' })`
|
||||
|
||||
The value of the parameter `indexID` needs to be passed to the API service when completing step 1: `completeGuideStep('testGuide', 'step1', { indexID: 'testIndex' })`
|
||||
|
||||
## Guides config
|
||||
To use the API service, you need to know a guide ID (currently one of `appSearch`, `websiteSearch`, `databaseSearch`, `kubernetes`, `siem`) and a step ID (for example, `add_data`, `search_experience`, `rules` etc). The consumers of guided onboarding register their guide configs themselves and have therefore full control over the guide ID and step IDs used for their guide. For more details on registering a guide config, see below.
|
||||
|
||||
To use the API service, you need to know a guide ID (currently one of `appSearch`, `websiteSearch`, `databaseSearch`, `kubernetes`, `siem`) and a step ID (for example, `add_data`, `search_experience`, `rules` etc). The consumers of guided onboarding register their guide configs themselves and have therefore full control over the guide ID and step IDs used for their guide. For more details on registering a guide config, see below.
|
||||
|
||||
## Server side: register a guide config
|
||||
The guided onboarding exposes a function `registerGuideConfig(guideId: GuideId, guideConfig: GuideConfig)` function in its setup contract. This function allows consumers to register a guide config for a specified guide ID. The function throws an error if a config already exists for the guide ID. See code examples in following plugins:
|
||||
|
||||
The guided onboarding exposes a function `registerGuideConfig(guideId: GuideId, guideConfig: GuideConfig)` function in its setup contract. This function allows consumers to register a guide config for a specified guide ID. The function throws an error if a config already exists for the guide ID. See code examples in following plugins:
|
||||
|
||||
- enterprise search: `x-pack/plugins/enterprise_search/server/plugin.ts`
|
||||
- observability: `x-pack/plugins/observability/server/plugin.ts`
|
||||
- security solution: `x-pack/plugins/security_solution/server/plugin.ts`
|
||||
|
||||
|
||||
## Adding a new guide
|
||||
|
||||
Follow these simple steps to add a new guide to the guided onboarding framework. For more detailed information about framework functionality and architecture and about API services exposed by the plugin, please read the full readme.
|
||||
|
||||
1. Declare the `guidedOnboarding` plugin as a dependency in your plugin's `kibana.json` file. Add the guided onboarding plugin's client-side start contract to your plugin's client-side start dependencies and the guided onboarding plugin's server-side setup contract to your plugin's server-side dependencies.
|
||||
1. Declare the `guidedOnboarding` plugin as an optional dependency in your plugin's `kibana.json` file. Add the guided onboarding plugin's client-side start contract to your plugin's client-side start dependencies and the guided onboarding plugin's server-side setup contract to your plugin's server-side dependencies.
|
||||
2. Define the configuration for your guide. At a high level, this includes a title, description, and list of steps. See this [example config](https://github.com/elastic/kibana/blob/main/packages/kbn-guided-onboarding/src/common/test_guide_config.ts) or consult the `GuideConfig` interface.
|
||||
3. Register your guide during your plugin's server-side setup by calling a function exposed by the guided onboarding plugin: `registerGuideConfig(guideId: GuideId, guideConfig: GuideConfig)`. For an example, see this [example plugin](https://github.com/elastic/kibana/blob/main/examples/guided_onboarding_example/server/plugin.ts).
|
||||
4. Update the cards on the landing page to include your guide in the use case selection. Make sure that the card doesn't have the property `navigateTo` because that is only used for cards that redirect to Kibana pages and don't start a guide. Also add the same value to the property `guideId` as used in the guide config. Landing page cards are configured in this [kbn-guided-onboarding package](https://github.com/elastic/kibana/blob/main/packages/kbn-guided-onboarding/src/components/landing_page/guide_cards.constants.tsx).
|
||||
5. Integrate the new guide into your Kibana pages by using the guided onboarding client-side API service. Make sure your Kibana pages correctly display UI elements depending on the active guide step and the UI flow is straight forward to complete the guide. See existing guides for an example and read more about the API service in this file, the section "Client-side: API service".
|
||||
6. Optionally, update the example plugin's [form](https://github.com/elastic/kibana/blob/main/examples/guided_onboarding_example/public/components/main.tsx#L38) to be able to start your guide from that page and activate any step in your guide (useful to test your guide steps).
|
||||
3. Register your guide during your plugin's server-side setup by calling a function exposed by the guided onboarding plugin: `registerGuideConfig(guideId: GuideId, guideConfig: GuideConfig)`. For an example, see this [example plugin](https://github.com/elastic/kibana/blob/main/examples/guided_onboarding_example/server/plugin.ts).
|
||||
4. Update the cards on the landing page to include your guide in the use case selection. Make sure that the card doesn't have the property `navigateTo` because that is only used for cards that redirect to Kibana pages and don't start a guide. Also add the same value to the property `guideId` as used in the guide config. Landing page cards are configured in this [kbn-guided-onboarding package](https://github.com/elastic/kibana/blob/main/packages/kbn-guided-onboarding/src/components/landing_page/guide_cards.constants.tsx).
|
||||
5. Integrate the new guide into your Kibana pages by using the guided onboarding client-side API service. Make sure your Kibana pages correctly display UI elements depending on the active guide step and the UI flow is straight forward to complete the guide. See existing guides for an example and read more about the API service in this file, the section "Client-side: API service".
|
||||
6. Optionally, update the example plugin's [form](https://github.com/elastic/kibana/blob/main/examples/guided_onboarding_example/public/components/main.tsx#L38) to be able to start your guide from that page and activate any step in your guide (useful to test your guide steps).
|
||||
|
|
24
src/plugins/guided_onboarding/server/config.ts
Normal file
24
src/plugins/guided_onboarding/server/config.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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 { offeringBasedSchema, schema, TypeOf } from '@kbn/config-schema';
|
||||
import { PluginConfigDescriptor } from '@kbn/core-plugins-server';
|
||||
|
||||
const configSchema = schema.object({
|
||||
enabled: offeringBasedSchema({
|
||||
// guided_onboarding is disabled in serverless; refer to the serverless.yml file as the source of truth
|
||||
// We take this approach in order to have a central place (serverless.yml) to view disabled plugins across Kibana
|
||||
serverless: schema.boolean({ defaultValue: true }),
|
||||
}),
|
||||
});
|
||||
|
||||
export type GuidedOnboardingConfig = TypeOf<typeof configSchema>;
|
||||
|
||||
export const config: PluginConfigDescriptor<GuidedOnboardingConfig> = {
|
||||
schema: configSchema,
|
||||
};
|
|
@ -14,3 +14,5 @@ export function plugin(initializerContext: PluginInitializerContext) {
|
|||
}
|
||||
|
||||
export type { GuidedOnboardingPluginSetup, GuidedOnboardingPluginStart } from './types';
|
||||
|
||||
export { config } from './config';
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
"@kbn/i18n-react",
|
||||
"@kbn/core-application-browser-mocks",
|
||||
"@kbn/core-notifications-browser-mocks",
|
||||
"@kbn/config-schema",
|
||||
"@kbn/core-plugins-server",
|
||||
"@kbn/test-jest-helpers",
|
||||
"@kbn/i18n",
|
||||
"@kbn/core-http-browser",
|
||||
|
|
|
@ -71,7 +71,7 @@ export function HomeApp({ directories, solutions }) {
|
|||
<Routes>
|
||||
<Route path="/tutorial/:id" render={renderTutorial} />
|
||||
<Route path="/tutorial_directory/:tab?" render={renderTutorialDirectory} />
|
||||
{guidedOnboardingService.isEnabled && (
|
||||
{guidedOnboardingService?.isEnabled && (
|
||||
<Route path="/getting_started">
|
||||
<GettingStarted />
|
||||
</Route>
|
||||
|
|
|
@ -41,7 +41,7 @@ import {
|
|||
export interface HomePluginStartDependencies {
|
||||
dataViews: DataViewsPublicPluginStart;
|
||||
urlForwarding: UrlForwardingStart;
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
guidedOnboarding?: GuidedOnboardingPluginStart;
|
||||
}
|
||||
|
||||
export interface HomePluginSetupDependencies {
|
||||
|
@ -104,7 +104,7 @@ export class HomePublicPlugin
|
|||
addDataService: this.addDataService,
|
||||
featureCatalogue: this.featuresCatalogueRegistry,
|
||||
welcomeService: this.welcomeService,
|
||||
guidedOnboardingService: guidedOnboarding.guidedOnboardingApi,
|
||||
guidedOnboardingService: guidedOnboarding?.guidedOnboardingApi,
|
||||
cloud,
|
||||
});
|
||||
coreStart.chrome.docTitle.change(
|
||||
|
|
|
@ -22,7 +22,7 @@ export interface KibanaDeps {
|
|||
data: DataPublicPluginStart;
|
||||
discover: DiscoverStart;
|
||||
features: FeaturesPluginStart;
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
guidedOnboarding?: GuidedOnboardingPluginStart;
|
||||
licensing: LicensingPluginStart;
|
||||
security: SecurityPluginStart;
|
||||
share: SharePluginStart;
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
"logsShared",
|
||||
"cloud",
|
||||
"esUiShared",
|
||||
"guidedOnboarding",
|
||||
"lens",
|
||||
"embeddable",
|
||||
"share"
|
||||
|
@ -31,7 +30,8 @@
|
|||
"home",
|
||||
"ml",
|
||||
"spaces",
|
||||
"usageCollection"
|
||||
"usageCollection",
|
||||
"guidedOnboarding",
|
||||
],
|
||||
"requiredBundles": [
|
||||
"kibanaReact"
|
||||
|
|
|
@ -11,8 +11,6 @@ import { useParams } from 'react-router-dom';
|
|||
|
||||
import { useValues } from 'kea';
|
||||
|
||||
import useObservable from 'react-use/lib/useObservable';
|
||||
|
||||
import { EuiTabbedContent, EuiTabbedContentTab } from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
@ -80,24 +78,39 @@ export const SearchIndex: React.FC = () => {
|
|||
productAccess: { hasAppSearchAccess },
|
||||
productFeatures: { hasDefaultIngestPipeline },
|
||||
} = useValues(KibanaLogic);
|
||||
const isAppGuideActive = useObservable(
|
||||
guidedOnboarding.guidedOnboardingApi!.isGuideStepActive$('appSearch', 'add_data')
|
||||
);
|
||||
const isWebsiteGuideActive = useObservable(
|
||||
guidedOnboarding.guidedOnboardingApi!.isGuideStepActive$('websiteSearch', 'add_data')
|
||||
);
|
||||
const isDatabaseGuideActive = useObservable(
|
||||
guidedOnboarding.guidedOnboardingApi!.isGuideStepActive$('databaseSearch', 'add_data')
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isAppGuideActive && index?.count) {
|
||||
guidedOnboarding.guidedOnboardingApi?.completeGuideStep('appSearch', 'add_data');
|
||||
} else if (isWebsiteGuideActive && index?.count) {
|
||||
guidedOnboarding.guidedOnboardingApi?.completeGuideStep('websiteSearch', 'add_data');
|
||||
} else if (isDatabaseGuideActive && index?.count) {
|
||||
guidedOnboarding.guidedOnboardingApi?.completeGuideStep('databaseSearch', 'add_data');
|
||||
}
|
||||
}, [isAppGuideActive, isWebsiteGuideActive, isDatabaseGuideActive, index?.count]);
|
||||
const subscription = guidedOnboarding?.guidedOnboardingApi
|
||||
?.isGuideStepActive$('appSearch', 'add_data')
|
||||
.subscribe((isStepActive) => {
|
||||
if (isStepActive && index?.count) {
|
||||
guidedOnboarding?.guidedOnboardingApi?.completeGuideStep('appSearch', 'add_data');
|
||||
}
|
||||
});
|
||||
return () => subscription?.unsubscribe();
|
||||
}, [guidedOnboarding, index?.count]);
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = guidedOnboarding?.guidedOnboardingApi
|
||||
?.isGuideStepActive$('websiteSearch', 'add_data')
|
||||
.subscribe((isStepActive) => {
|
||||
if (isStepActive && index?.count) {
|
||||
guidedOnboarding?.guidedOnboardingApi?.completeGuideStep('websiteSearch', 'add_data');
|
||||
}
|
||||
});
|
||||
return () => subscription?.unsubscribe();
|
||||
}, [guidedOnboarding, index?.count]);
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = guidedOnboarding?.guidedOnboardingApi
|
||||
?.isGuideStepActive$('databaseSearch', 'add_data')
|
||||
.subscribe((isStepActive) => {
|
||||
if (isStepActive && index?.count) {
|
||||
guidedOnboarding.guidedOnboardingApi?.completeGuideStep('databaseSearch', 'add_data');
|
||||
}
|
||||
});
|
||||
return () => subscription?.unsubscribe();
|
||||
}, [guidedOnboarding, index?.count]);
|
||||
|
||||
const ALL_INDICES_TABS: EuiTabbedContentTab[] = [
|
||||
{
|
||||
|
|
|
@ -40,7 +40,7 @@ export interface KibanaLogicProps {
|
|||
cloud?: CloudSetup;
|
||||
config: ClientConfigType;
|
||||
data: DataPublicPluginStart;
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
guidedOnboarding?: GuidedOnboardingPluginStart;
|
||||
history: ScopedHistory;
|
||||
isSidebarEnabled: boolean;
|
||||
lens: LensPublicStart;
|
||||
|
|
|
@ -87,7 +87,7 @@ interface PluginsSetup {
|
|||
customIntegrations?: CustomIntegrationsPluginSetup;
|
||||
features: FeaturesPluginSetup;
|
||||
globalSearch: GlobalSearchPluginSetup;
|
||||
guidedOnboarding: GuidedOnboardingPluginSetup;
|
||||
guidedOnboarding?: GuidedOnboardingPluginSetup;
|
||||
logsShared: LogsSharedPluginSetup;
|
||||
ml?: MlPluginSetup;
|
||||
security: SecurityPluginSetup;
|
||||
|
@ -294,13 +294,13 @@ export class EnterpriseSearchPlugin implements Plugin {
|
|||
* Register a config for the search guide
|
||||
*/
|
||||
if (config.canDeployEntSearch) {
|
||||
guidedOnboarding.registerGuideConfig(appSearchGuideId, appSearchGuideConfig);
|
||||
guidedOnboarding?.registerGuideConfig(appSearchGuideId, appSearchGuideConfig);
|
||||
}
|
||||
if (config.hasWebCrawler) {
|
||||
guidedOnboarding.registerGuideConfig(websiteSearchGuideId, websiteSearchGuideConfig);
|
||||
guidedOnboarding?.registerGuideConfig(websiteSearchGuideId, websiteSearchGuideConfig);
|
||||
}
|
||||
if (config.hasConnectors) {
|
||||
guidedOnboarding.registerGuideConfig(databaseSearchGuideId, databaseSearchGuideConfig);
|
||||
guidedOnboarding?.registerGuideConfig(databaseSearchGuideId, databaseSearchGuideConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
"dataViews",
|
||||
"features",
|
||||
"files",
|
||||
"guidedOnboarding",
|
||||
"inspector",
|
||||
"lens",
|
||||
"observabilityShared",
|
||||
|
|
|
@ -33,7 +33,6 @@ import {
|
|||
} from '@kbn/triggers-actions-ui-plugin/public';
|
||||
import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';
|
||||
import { SecurityPluginStart } from '@kbn/security-plugin/public';
|
||||
import { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public';
|
||||
import { SpacesPluginStart } from '@kbn/spaces-plugin/public';
|
||||
import { LicensingPluginStart } from '@kbn/licensing-plugin/public';
|
||||
import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
|
||||
|
@ -60,7 +59,6 @@ export interface ExploratoryViewPublicPluginsStart {
|
|||
discover: DiscoverStart;
|
||||
embeddable: EmbeddableStart;
|
||||
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
lens: LensPublicStart;
|
||||
licensing: LicensingPluginStart;
|
||||
observabilityShared: ObservabilitySharedPluginStart;
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
"@kbn/lens-plugin",
|
||||
"@kbn/spaces-plugin",
|
||||
"@kbn/unified-search-plugin",
|
||||
"@kbn/guided-onboarding-plugin",
|
||||
"@kbn/discover-plugin",
|
||||
"@kbn/i18n",
|
||||
"@kbn/data-views-plugin",
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
"unifiedSearch",
|
||||
"savedObjectsTagging",
|
||||
"taskManager",
|
||||
"guidedOnboarding",
|
||||
"files",
|
||||
"uiActions",
|
||||
"dashboard"
|
||||
|
@ -36,6 +35,7 @@
|
|||
"discover",
|
||||
"ingestPipelines",
|
||||
"spaces",
|
||||
"guidedOnboarding",
|
||||
],
|
||||
"requiredBundles": [
|
||||
"kibanaReact",
|
||||
|
|
|
@ -143,7 +143,7 @@ export const ConfirmIncomingDataWithPreview: React.FunctionComponent<Props> = ({
|
|||
if (!isLoading && enrolledAgents > 0 && numAgentsWithData > 0) {
|
||||
setAgentDataConfirmed(true);
|
||||
if (isGuidedOnboardingActive) {
|
||||
guidedOnboarding.guidedOnboardingApi?.completeGuidedOnboardingForIntegration(
|
||||
guidedOnboarding?.guidedOnboardingApi?.completeGuidedOnboardingForIntegration(
|
||||
packageInfo?.name
|
||||
);
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ export const ConfirmIncomingData: React.FunctionComponent<Props> = ({
|
|||
if (!isLoading && enrolledAgents > 0 && numAgentsWithData > 0) {
|
||||
setAgentDataConfirmed(true);
|
||||
if (installedPolicy?.name && isGuidedOnboardingActive) {
|
||||
guidedOnboarding.guidedOnboardingApi?.completeGuidedOnboardingForIntegration(
|
||||
guidedOnboarding?.guidedOnboardingApi?.completeGuidedOnboardingForIntegration(
|
||||
installedPolicy!.name
|
||||
);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ export const useIsGuidedOnboardingActive = (packageName?: string): boolean => {
|
|||
const { guidedOnboarding } = useStartServices();
|
||||
const isGuidedOnboardingActiveForIntegration = useObservable(
|
||||
// if guided onboarding is not available, return false
|
||||
guidedOnboarding.guidedOnboardingApi
|
||||
guidedOnboarding?.guidedOnboardingApi
|
||||
? guidedOnboarding.guidedOnboardingApi.isGuidedOnboardingActiveForIntegration$(packageName)
|
||||
: of(false)
|
||||
);
|
||||
|
|
|
@ -129,7 +129,7 @@ export interface FleetStartDeps {
|
|||
share: SharePluginStart;
|
||||
cloud?: CloudStart;
|
||||
usageCollection?: UsageCollectionStart;
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
guidedOnboarding?: GuidedOnboardingPluginStart;
|
||||
}
|
||||
|
||||
export interface FleetStartServices extends CoreStart, Exclude<FleetStartDeps, 'cloud'> {
|
||||
|
@ -140,7 +140,7 @@ export interface FleetStartServices extends CoreStart, Exclude<FleetStartDeps, '
|
|||
discover?: DiscoverStart;
|
||||
spaces?: SpacesPluginStart;
|
||||
authz: FleetAuthz;
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
guidedOnboarding?: GuidedOnboardingPluginStart;
|
||||
}
|
||||
|
||||
export class FleetPlugin implements Plugin<FleetSetup, FleetStart, FleetSetupDeps, FleetStartDeps> {
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
"exploratoryView",
|
||||
"features",
|
||||
"files",
|
||||
"guidedOnboarding",
|
||||
"inspector",
|
||||
"lens",
|
||||
"observabilityShared",
|
||||
|
@ -44,7 +43,8 @@
|
|||
"usageCollection",
|
||||
"cloud",
|
||||
"spaces",
|
||||
"serverless"
|
||||
"serverless",
|
||||
"guidedOnboarding"
|
||||
],
|
||||
"requiredBundles": [
|
||||
"data",
|
||||
|
@ -58,4 +58,4 @@
|
|||
"common"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ export interface ObservabilityPublicPluginsStart {
|
|||
discover: DiscoverStart;
|
||||
embeddable: EmbeddableStart;
|
||||
exploratoryView: ExploratoryViewPublicStart;
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
guidedOnboarding?: GuidedOnboardingPluginStart;
|
||||
lens: LensPublicStart;
|
||||
licensing: LicensingPluginStart;
|
||||
observabilityShared: ObservabilitySharedPluginStart;
|
||||
|
|
|
@ -63,7 +63,7 @@ export type ObservabilityPluginSetup = ReturnType<ObservabilityPlugin['setup']>;
|
|||
interface PluginSetup {
|
||||
alerting: PluginSetupContract;
|
||||
features: FeaturesSetup;
|
||||
guidedOnboarding: GuidedOnboardingPluginSetup;
|
||||
guidedOnboarding?: GuidedOnboardingPluginSetup;
|
||||
ruleRegistry: RuleRegistryPluginSetupContract;
|
||||
share: SharePluginSetup;
|
||||
spaces?: SpacesPluginSetup;
|
||||
|
@ -344,7 +344,7 @@ export class ObservabilityPlugin implements Plugin<ObservabilityPluginSetup> {
|
|||
/**
|
||||
* Register a config for the observability guide
|
||||
*/
|
||||
plugins.guidedOnboarding.registerGuideConfig(kubernetesGuideId, kubernetesGuideConfig);
|
||||
plugins.guidedOnboarding?.registerGuideConfig(kubernetesGuideId, kubernetesGuideConfig);
|
||||
|
||||
return {
|
||||
getAlertDetailsConfig() {
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
"server": false,
|
||||
"browser": true,
|
||||
"configPath": ["xpack", "observability_shared"],
|
||||
"requiredPlugins": ["cases", "guidedOnboarding", "uiActions", "embeddable", "share"],
|
||||
"optionalPlugins": [],
|
||||
"requiredPlugins": ["cases", "uiActions", "embeddable", "share"],
|
||||
"optionalPlugins": ["guidedOnboarding"],
|
||||
"requiredBundles": ["data", "inspector", "kibanaReact", "kibanaUtils", "advancedSettings"],
|
||||
"extraPublicDirs": ["common"]
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ export interface ObservabilitySharedSetup {
|
|||
export interface ObservabilitySharedStart {
|
||||
spaces?: SpacesPluginStart;
|
||||
cases: CasesUiStart;
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
guidedOnboarding?: GuidedOnboardingPluginStart;
|
||||
setIsSidebarEnabled: (isEnabled: boolean) => void;
|
||||
embeddable: EmbeddableStart;
|
||||
share: SharePluginStart;
|
||||
|
@ -73,7 +73,7 @@ export class ObservabilitySharedPlugin implements Plugin {
|
|||
getUrlForApp: application.getUrlForApp,
|
||||
navigateToApp: application.navigateToApp,
|
||||
navigationSections$: this.navigationRegistry.sections$,
|
||||
guidedOnboardingApi: plugins.guidedOnboarding.guidedOnboardingApi,
|
||||
guidedOnboardingApi: plugins.guidedOnboarding?.guidedOnboardingApi,
|
||||
getPageTemplateServices: () => ({ coreStart: core }),
|
||||
isSidebarEnabled$: this.isSidebarEnabled$,
|
||||
});
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
"eventLog",
|
||||
"features",
|
||||
"fieldFormats",
|
||||
"guidedOnboarding",
|
||||
"inspector",
|
||||
"kubernetesSecurity",
|
||||
"lens",
|
||||
|
@ -69,7 +68,8 @@
|
|||
"telemetry",
|
||||
"dataViewFieldEditor",
|
||||
"osquery",
|
||||
"savedObjectsTaggingOss"
|
||||
"savedObjectsTaggingOss",
|
||||
"guidedOnboarding"
|
||||
],
|
||||
"requiredBundles": [
|
||||
"esUiShared",
|
||||
|
|
|
@ -36,22 +36,26 @@ const initialState: TourContextValue = {
|
|||
const TourContext = createContext<TourContextValue>(initialState);
|
||||
|
||||
export const RealTourContextProvider = ({ children }: { children: ReactChild }) => {
|
||||
const { guidedOnboardingApi } = useKibana().services.guidedOnboarding;
|
||||
const { guidedOnboarding } = useKibana().services;
|
||||
|
||||
const isRulesTourActive = useObservable(
|
||||
guidedOnboardingApi?.isGuideStepActive$(siemGuideId, SecurityStepId.rules).pipe(
|
||||
// if no result after 30s the observable will error, but the error handler will just emit false
|
||||
timeout(30000),
|
||||
catchError((error) => of(false))
|
||||
) ?? of(false),
|
||||
guidedOnboarding?.guidedOnboardingApi
|
||||
?.isGuideStepActive$(siemGuideId, SecurityStepId.rules)
|
||||
.pipe(
|
||||
// if no result after 30s the observable will error, but the error handler will just emit false
|
||||
timeout(30000),
|
||||
catchError((error) => of(false))
|
||||
) ?? of(false),
|
||||
false
|
||||
);
|
||||
const isAlertsCasesTourActive = useObservable(
|
||||
guidedOnboardingApi?.isGuideStepActive$(siemGuideId, SecurityStepId.alertsCases).pipe(
|
||||
// if no result after 30s the observable will error, but the error handler will just emit false
|
||||
timeout(30000),
|
||||
catchError((error) => of(false))
|
||||
) ?? of(false),
|
||||
guidedOnboarding?.guidedOnboardingApi
|
||||
?.isGuideStepActive$(siemGuideId, SecurityStepId.alertsCases)
|
||||
.pipe(
|
||||
// if no result after 30s the observable will error, but the error handler will just emit false
|
||||
timeout(30000),
|
||||
catchError((error) => of(false))
|
||||
) ?? of(false),
|
||||
false
|
||||
);
|
||||
|
||||
|
@ -79,12 +83,12 @@ export const RealTourContextProvider = ({ children }: { children: ReactChild })
|
|||
const [completeStep, setCompleteStep] = useState<null | SecurityStepId>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!completeStep || !guidedOnboardingApi) {
|
||||
if (!completeStep || !guidedOnboarding?.guidedOnboardingApi) {
|
||||
return;
|
||||
}
|
||||
let ignore = false;
|
||||
const complete = async () => {
|
||||
await guidedOnboardingApi.completeGuideStep(siemGuideId, completeStep);
|
||||
await guidedOnboarding?.guidedOnboardingApi?.completeGuideStep(siemGuideId, completeStep);
|
||||
if (!ignore) {
|
||||
setCompleteStep(null);
|
||||
_setActiveStep(1);
|
||||
|
@ -94,7 +98,7 @@ export const RealTourContextProvider = ({ children }: { children: ReactChild })
|
|||
return () => {
|
||||
ignore = true;
|
||||
};
|
||||
}, [completeStep, guidedOnboardingApi]);
|
||||
}, [completeStep, guidedOnboarding]);
|
||||
|
||||
const endTourStep = useCallback((tourId: SecurityStepId) => {
|
||||
setCompleteStep(tourId);
|
||||
|
|
|
@ -25,13 +25,10 @@ export const RulesPageTourComponent: React.FC<Props> = ({ children }) => {
|
|||
tourPopoverWidth: 300,
|
||||
};
|
||||
|
||||
const {
|
||||
storage,
|
||||
guidedOnboarding: { guidedOnboardingApi },
|
||||
} = useKibana().services;
|
||||
const { storage, guidedOnboarding } = useKibana().services;
|
||||
|
||||
const isGuidedOnboardingActive = useObservable(
|
||||
guidedOnboardingApi?.isGuideStepActive$(siemGuideId, 'rules') ?? of(false),
|
||||
guidedOnboarding?.guidedOnboardingApi?.isGuideStepActive$(siemGuideId, 'rules') ?? of(false),
|
||||
true
|
||||
);
|
||||
|
||||
|
|
|
@ -44,12 +44,12 @@ export enum GuidedOnboardingRulesStatus {
|
|||
}
|
||||
|
||||
export const RulesManagementTour = () => {
|
||||
const { guidedOnboardingApi } = useKibana().services.guidedOnboarding;
|
||||
const { guidedOnboarding } = useKibana().services;
|
||||
const { executeBulkAction } = useExecuteBulkAction();
|
||||
const { actions } = useRulesTableContext();
|
||||
|
||||
const isRulesStepActive = useObservable(
|
||||
guidedOnboardingApi?.isGuideStepActive$(siemGuideId, 'rules') ?? of(false),
|
||||
guidedOnboarding?.guidedOnboardingApi?.isGuideStepActive$(siemGuideId, 'rules') ?? of(false),
|
||||
false
|
||||
);
|
||||
|
||||
|
@ -106,9 +106,9 @@ export const RulesManagementTour = () => {
|
|||
// Synchronize the current "internal" tour step with the global one
|
||||
useEffect(() => {
|
||||
if (isRulesStepActive && tourStatus === GuidedOnboardingRulesStatus.completed) {
|
||||
guidedOnboardingApi?.completeGuideStep('siem', 'rules');
|
||||
guidedOnboarding?.guidedOnboardingApi?.completeGuideStep('siem', 'rules');
|
||||
}
|
||||
}, [guidedOnboardingApi, isRulesStepActive, tourStatus]);
|
||||
}, [guidedOnboarding, isRulesStepActive, tourStatus]);
|
||||
|
||||
const enableDemoRule = useCallback(async () => {
|
||||
if (demoRule) {
|
||||
|
|
|
@ -111,7 +111,7 @@ export interface StartPlugins {
|
|||
embeddable: EmbeddableStart;
|
||||
inspector: InspectorStart;
|
||||
fleet?: FleetStart;
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
guidedOnboarding?: GuidedOnboardingPluginStart;
|
||||
kubernetesSecurity: KubernetesSecurityStart;
|
||||
lens: LensPublicStart;
|
||||
lists?: ListsPluginStart;
|
||||
|
|
|
@ -416,19 +416,19 @@ export class Plugin implements ISecuritySolutionPlugin {
|
|||
depsStart.cloudExperiments
|
||||
.getVariation('security-solutions.guided-onboarding-content', defaultGuideTranslations)
|
||||
.then((variation) => {
|
||||
plugins.guidedOnboarding.registerGuideConfig(
|
||||
plugins.guidedOnboarding?.registerGuideConfig(
|
||||
siemGuideId,
|
||||
getSiemGuideConfig(variation)
|
||||
);
|
||||
});
|
||||
} catch {
|
||||
plugins.guidedOnboarding.registerGuideConfig(
|
||||
plugins.guidedOnboarding?.registerGuideConfig(
|
||||
siemGuideId,
|
||||
getSiemGuideConfig(defaultGuideTranslations)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
plugins.guidedOnboarding.registerGuideConfig(
|
||||
plugins.guidedOnboarding?.registerGuideConfig(
|
||||
siemGuideId,
|
||||
getSiemGuideConfig(defaultGuideTranslations)
|
||||
);
|
||||
|
|
|
@ -61,7 +61,7 @@ export interface SecuritySolutionPluginSetupDependencies {
|
|||
usageCollection?: UsageCollectionPluginSetup;
|
||||
licensing: LicensingPluginSetup;
|
||||
osquery: OsqueryPluginSetup;
|
||||
guidedOnboarding: GuidedOnboardingPluginSetup;
|
||||
guidedOnboarding?: GuidedOnboardingPluginSetup;
|
||||
unifiedSearch: UnifiedSearchServerPluginSetup;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ import { login } from '../../../tasks/login';
|
|||
import { visit } from '../../../tasks/navigation';
|
||||
import { startAlertsCasesTour } from '../../../tasks/api_calls/tour';
|
||||
|
||||
describe('Guided onboarding tour', { tags: ['@ess', '@brokenInServerless'] }, () => {
|
||||
describe('Guided onboarding tour', { tags: ['@ess'] }, () => {
|
||||
before(() => {
|
||||
cleanKibana();
|
||||
login();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue