mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Onboarding] Create guided_onboarding plugin (#138611)
* [Guided onboarding] Smashed commit of all POC work for guided onboarding and guided onboarding example plugins * [Guided onboarding] Fixed type errors * [Guided onboarding] Removed guidedOnboardingExample limit * [Guided onboarding] Fixed a functonal test for exposed configs * [Guided onboarding] Fixed plugin limit * [Guided onboarding] Added more information to the example plugin * [Guided onboarding] Fixed no-console error * [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' * [Guided onboarding] Fixed snake case errors * move guided_onboarding out of x-pack Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Alison Goryachev <alison.goryachev@elastic.co>
This commit is contained in:
parent
7d6b5c6eb2
commit
95086f4365
41 changed files with 1666 additions and 0 deletions
|
@ -40,6 +40,7 @@
|
|||
"eventAnnotation": "src/plugins/event_annotation",
|
||||
"fieldFormats": "src/plugins/field_formats",
|
||||
"flot": "packages/kbn-flot-charts/lib",
|
||||
"guidedOnboarding": "src/plugins/guided_onboarding",
|
||||
"home": "src/plugins/home",
|
||||
"homePackages": "packages/home",
|
||||
"indexPatternEditor": "src/plugins/data_view_editor",
|
||||
|
|
|
@ -176,6 +176,10 @@ for use in their own application.
|
|||
|Index pattern fields formatters
|
||||
|
||||
|
||||
|{kib-repo}blob/{branch}/src/plugins/guided_onboarding/README.md[guidedOnboarding]
|
||||
|A Kibana plugin
|
||||
|
||||
|
||||
|{kib-repo}blob/{branch}/src/plugins/home/README.md[home]
|
||||
|Moves the legacy ui/registry/feature_catalogue module for registering "features" that should be shown in the home page's feature catalogue to a service within a "home" plugin. The feature catalogue refered to here should not be confused with the "feature" plugin for registering features used to derive UI capabilities for feature controls.
|
||||
|
||||
|
|
7
examples/guided_onboarding_example/.i18nrc.json
Executable file
7
examples/guided_onboarding_example/.i18nrc.json
Executable file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"prefix": "guidedOnboardingExample",
|
||||
"paths": {
|
||||
"guidedOnboardingExample": "."
|
||||
},
|
||||
"translations": ["translations/ja-JP.json"]
|
||||
}
|
9
examples/guided_onboarding_example/README.md
Executable file
9
examples/guided_onboarding_example/README.md
Executable file
|
@ -0,0 +1,9 @@
|
|||
# guidedOnboardingExample
|
||||
|
||||
A Kibana plugin
|
||||
|
||||
---
|
||||
|
||||
## Development
|
||||
|
||||
See the [kibana contributing guide](https://github.com/elastic/kibana/blob/main/CONTRIBUTING.md) for instructions setting up your development environment.
|
10
examples/guided_onboarding_example/common/index.ts
Executable file
10
examples/guided_onboarding_example/common/index.ts
Executable file
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* 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 const PLUGIN_ID = 'guidedOnboardingExample';
|
||||
export const PLUGIN_NAME = 'guidedOnboardingExample';
|
14
examples/guided_onboarding_example/kibana.json
Executable file
14
examples/guided_onboarding_example/kibana.json
Executable file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"id": "guidedOnboardingExample",
|
||||
"version": "1.0.0",
|
||||
"kibanaVersion": "kibana",
|
||||
"owner": {
|
||||
"name": "platform-onboarding",
|
||||
"githubTeam": "platform-onboarding"
|
||||
},
|
||||
"description": "Example plugin to consume guidedOnboarding",
|
||||
"server": false,
|
||||
"ui": true,
|
||||
"requiredPlugins": ["navigation", "guidedOnboarding"],
|
||||
"optionalPlugins": []
|
||||
}
|
30
examples/guided_onboarding_example/public/application.tsx
Executable file
30
examples/guided_onboarding_example/public/application.tsx
Executable file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 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 ReactDOM from 'react-dom';
|
||||
import { AppMountParameters, CoreStart } from '@kbn/core/public';
|
||||
import { AppPluginStartDependencies } from './types';
|
||||
import { GuidedOnboardingExampleApp } from './components/app';
|
||||
|
||||
export const renderApp = (
|
||||
{ notifications }: CoreStart,
|
||||
{ guidedOnboarding }: AppPluginStartDependencies,
|
||||
{ element, history }: AppMountParameters
|
||||
) => {
|
||||
ReactDOM.render(
|
||||
<GuidedOnboardingExampleApp
|
||||
notifications={notifications}
|
||||
guidedOnboarding={guidedOnboarding}
|
||||
history={history}
|
||||
/>,
|
||||
element
|
||||
);
|
||||
|
||||
return () => ReactDOM.unmountComponentAtNode(element);
|
||||
};
|
70
examples/guided_onboarding_example/public/components/app.tsx
Executable file
70
examples/guided_onboarding_example/public/components/app.tsx
Executable file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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 { FormattedMessage, I18nProvider } from '@kbn/i18n-react';
|
||||
import { Router, Switch, Route } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
EuiPage,
|
||||
EuiPageBody,
|
||||
EuiPageContent_Deprecated as EuiPageContent,
|
||||
EuiPageHeader,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { CoreStart, ScopedHistory } from '@kbn/core/public';
|
||||
|
||||
import { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public/types';
|
||||
import { StepTwo } from './step_two';
|
||||
import { StepOne } from './step_one';
|
||||
import { Main } from './main';
|
||||
|
||||
interface GuidedOnboardingExampleAppDeps {
|
||||
notifications: CoreStart['notifications'];
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
history: ScopedHistory;
|
||||
}
|
||||
|
||||
export const GuidedOnboardingExampleApp = (props: GuidedOnboardingExampleAppDeps) => {
|
||||
const { notifications, guidedOnboarding, history } = props;
|
||||
|
||||
return (
|
||||
<I18nProvider>
|
||||
<EuiPage restrictWidth="1000px">
|
||||
<EuiPageBody>
|
||||
<EuiPageHeader>
|
||||
<EuiTitle size="l">
|
||||
<h1>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.title"
|
||||
defaultMessage="Guided onboarding examples"
|
||||
/>
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
</EuiPageHeader>
|
||||
<EuiPageContent>
|
||||
<Router history={history}>
|
||||
<Switch>
|
||||
<Route exact path="/">
|
||||
<Main notifications={notifications} guidedOnboarding={guidedOnboarding} />
|
||||
</Route>
|
||||
<Route exact path="/stepOne">
|
||||
<StepOne guidedOnboarding={guidedOnboarding} />
|
||||
</Route>
|
||||
<Route exact path="/stepTwo">
|
||||
<StepTwo guidedOnboarding={guidedOnboarding} />
|
||||
</Route>
|
||||
</Switch>
|
||||
</Router>
|
||||
</EuiPageContent>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
</I18nProvider>
|
||||
);
|
||||
};
|
255
examples/guided_onboarding_example/public/components/main.tsx
Normal file
255
examples/guided_onboarding_example/public/components/main.tsx
Normal file
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* 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, { useEffect, useState } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
EuiButton,
|
||||
EuiFieldNumber,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiFormRow,
|
||||
EuiHorizontalRule,
|
||||
EuiPageContentBody_Deprecated as EuiPageContentBody,
|
||||
EuiPageContentHeader_Deprecated as EuiPageContentHeader,
|
||||
EuiSelect,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import {
|
||||
GuidedOnboardingPluginStart,
|
||||
GuidedOnboardingState,
|
||||
UseCase,
|
||||
} from '@kbn/guided-onboarding-plugin/public';
|
||||
import { CoreStart } from '@kbn/core/public';
|
||||
|
||||
interface MainProps {
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
notifications: CoreStart['notifications'];
|
||||
}
|
||||
export const Main = (props: MainProps) => {
|
||||
const {
|
||||
guidedOnboarding: { guidedOnboardingApi },
|
||||
notifications,
|
||||
} = props;
|
||||
const history = useHistory();
|
||||
const [guideState, setGuideState] = useState<GuidedOnboardingState | undefined>(undefined);
|
||||
|
||||
const [selectedGuide, setSelectedGuide] = useState<
|
||||
GuidedOnboardingState['activeGuide'] | undefined
|
||||
>(undefined);
|
||||
const [selectedStep, setSelectedStep] = useState<GuidedOnboardingState['activeStep'] | undefined>(
|
||||
undefined
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = guidedOnboardingApi?.fetchGuideState$().subscribe((newState) => {
|
||||
setGuideState(newState);
|
||||
});
|
||||
return () => subscription?.unsubscribe();
|
||||
}, [guidedOnboardingApi]);
|
||||
|
||||
const startGuide = async (guide: UseCase) => {
|
||||
const response = await guidedOnboardingApi?.updateGuideState({
|
||||
activeGuide: guide,
|
||||
activeStep: 'add_data',
|
||||
});
|
||||
|
||||
if (response) {
|
||||
notifications.toasts.addSuccess(
|
||||
i18n.translate('guidedOnboardingExample.startGuide.toastLabel', {
|
||||
defaultMessage: 'Guide (re-)started',
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const updateGuideState = async () => {
|
||||
const response = await guidedOnboardingApi?.updateGuideState({
|
||||
activeGuide: selectedGuide!,
|
||||
activeStep: selectedStep!,
|
||||
});
|
||||
|
||||
if (response) {
|
||||
notifications.toasts.addSuccess(
|
||||
i18n.translate('guidedOnboardingExample.updateGuideState.toastLabel', {
|
||||
defaultMessage: 'Guide state updated',
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiPageContentHeader>
|
||||
<EuiTitle>
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.main.title"
|
||||
defaultMessage="Guided setup state"
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
</EuiPageContentHeader>
|
||||
<EuiPageContentBody>
|
||||
<EuiText>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.main.currentStateTitle"
|
||||
defaultMessage="Current state"
|
||||
/>
|
||||
</h3>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.guidesSelection.state.explanation"
|
||||
defaultMessage="The guide state on this page is updated automatically via an Observable,
|
||||
so there is no need to 'load' the state from the server."
|
||||
/>
|
||||
</p>
|
||||
{guideState ? (
|
||||
<dl>
|
||||
<dt>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.guidesSelection.state.activeGuideLabel"
|
||||
defaultMessage="Active guide"
|
||||
/>
|
||||
</dt>
|
||||
<dd>{guideState.activeGuide ?? 'undefined'}</dd>
|
||||
|
||||
<dt>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.guidesSelection.state.activeStepLabel"
|
||||
defaultMessage="Active step"
|
||||
/>
|
||||
</dt>
|
||||
<dd>{guideState.activeStep ?? 'undefined'}</dd>
|
||||
</dl>
|
||||
) : undefined}
|
||||
</EuiText>
|
||||
<EuiHorizontalRule />
|
||||
<EuiText>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.main.startGuide.title"
|
||||
defaultMessage="(Re-)Start a guide"
|
||||
/>
|
||||
</h3>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiButton onClick={() => startGuide('search')} fill>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.guidesSelection.search.buttonLabel"
|
||||
defaultMessage="(Re-)Start search guide"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiButton onClick={() => startGuide('observability')} fill>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.guidesSelection.observability.buttonLabel"
|
||||
defaultMessage="(Re-)Start observability guide"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiButton onClick={() => startGuide('security')} fill>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.guidesSelection.security.label"
|
||||
defaultMessage="(Re-)Start security guide"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer />
|
||||
<EuiHorizontalRule />
|
||||
<EuiText>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.main.setGuideState.title"
|
||||
defaultMessage="Set guide state"
|
||||
/>
|
||||
</h3>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow label="Guide" helpText="Select a guide">
|
||||
<EuiSelect
|
||||
id={'guideSelect'}
|
||||
options={[
|
||||
{ value: 'observability', text: 'observability' },
|
||||
{ value: 'security', text: 'security' },
|
||||
{ value: 'search', text: 'search' },
|
||||
{ value: '', text: 'unset' },
|
||||
]}
|
||||
value={selectedGuide}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value as UseCase;
|
||||
const shouldResetState = value.trim().length === 0;
|
||||
if (shouldResetState) {
|
||||
setSelectedGuide(undefined);
|
||||
setSelectedStep(undefined);
|
||||
} else {
|
||||
setSelectedGuide(value);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow label="Step">
|
||||
<EuiFieldNumber
|
||||
value={selectedStep}
|
||||
onChange={(e) => setSelectedStep(e.target.value)}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFormRow hasEmptyLabelSpace>
|
||||
<EuiButton onClick={updateGuideState}>Save</EuiButton>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer />
|
||||
<EuiHorizontalRule />
|
||||
<EuiText>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.main.examplePages.title"
|
||||
defaultMessage="Example pages"
|
||||
/>
|
||||
</h3>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton onClick={() => history.push('stepOne')}>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.main.examplePages.stepOne.link"
|
||||
defaultMessage="Step 1"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton onClick={() => history.push('stepTwo')}>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.main.examplePages.stepTwo.link"
|
||||
defaultMessage="Step 2"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPageContentBody>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* 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, { useEffect, useState } from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import {
|
||||
EuiButton,
|
||||
EuiText,
|
||||
EuiTourStep,
|
||||
EuiTitle,
|
||||
EuiPageContentHeader_Deprecated as EuiPageContentHeader,
|
||||
EuiPageContentBody_Deprecated as EuiPageContentBody,
|
||||
EuiSpacer,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public/types';
|
||||
|
||||
interface GuidedOnboardingExampleAppDeps {
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
}
|
||||
|
||||
export const StepOne = ({ guidedOnboarding }: GuidedOnboardingExampleAppDeps) => {
|
||||
const { guidedOnboardingApi } = guidedOnboarding;
|
||||
|
||||
const [isTourStepOpen, setIsTourStepOpen] = useState<boolean>(false);
|
||||
useEffect(() => {
|
||||
const subscription = guidedOnboardingApi?.fetchGuideState$().subscribe((newState) => {
|
||||
const { activeGuide: guide, activeStep: step } = newState;
|
||||
|
||||
if (guide === 'search' && step === 'add_data') {
|
||||
setIsTourStepOpen(true);
|
||||
}
|
||||
});
|
||||
return () => subscription?.unsubscribe();
|
||||
}, [guidedOnboardingApi]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiPageContentHeader>
|
||||
<EuiTitle>
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.stepOne.title"
|
||||
defaultMessage="Example step Add data"
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
</EuiPageContentHeader>
|
||||
<EuiPageContentBody>
|
||||
<EuiText>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.guidesSelection.stepOne.explanation"
|
||||
defaultMessage="The code on this page is listening to the guided setup state. If the state is set to
|
||||
Search guide, step Add data, a EUI tour will be displayed, pointing to the button below. Alternatively,
|
||||
the tour can be displayed via a localStorage value or a url param (see step 2)."
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiTourStep
|
||||
content={
|
||||
<EuiText>
|
||||
<p>Click this button to complete step 1.</p>
|
||||
</EuiText>
|
||||
}
|
||||
isStepOpen={isTourStepOpen}
|
||||
minWidth={300}
|
||||
onFinish={() => setIsTourStepOpen(false)}
|
||||
step={1}
|
||||
stepsTotal={1}
|
||||
title="Step Add data"
|
||||
anchorPosition="rightUp"
|
||||
>
|
||||
<EuiButton
|
||||
onClick={async () => {
|
||||
await guidedOnboardingApi?.updateGuideState({
|
||||
activeGuide: 'search',
|
||||
activeStep: 'search_experience',
|
||||
});
|
||||
}}
|
||||
>
|
||||
Complete step 1
|
||||
</EuiButton>
|
||||
</EuiTourStep>
|
||||
</EuiPageContentBody>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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, { useEffect, useState } from 'react';
|
||||
|
||||
import { EuiButton, EuiSpacer, EuiText, EuiTitle, EuiTourStep } from '@elastic/eui';
|
||||
|
||||
import { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public/types';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import {
|
||||
EuiPageContentHeader_Deprecated as EuiPageContentHeader,
|
||||
EuiPageContentBody_Deprecated as EuiPageContentBody,
|
||||
} from '@elastic/eui';
|
||||
|
||||
interface StepTwoProps {
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
}
|
||||
|
||||
export const StepTwo = (props: StepTwoProps) => {
|
||||
const {
|
||||
guidedOnboarding: { guidedOnboardingApi },
|
||||
} = props;
|
||||
const { search } = useLocation();
|
||||
const history = useHistory();
|
||||
|
||||
const query = React.useMemo(() => new URLSearchParams(search), [search]);
|
||||
useEffect(() => {
|
||||
if (query.get('showTour') === 'true') {
|
||||
setIsTourStepOpen(true);
|
||||
}
|
||||
}, [query]);
|
||||
|
||||
const [isTourStepOpen, setIsTourStepOpen] = useState<boolean>(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiPageContentHeader>
|
||||
<EuiTitle>
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.stepTwo.title"
|
||||
defaultMessage="Example step 2"
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
</EuiPageContentHeader>
|
||||
<EuiPageContentBody>
|
||||
<EuiText>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="guidedOnboardingExample.guidesSelection.stepTwo.explanation"
|
||||
defaultMessage="The EUI tour on this page is displayed, when a url param 'showTour' is set to 'true'."
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiTourStep
|
||||
content={
|
||||
<EuiText>
|
||||
<p>Click this button to complete step 2.</p>
|
||||
</EuiText>
|
||||
}
|
||||
isStepOpen={isTourStepOpen}
|
||||
minWidth={300}
|
||||
onFinish={() => {
|
||||
history.push('/stepTwo');
|
||||
query.set('showTour', 'false');
|
||||
setIsTourStepOpen(false);
|
||||
}}
|
||||
step={1}
|
||||
stepsTotal={1}
|
||||
title="Step Add data"
|
||||
anchorPosition="rightUp"
|
||||
>
|
||||
<EuiButton
|
||||
onClick={async () => {
|
||||
await guidedOnboardingApi?.updateGuideState({
|
||||
activeGuide: 'search',
|
||||
activeStep: 'optimize',
|
||||
});
|
||||
}}
|
||||
>
|
||||
Complete step 2
|
||||
</EuiButton>
|
||||
</EuiTourStep>
|
||||
</EuiPageContentBody>
|
||||
</>
|
||||
);
|
||||
};
|
19
examples/guided_onboarding_example/public/index.ts
Executable file
19
examples/guided_onboarding_example/public/index.ts
Executable file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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 { GuidedOnboardingExamplePlugin } from './plugin';
|
||||
|
||||
// This exports static code and TypeScript types,
|
||||
// as well as, Kibana Platform `plugin()` initializer.
|
||||
export function plugin() {
|
||||
return new GuidedOnboardingExamplePlugin();
|
||||
}
|
||||
export type {
|
||||
GuidedOnboardingExamplePluginSetup,
|
||||
GuidedOnboardingExamplePluginStart,
|
||||
} from './types';
|
43
examples/guided_onboarding_example/public/plugin.ts
Executable file
43
examples/guided_onboarding_example/public/plugin.ts
Executable file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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 { AppMountParameters, CoreSetup, CoreStart, Plugin } from '@kbn/core/public';
|
||||
import {
|
||||
GuidedOnboardingExamplePluginSetup,
|
||||
GuidedOnboardingExamplePluginStart,
|
||||
AppPluginStartDependencies,
|
||||
} from './types';
|
||||
import { PLUGIN_NAME } from '../common';
|
||||
|
||||
export class GuidedOnboardingExamplePlugin
|
||||
implements Plugin<GuidedOnboardingExamplePluginSetup, GuidedOnboardingExamplePluginStart>
|
||||
{
|
||||
public setup(core: CoreSetup): GuidedOnboardingExamplePluginSetup {
|
||||
// Register an application into the side navigation menu
|
||||
core.application.register({
|
||||
id: 'guidedOnboardingExample',
|
||||
title: PLUGIN_NAME,
|
||||
async mount(params: AppMountParameters) {
|
||||
// Load application bundle
|
||||
const { renderApp } = await import('./application');
|
||||
// Get start services as specified in kibana.json
|
||||
const [coreStart, depsStart] = await core.getStartServices();
|
||||
// Render the application
|
||||
return renderApp(coreStart, depsStart as AppPluginStartDependencies, params);
|
||||
},
|
||||
});
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
public start(core: CoreStart): GuidedOnboardingExamplePluginStart {
|
||||
return {};
|
||||
}
|
||||
|
||||
public stop() {}
|
||||
}
|
21
examples/guided_onboarding_example/public/types.ts
Executable file
21
examples/guided_onboarding_example/public/types.ts
Executable file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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 { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public';
|
||||
import { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public/types';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface GuidedOnboardingExamplePluginSetup {}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface GuidedOnboardingExamplePluginStart {}
|
||||
|
||||
export interface AppPluginStartDependencies {
|
||||
navigation: NavigationPublicPluginStart;
|
||||
guidedOnboarding: GuidedOnboardingPluginStart;
|
||||
}
|
24
examples/guided_onboarding_example/tsconfig.json
Normal file
24
examples/guided_onboarding_example/tsconfig.json
Normal file
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./target/types",
|
||||
"emitDeclarationOnly": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true
|
||||
},
|
||||
"include": [
|
||||
"__jest__/**/*",
|
||||
"common/**/*",
|
||||
"public/**/*",
|
||||
"server/**/*",
|
||||
"../../typings/**/*",
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../src/core/tsconfig.json"
|
||||
},
|
||||
{
|
||||
"path": "../../src/plugins/guided_onboarding/tsconfig.json"
|
||||
},
|
||||
]
|
||||
}
|
|
@ -56,6 +56,7 @@ pageLoadAssetSize:
|
|||
globalSearchProviders: 25554
|
||||
graph: 31504
|
||||
grokdebugger: 26779
|
||||
guidedOnboarding: 26875
|
||||
home: 30182
|
||||
indexLifecycleManagement: 107090
|
||||
indexManagement: 140608
|
||||
|
|
|
@ -59,6 +59,7 @@ const previouslyRegisteredTypes = [
|
|||
'fleet-enrollment-api-keys',
|
||||
'fleet-preconfiguration-deletion-record',
|
||||
'graph-workspace',
|
||||
'guided-setup-state',
|
||||
'index-pattern',
|
||||
'infrastructure-monitoring-log-view',
|
||||
'infrastructure-ui-source',
|
||||
|
|
7
src/plugins/guided_onboarding/.i18nrc.json
Executable file
7
src/plugins/guided_onboarding/.i18nrc.json
Executable file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"prefix": "guidedOnboarding",
|
||||
"paths": {
|
||||
"guidedOnboarding": "."
|
||||
},
|
||||
"translations": ["translations/ja-JP.json"]
|
||||
}
|
9
src/plugins/guided_onboarding/README.md
Executable file
9
src/plugins/guided_onboarding/README.md
Executable file
|
@ -0,0 +1,9 @@
|
|||
# guidedOnboarding
|
||||
|
||||
A Kibana plugin
|
||||
|
||||
---
|
||||
|
||||
## Development
|
||||
|
||||
See the [kibana contributing guide](https://github.com/elastic/kibana/blob/main/CONTRIBUTING.md) for instructions setting up your development environment.
|
12
src/plugins/guided_onboarding/common/index.ts
Executable file
12
src/plugins/guided_onboarding/common/index.ts
Executable file
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* 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 const PLUGIN_ID = 'guidedOnboarding';
|
||||
export const PLUGIN_NAME = 'guidedOnboarding';
|
||||
|
||||
export const API_BASE_PATH = '/api/guided_onboarding';
|
15
src/plugins/guided_onboarding/kibana.json
Executable file
15
src/plugins/guided_onboarding/kibana.json
Executable file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"id": "guidedOnboarding",
|
||||
"version": "1.0.0",
|
||||
"kibanaVersion": "kibana",
|
||||
"owner": {
|
||||
"name": "Journey Onboarding",
|
||||
"githubTeam": "platform-onboarding"
|
||||
},
|
||||
"description": "Guided onboarding framework",
|
||||
"server": true,
|
||||
"ui": true,
|
||||
"requiredBundles": ["kibanaReact"],
|
||||
"optionalPlugins": [],
|
||||
"configPath": ["guidedOnboarding"]
|
||||
}
|
9
src/plugins/guided_onboarding/public/components/index.ts
Normal file
9
src/plugins/guided_onboarding/public/components/index.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* 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 { GuidedOnboardingButton } from './onboarding_button';
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* 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, { useState, useEffect, useRef } from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import {
|
||||
EuiPopover,
|
||||
EuiPopoverTitle,
|
||||
EuiPopoverFooter,
|
||||
EuiButton,
|
||||
EuiText,
|
||||
EuiProgress,
|
||||
EuiAccordion,
|
||||
EuiHorizontalRule,
|
||||
EuiSpacer,
|
||||
EuiTextColor,
|
||||
htmlIdGenerator,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiIcon,
|
||||
useEuiTheme,
|
||||
EuiButtonEmpty,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { ApplicationStart } from '@kbn/core-application-browser';
|
||||
import { HttpStart } from '@kbn/core-http-browser';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { guidesConfig } from '../constants';
|
||||
import type { GuideConfig, StepStatus, GuidedOnboardingState, StepConfig } from '../types';
|
||||
import type { ApiService } from '../services/api';
|
||||
|
||||
interface Props {
|
||||
api: ApiService;
|
||||
application: ApplicationStart;
|
||||
http: HttpStart;
|
||||
}
|
||||
|
||||
const getConfig = (state?: GuidedOnboardingState): GuideConfig | undefined => {
|
||||
if (state?.activeGuide && state.activeGuide !== 'unset') {
|
||||
return guidesConfig[state.activeGuide];
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const getStepLabel = (steps?: StepConfig[], state?: GuidedOnboardingState): string => {
|
||||
if (steps && state?.activeStep) {
|
||||
const activeStepIndex = steps.findIndex((step: StepConfig) => step.id === state.activeStep);
|
||||
if (activeStepIndex > -1) {
|
||||
return `: Step ${activeStepIndex + 1}`;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
const getStepStatus = (steps: StepConfig[], stepIndex: number, activeStep?: string): StepStatus => {
|
||||
const activeStepIndex = steps.findIndex((step: StepConfig) => step.id === activeStep);
|
||||
if (activeStepIndex < stepIndex) {
|
||||
return 'incomplete';
|
||||
}
|
||||
if (activeStepIndex === stepIndex) {
|
||||
return 'in_progress';
|
||||
}
|
||||
return 'complete';
|
||||
};
|
||||
|
||||
export const GuidedOnboardingButton = ({ api, application, http }: Props) => {
|
||||
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
|
||||
|
||||
const [guidedOnboardingState, setGuidedOnboardingState] = useState<
|
||||
GuidedOnboardingState | undefined
|
||||
>(undefined);
|
||||
|
||||
const firstRender = useRef(true);
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = api.fetchGuideState$().subscribe((newState) => {
|
||||
if (
|
||||
guidedOnboardingState?.activeGuide !== newState.activeGuide ||
|
||||
guidedOnboardingState?.activeStep !== newState.activeStep
|
||||
) {
|
||||
if (firstRender.current) {
|
||||
firstRender.current = false;
|
||||
} else {
|
||||
setIsPopoverOpen(true);
|
||||
}
|
||||
}
|
||||
setGuidedOnboardingState(newState);
|
||||
});
|
||||
return () => subscription.unsubscribe();
|
||||
}, [api, guidedOnboardingState?.activeGuide, guidedOnboardingState?.activeStep]);
|
||||
|
||||
const { euiTheme } = useEuiTheme();
|
||||
|
||||
const togglePopover = () => {
|
||||
setIsPopoverOpen((prevIsPopoverOpen) => !prevIsPopoverOpen);
|
||||
};
|
||||
|
||||
const popoverContainerCss = css`
|
||||
width: 400px;
|
||||
`;
|
||||
|
||||
const statusCircleCss = ({ status }: { status: StepStatus }) => css`
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 32px;
|
||||
${(status === 'complete' || status === 'in_progress') &&
|
||||
`background-color: ${euiTheme.colors.success};`}
|
||||
${status === 'incomplete' &&
|
||||
`
|
||||
border: 2px solid ${euiTheme.colors.lightShade};
|
||||
`}
|
||||
`;
|
||||
|
||||
const guideConfig = getConfig(guidedOnboardingState);
|
||||
const stepLabel = getStepLabel(guideConfig?.steps, guidedOnboardingState);
|
||||
|
||||
const navigateToStep = (step: StepConfig) => {
|
||||
setIsPopoverOpen(false);
|
||||
if (step.location) {
|
||||
application.navigateToApp(step.location.appID, { path: step.location.path });
|
||||
}
|
||||
};
|
||||
|
||||
return guideConfig ? (
|
||||
<EuiPopover
|
||||
button={
|
||||
<EuiButton onClick={togglePopover} color="success" fill>
|
||||
{i18n.translate('guidedOnboarding.guidedSetupButtonLabel', {
|
||||
defaultMessage: 'Guided setup{stepLabel}',
|
||||
values: {
|
||||
stepLabel,
|
||||
},
|
||||
})}
|
||||
</EuiButton>
|
||||
}
|
||||
isOpen={isPopoverOpen}
|
||||
closePopover={() => setIsPopoverOpen(false)}
|
||||
anchorPosition="downRight"
|
||||
hasArrow={false}
|
||||
offset={10}
|
||||
panelPaddingSize="l"
|
||||
>
|
||||
<EuiPopoverTitle>
|
||||
<EuiButtonEmpty
|
||||
onClick={() => {}}
|
||||
iconSide="left"
|
||||
iconType="arrowLeft"
|
||||
isDisabled={true}
|
||||
flush="left"
|
||||
>
|
||||
{i18n.translate('guidedOnboarding.dropdownPanel.backToGuidesLink', {
|
||||
defaultMessage: 'Back to guides',
|
||||
})}
|
||||
</EuiButtonEmpty>
|
||||
<EuiTitle size="m">
|
||||
<h3>{guideConfig?.title}</h3>
|
||||
</EuiTitle>
|
||||
</EuiPopoverTitle>
|
||||
|
||||
<div css={popoverContainerCss}>
|
||||
<EuiText>
|
||||
<p>{guideConfig?.description}</p>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiHorizontalRule />
|
||||
<EuiProgress label="Progress" value={40} max={100} size="l" valueText />
|
||||
<EuiSpacer size="xl" />
|
||||
{guideConfig?.steps.map((step, index, steps) => {
|
||||
const accordionId = htmlIdGenerator(`accordion${index}`)();
|
||||
|
||||
const stepStatus = getStepStatus(steps, index, guidedOnboardingState?.activeStep);
|
||||
const buttonContent = (
|
||||
<EuiFlexGroup gutterSize="s">
|
||||
<EuiFlexItem grow={false}>
|
||||
<span css={statusCircleCss({ status: stepStatus })} className="eui-textCenter">
|
||||
<span className="euiScreenReaderOnly">{stepStatus}</span>
|
||||
{stepStatus === 'complete' && <EuiIcon type="check" color="white" />}
|
||||
</span>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>{step.title}</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<EuiAccordion
|
||||
id={accordionId}
|
||||
buttonContent={buttonContent}
|
||||
arrowDisplay="right"
|
||||
forceState={stepStatus === 'in_progress' ? 'open' : 'closed'}
|
||||
>
|
||||
<>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiText size="s">{step.description}</EuiText>
|
||||
<EuiSpacer />
|
||||
{stepStatus === 'in_progress' && (
|
||||
<EuiFlexGroup justifyContent="flexEnd">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton onClick={() => navigateToStep(step)} fill>
|
||||
{/* TODO: Support for conditional "Continue" button label if user revists a step */}
|
||||
{i18n.translate('guidedOnboarding.dropdownPanel.startStepButtonLabel', {
|
||||
defaultMessage: 'Start',
|
||||
})}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
)}
|
||||
</>
|
||||
</EuiAccordion>
|
||||
|
||||
{/* Do not show horizontal rule for last item */}
|
||||
{guideConfig.steps.length - 1 !== index && <EuiHorizontalRule margin="m" />}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<EuiPopoverFooter>
|
||||
<EuiText size="xs" textAlign="center">
|
||||
<EuiTextColor color="subdued">
|
||||
<p>
|
||||
{i18n.translate('guidedOnboarding.dropdownPanel.footerDescription', {
|
||||
defaultMessage: `Got questions? We're here to help.`,
|
||||
})}
|
||||
</p>
|
||||
</EuiTextColor>
|
||||
</EuiText>
|
||||
</EuiPopoverFooter>
|
||||
</div>
|
||||
</EuiPopover>
|
||||
) : (
|
||||
<EuiButton onClick={togglePopover} color="success" fill isDisabled={true}>
|
||||
Guided setup
|
||||
</EuiButton>
|
||||
);
|
||||
};
|
22
src/plugins/guided_onboarding/public/constants/index.ts
Normal file
22
src/plugins/guided_onboarding/public/constants/index.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* 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 { securityConfig } from './security';
|
||||
import { observabilityConfig } from './observability';
|
||||
import { searchConfig } from './search';
|
||||
import type { GuideConfig, UseCase } from '../types';
|
||||
|
||||
type GuidesConfig = {
|
||||
[key in UseCase]: GuideConfig;
|
||||
};
|
||||
|
||||
export const guidesConfig: GuidesConfig = {
|
||||
security: securityConfig,
|
||||
observability: observabilityConfig,
|
||||
search: searchConfig,
|
||||
};
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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 type { GuideConfig } from '../types';
|
||||
|
||||
export const observabilityConfig: GuideConfig = {
|
||||
title: 'Observe my infrastructure',
|
||||
description:
|
||||
'The foundation of seeing Elastic in action, is adding you own data. Follow links to our documents below to learn more.',
|
||||
docs: {
|
||||
text: 'Observability 101 Documentation',
|
||||
url: 'example.com',
|
||||
},
|
||||
steps: [
|
||||
{
|
||||
id: 'add_data',
|
||||
title: 'Add data',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ligula enim, malesuada a finibus vel, cursus sed risus. Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.',
|
||||
},
|
||||
{
|
||||
id: 'rules',
|
||||
title: 'Customize your alerting rules',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ligula enim, malesuada a finibus vel, cursus sed risus. Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.',
|
||||
},
|
||||
{
|
||||
id: 'infrastructure',
|
||||
title: 'View infrastructure details',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ligula enim, malesuada a finibus vel, cursus sed risus. Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.',
|
||||
},
|
||||
{
|
||||
id: 'explore',
|
||||
title: 'Explore Discover and Dashboards',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ligula enim, malesuada a finibus vel, cursus sed risus. Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.',
|
||||
},
|
||||
{
|
||||
id: 'tour',
|
||||
title: 'Tour Observability',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ligula enim, malesuada a finibus vel, cursus sed risus. Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.',
|
||||
},
|
||||
{
|
||||
id: 'do_more',
|
||||
title: 'Do more with Observability',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ligula enim, malesuada a finibus vel, cursus sed risus. Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.',
|
||||
},
|
||||
],
|
||||
};
|
52
src/plugins/guided_onboarding/public/constants/search.ts
Normal file
52
src/plugins/guided_onboarding/public/constants/search.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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 type { GuideConfig } from '../types';
|
||||
|
||||
export const searchConfig: GuideConfig = {
|
||||
title: 'Search my data',
|
||||
description: `We'll help you build world-class search experiences with your data.`,
|
||||
docs: {
|
||||
text: 'Enterprise Search 101 Documentation',
|
||||
url: 'example.com',
|
||||
},
|
||||
steps: [
|
||||
{
|
||||
id: 'add_data',
|
||||
title: 'Add data',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ligula enim, malesuada a finibus vel, cursus sed risus. Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.',
|
||||
location: {
|
||||
appID: 'guidedOnboardingExample',
|
||||
path: 'stepOne',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'search_experience',
|
||||
title: 'Build a search experience',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ligula enim, malesuada a finibus vel, cursus sed risus. Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.',
|
||||
location: {
|
||||
appID: 'guidedOnboardingExample',
|
||||
path: 'stepTwo?showTour=true',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'optimize',
|
||||
title: 'Optimize your search relevance',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ligula enim, malesuada a finibus vel, cursus sed risus. Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.',
|
||||
},
|
||||
{
|
||||
id: 'review',
|
||||
title: 'Review your search analytics',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ligula enim, malesuada a finibus vel, cursus sed risus. Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.',
|
||||
},
|
||||
],
|
||||
};
|
43
src/plugins/guided_onboarding/public/constants/security.ts
Normal file
43
src/plugins/guided_onboarding/public/constants/security.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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 type { GuideConfig } from '../types';
|
||||
|
||||
export const securityConfig: GuideConfig = {
|
||||
title: 'Get started with SIEM',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ligula enim, malesuada a finibus vel, cursus sed risus. Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.',
|
||||
steps: [
|
||||
{
|
||||
id: 'add_data',
|
||||
title: 'Add and view your data',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ligula enim, malesuada a finibus vel, cursus sed risus. Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.',
|
||||
},
|
||||
{
|
||||
id: 'rules',
|
||||
title: 'Turn on rules',
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
},
|
||||
{
|
||||
id: 'alerts',
|
||||
title: 'View Alerts',
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
},
|
||||
{
|
||||
id: 'cases',
|
||||
title: 'Cases and investigations',
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
},
|
||||
{
|
||||
id: 'do_more',
|
||||
title: 'Do more with Elastic Security',
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
},
|
||||
],
|
||||
};
|
20
src/plugins/guided_onboarding/public/index.ts
Executable file
20
src/plugins/guided_onboarding/public/index.ts
Executable file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* 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 { PluginInitializerContext } from '@kbn/core/public';
|
||||
import { GuidedOnboardingPlugin } from './plugin';
|
||||
|
||||
export function plugin(ctx: PluginInitializerContext) {
|
||||
return new GuidedOnboardingPlugin(ctx);
|
||||
}
|
||||
export type {
|
||||
GuidedOnboardingPluginSetup,
|
||||
GuidedOnboardingPluginStart,
|
||||
GuidedOnboardingState,
|
||||
UseCase,
|
||||
} from './types';
|
94
src/plugins/guided_onboarding/public/plugin.tsx
Executable file
94
src/plugins/guided_onboarding/public/plugin.tsx
Executable file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* 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 ReactDOM from 'react-dom';
|
||||
import React from 'react';
|
||||
import * as Rx from 'rxjs';
|
||||
import { I18nProvider } from '@kbn/i18n-react';
|
||||
import {
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
Plugin,
|
||||
CoreTheme,
|
||||
ApplicationStart,
|
||||
HttpStart,
|
||||
PluginInitializerContext,
|
||||
} from '@kbn/core/public';
|
||||
|
||||
import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public';
|
||||
import {
|
||||
ClientConfigType,
|
||||
GuidedOnboardingPluginSetup,
|
||||
GuidedOnboardingPluginStart,
|
||||
} from './types';
|
||||
import { GuidedOnboardingButton } from './components';
|
||||
import { ApiService, apiService } from './services/api';
|
||||
|
||||
export class GuidedOnboardingPlugin
|
||||
implements Plugin<GuidedOnboardingPluginSetup, GuidedOnboardingPluginStart>
|
||||
{
|
||||
constructor(private ctx: PluginInitializerContext) {}
|
||||
public setup(core: CoreSetup): GuidedOnboardingPluginSetup {
|
||||
return {};
|
||||
}
|
||||
|
||||
public start(core: CoreStart): GuidedOnboardingPluginStart {
|
||||
const { ui: isGuidedOnboardingUiEnabled } = this.ctx.config.get<ClientConfigType>();
|
||||
if (!isGuidedOnboardingUiEnabled) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const { chrome, http, theme, application } = core;
|
||||
|
||||
// Initialize services
|
||||
apiService.setup(http);
|
||||
|
||||
chrome.navControls.registerExtension({
|
||||
order: 1000,
|
||||
mount: (target) =>
|
||||
this.mount({
|
||||
targetDomElement: target,
|
||||
theme$: theme.theme$,
|
||||
api: apiService,
|
||||
application,
|
||||
http,
|
||||
}),
|
||||
});
|
||||
|
||||
// Return methods that should be available to other plugins
|
||||
return {
|
||||
guidedOnboardingApi: apiService,
|
||||
};
|
||||
}
|
||||
|
||||
public stop() {}
|
||||
|
||||
private mount({
|
||||
targetDomElement,
|
||||
theme$,
|
||||
api,
|
||||
application,
|
||||
http,
|
||||
}: {
|
||||
targetDomElement: HTMLElement;
|
||||
theme$: Rx.Observable<CoreTheme>;
|
||||
api: ApiService;
|
||||
application: ApplicationStart;
|
||||
http: HttpStart;
|
||||
}) {
|
||||
ReactDOM.render(
|
||||
<KibanaThemeProvider theme$={theme$}>
|
||||
<I18nProvider>
|
||||
<GuidedOnboardingButton api={api} application={application} http={http} />
|
||||
</I18nProvider>
|
||||
</KibanaThemeProvider>,
|
||||
targetDomElement
|
||||
);
|
||||
return () => ReactDOM.unmountComponentAtNode(targetDomElement);
|
||||
}
|
||||
}
|
59
src/plugins/guided_onboarding/public/services/api.ts
Normal file
59
src/plugins/guided_onboarding/public/services/api.ts
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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 { HttpSetup } from '@kbn/core/public';
|
||||
import { BehaviorSubject, map, from, concatMap, of } from 'rxjs';
|
||||
|
||||
import { API_BASE_PATH } from '../../common';
|
||||
import { GuidedOnboardingState } from '../types';
|
||||
|
||||
export class ApiService {
|
||||
private client: HttpSetup | undefined;
|
||||
private onboardingGuideState$!: BehaviorSubject<GuidedOnboardingState | undefined>;
|
||||
|
||||
public setup(httpClient: HttpSetup): void {
|
||||
this.client = httpClient;
|
||||
this.onboardingGuideState$ = new BehaviorSubject<GuidedOnboardingState | undefined>(undefined);
|
||||
}
|
||||
|
||||
public fetchGuideState$() {
|
||||
// TODO add error handling if this.client has not been initialized or request fails
|
||||
return this.onboardingGuideState$.pipe(
|
||||
concatMap((state) =>
|
||||
state === undefined
|
||||
? from(this.client!.get<{ state: GuidedOnboardingState }>(`${API_BASE_PATH}/state`)).pipe(
|
||||
map((response) => response.state)
|
||||
)
|
||||
: of(state)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public async updateGuideState(newState: GuidedOnboardingState) {
|
||||
if (!this.client) {
|
||||
throw new Error('ApiService has not be initialized.');
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await this.client.put<{ state: GuidedOnboardingState }>(
|
||||
`${API_BASE_PATH}/state`,
|
||||
{
|
||||
body: JSON.stringify(newState),
|
||||
}
|
||||
);
|
||||
this.onboardingGuideState$.next(newState);
|
||||
return response;
|
||||
} catch (error) {
|
||||
// TODO handle error
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const apiService = new ApiService();
|
54
src/plugins/guided_onboarding/public/types.ts
Executable file
54
src/plugins/guided_onboarding/public/types.ts
Executable file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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 { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public';
|
||||
import { ApiService } from './services/api';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface GuidedOnboardingPluginSetup {}
|
||||
|
||||
export interface GuidedOnboardingPluginStart {
|
||||
guidedOnboardingApi?: ApiService;
|
||||
}
|
||||
|
||||
export interface AppPluginStartDependencies {
|
||||
navigation: NavigationPublicPluginStart;
|
||||
}
|
||||
|
||||
export type UseCase = 'observability' | 'security' | 'search';
|
||||
export type StepStatus = 'incomplete' | 'complete' | 'in_progress';
|
||||
|
||||
export interface StepConfig {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
location?: {
|
||||
appID: string;
|
||||
path: string;
|
||||
};
|
||||
status?: StepStatus;
|
||||
}
|
||||
|
||||
export interface GuideConfig {
|
||||
title: string;
|
||||
description: string;
|
||||
docs?: {
|
||||
text: string;
|
||||
url: string;
|
||||
};
|
||||
steps: StepConfig[];
|
||||
}
|
||||
|
||||
export interface GuidedOnboardingState {
|
||||
activeGuide: UseCase | 'unset';
|
||||
activeStep: string | 'unset';
|
||||
}
|
||||
|
||||
export interface ClientConfigType {
|
||||
ui: boolean;
|
||||
}
|
25
src/plugins/guided_onboarding/server/config.ts
Normal file
25
src/plugins/guided_onboarding/server/config.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { PluginConfigDescriptor } from '@kbn/core/server';
|
||||
import { schema, TypeOf } from '@kbn/config-schema';
|
||||
|
||||
// By default, hide any guided onboarding UI. Change it with guidedOnboarding.ui:true in kibana.dev.yml
|
||||
const configSchema = schema.object({
|
||||
ui: schema.boolean({ defaultValue: false }),
|
||||
});
|
||||
|
||||
export type GuidedOnboardingConfig = TypeOf<typeof configSchema>;
|
||||
|
||||
export const config: PluginConfigDescriptor<GuidedOnboardingConfig> = {
|
||||
// define which config properties should be available in the client side plugin
|
||||
exposeToBrowser: {
|
||||
ui: true,
|
||||
},
|
||||
schema: configSchema,
|
||||
};
|
18
src/plugins/guided_onboarding/server/index.ts
Executable file
18
src/plugins/guided_onboarding/server/index.ts
Executable file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* 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 { PluginInitializerContext } from '@kbn/core/server';
|
||||
import { GuidedOnboardingPlugin } from './plugin';
|
||||
|
||||
export { config } from './config';
|
||||
|
||||
export function plugin(initializerContext: PluginInitializerContext) {
|
||||
return new GuidedOnboardingPlugin(initializerContext);
|
||||
}
|
||||
|
||||
export type { GuidedOnboardingPluginSetup, GuidedOnboardingPluginStart } from './types';
|
43
src/plugins/guided_onboarding/server/plugin.ts
Executable file
43
src/plugins/guided_onboarding/server/plugin.ts
Executable file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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 { PluginInitializerContext, CoreSetup, Plugin, Logger } from '@kbn/core/server';
|
||||
|
||||
import { GuidedOnboardingPluginSetup, GuidedOnboardingPluginStart } from './types';
|
||||
import { defineRoutes } from './routes';
|
||||
import { guidedSetupSavedObjects } from './saved_objects';
|
||||
|
||||
export class GuidedOnboardingPlugin
|
||||
implements Plugin<GuidedOnboardingPluginSetup, GuidedOnboardingPluginStart>
|
||||
{
|
||||
private readonly logger: Logger;
|
||||
|
||||
constructor(initializerContext: PluginInitializerContext) {
|
||||
this.logger = initializerContext.logger.get();
|
||||
}
|
||||
|
||||
public setup(core: CoreSetup) {
|
||||
this.logger.debug('guidedOnboarding: Setup');
|
||||
const router = core.http.createRouter();
|
||||
|
||||
// Register server side APIs
|
||||
defineRoutes(router);
|
||||
|
||||
// register saved objects
|
||||
core.savedObjects.registerType(guidedSetupSavedObjects);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
public start() {
|
||||
this.logger.debug('guidedOnboarding: Started');
|
||||
return {};
|
||||
}
|
||||
|
||||
public stop() {}
|
||||
}
|
101
src/plugins/guided_onboarding/server/routes/index.ts
Executable file
101
src/plugins/guided_onboarding/server/routes/index.ts
Executable file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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 { schema } from '@kbn/config-schema';
|
||||
import { IRouter, SavedObjectsClient } from '@kbn/core/server';
|
||||
import {
|
||||
guidedSetupDefaultState,
|
||||
guidedSetupSavedObjectsId,
|
||||
guidedSetupSavedObjectsType,
|
||||
} from '../saved_objects';
|
||||
|
||||
const doesGuidedSetupExist = async (savedObjectsClient: SavedObjectsClient): Promise<boolean> => {
|
||||
return savedObjectsClient
|
||||
.find({ type: guidedSetupSavedObjectsType })
|
||||
.then((foundSavedObjects) => foundSavedObjects.total > 0);
|
||||
};
|
||||
|
||||
export function defineRoutes(router: IRouter) {
|
||||
router.get(
|
||||
{
|
||||
path: '/api/guided_onboarding/state',
|
||||
validate: false,
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const coreContext = await context.core;
|
||||
const soClient = coreContext.savedObjects.client as SavedObjectsClient;
|
||||
|
||||
const stateExists = await doesGuidedSetupExist(soClient);
|
||||
if (stateExists) {
|
||||
const guidedSetupSO = await soClient.get(
|
||||
guidedSetupSavedObjectsType,
|
||||
guidedSetupSavedObjectsId
|
||||
);
|
||||
return response.ok({
|
||||
body: { state: guidedSetupSO.attributes },
|
||||
});
|
||||
} else {
|
||||
return response.ok({
|
||||
body: { state: guidedSetupDefaultState },
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
router.put(
|
||||
{
|
||||
path: '/api/guided_onboarding/state',
|
||||
validate: {
|
||||
body: schema.object({
|
||||
activeGuide: schema.maybe(schema.string()),
|
||||
activeStep: schema.maybe(schema.string()),
|
||||
}),
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const activeGuide = request.body.activeGuide;
|
||||
const activeStep = request.body.activeStep;
|
||||
const attributes = {
|
||||
activeGuide: activeGuide ?? 'unset',
|
||||
activeStep: activeStep ?? 'unset',
|
||||
};
|
||||
const coreContext = await context.core;
|
||||
const soClient = coreContext.savedObjects.client as SavedObjectsClient;
|
||||
|
||||
const stateExists = await doesGuidedSetupExist(soClient);
|
||||
|
||||
if (stateExists) {
|
||||
const updatedGuidedSetupSO = await soClient.update(
|
||||
guidedSetupSavedObjectsType,
|
||||
guidedSetupSavedObjectsId,
|
||||
attributes
|
||||
);
|
||||
return response.ok({
|
||||
body: { state: updatedGuidedSetupSO.attributes },
|
||||
});
|
||||
} else {
|
||||
const guidedSetupSO = await soClient.create(
|
||||
guidedSetupSavedObjectsType,
|
||||
{
|
||||
...guidedSetupDefaultState,
|
||||
...attributes,
|
||||
},
|
||||
{
|
||||
id: guidedSetupSavedObjectsId,
|
||||
}
|
||||
);
|
||||
|
||||
return response.ok({
|
||||
body: {
|
||||
state: guidedSetupSO.attributes,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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 { SavedObjectsType } from '@kbn/core/server';
|
||||
|
||||
export const guidedSetupSavedObjectsType = 'guided-setup-state';
|
||||
export const guidedSetupSavedObjectsId = 'guided-setup-state-id';
|
||||
export const guidedSetupDefaultState = {
|
||||
activeGuide: 'unset',
|
||||
activeStep: 'unset',
|
||||
};
|
||||
export const guidedSetupSavedObjects: SavedObjectsType = {
|
||||
name: guidedSetupSavedObjectsType,
|
||||
hidden: false,
|
||||
// make it available in all spaces for now
|
||||
namespaceType: 'agnostic',
|
||||
mappings: {
|
||||
dynamic: false,
|
||||
properties: {
|
||||
activeGuide: {
|
||||
type: 'keyword',
|
||||
},
|
||||
activeStep: {
|
||||
type: 'keyword',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
14
src/plugins/guided_onboarding/server/saved_objects/index.ts
Normal file
14
src/plugins/guided_onboarding/server/saved_objects/index.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* 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 {
|
||||
guidedSetupSavedObjects,
|
||||
guidedSetupSavedObjectsType,
|
||||
guidedSetupSavedObjectsId,
|
||||
guidedSetupDefaultState,
|
||||
} from './guided_setup';
|
13
src/plugins/guided_onboarding/server/types.ts
Executable file
13
src/plugins/guided_onboarding/server/types.ts
Executable 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.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface GuidedOnboardingPluginSetup {}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface GuidedOnboardingPluginStart {}
|
22
src/plugins/guided_onboarding/tsconfig.json
Normal file
22
src/plugins/guided_onboarding/tsconfig.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./target/types",
|
||||
"emitDeclarationOnly": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true
|
||||
},
|
||||
"include": ["common/**/*", "public/**/*", "server/**/*"],
|
||||
|
||||
"references": [
|
||||
{
|
||||
"path": "../../core/tsconfig.json"
|
||||
},
|
||||
{
|
||||
"path": "../navigation/tsconfig.json"
|
||||
},
|
||||
{
|
||||
"path": "../kibana_react/tsconfig.json"
|
||||
},
|
||||
]
|
||||
}
|
|
@ -106,6 +106,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
|
|||
'data.search.sessions.pageSize (number)',
|
||||
'data.search.sessions.trackingInterval (duration)',
|
||||
'enterpriseSearch.host (string)',
|
||||
'guidedOnboarding.ui (boolean)',
|
||||
'home.disableWelcomeScreen (boolean)',
|
||||
'map.emsFileApiUrl (string)',
|
||||
'map.emsFontLibraryUrl (string)',
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
"@kbn/expressions-explorer-plugin/*": ["examples/expressions_explorer/*"],
|
||||
"@kbn/field-formats-example-plugin": ["examples/field_formats_example"],
|
||||
"@kbn/field-formats-example-plugin/*": ["examples/field_formats_example/*"],
|
||||
"@kbn/guided-onboarding-example-plugin": ["examples/guided_onboarding_example"],
|
||||
"@kbn/guided-onboarding-example-plugin/*": ["examples/guided_onboarding_example/*"],
|
||||
"@kbn/hello-world-plugin": ["examples/hello_world"],
|
||||
"@kbn/hello-world-plugin/*": ["examples/hello_world/*"],
|
||||
"@kbn/locator-examples-plugin": ["examples/locator_examples"],
|
||||
|
@ -113,6 +115,8 @@
|
|||
"@kbn/expressions-plugin/*": ["src/plugins/expressions/*"],
|
||||
"@kbn/field-formats-plugin": ["src/plugins/field_formats"],
|
||||
"@kbn/field-formats-plugin/*": ["src/plugins/field_formats/*"],
|
||||
"@kbn/guided-onboarding-plugin": ["src/plugins/guided_onboarding"],
|
||||
"@kbn/guided-onboarding-plugin/*": ["src/plugins/guided_onboarding/*"],
|
||||
"@kbn/home-plugin": ["src/plugins/home"],
|
||||
"@kbn/home-plugin/*": ["src/plugins/home/*"],
|
||||
"@kbn/input-control-vis-plugin": ["src/plugins/input_control_vis"],
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue