Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Stateful sidenav] Welcome tour #194926

Merged
merged 28 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6d42a3b
Register global setting
sebelga Oct 4, 2024
9871ea3
Add tour to the SpacesNavControl
sebelga Oct 4, 2024
ff44a35
Add functional tests
sebelga Oct 4, 2024
bca12fb
Update jest tests
sebelga Oct 4, 2024
54a8364
Dont show the tour after editing the default space and set a solution
sebelga Oct 4, 2024
a828c85
Don't show tour after clicking on "Manage spaces" btn
sebelga Oct 7, 2024
cf246a8
Add more functional tests
sebelga Oct 7, 2024
6e8e7c8
Refactor
sebelga Oct 7, 2024
77d3eb6
Move tour logic to own folder and component
sebelga Oct 7, 2024
c9fca06
Fix functional test
sebelga Oct 7, 2024
12f4a9c
Merge branch 'main' into stateful-sidenav/welcome-tour
sebelga Oct 8, 2024
5d92a01
Merge remote-tracking branch 'upstream/main' into stateful-sidenav/we…
sebelga Oct 8, 2024
14d5974
Move the learn more btn inline
sebelga Oct 8, 2024
862eb61
Merge branch 'main' into stateful-sidenav/welcome-tour
sebelga Oct 9, 2024
eae5945
Update x-pack/plugins/spaces/public/nav_control/solution_view_tour/li…
sebelga Oct 9, 2024
b66d608
Make it more explicit that the tour is not shown when solution is cla…
sebelga Oct 9, 2024
d8ac760
Merge remote-tracking branch 'upstream/main' into stateful-sidenav/we…
sebelga Oct 9, 2024
954137d
Refactor using OnBoardingDefaultSolution
sebelga Oct 9, 2024
d7586fe
Fix jest test
sebelga Oct 9, 2024
a30e165
Merge remote-tracking branch 'upstream/main' into stateful-sidenav/we…
sebelga Oct 11, 2024
edc1252
Don't load spaces if the tour has been dismissed
sebelga Oct 11, 2024
0889760
Address CR feedback
sebelga Oct 11, 2024
7d2d8a7
Address CR changes
sebelga Oct 11, 2024
ed1d86e
Update snapshot
sebelga Oct 11, 2024
fc00407
Merge branch 'main' into stateful-sidenav/welcome-tour
sebelga Oct 13, 2024
91a8d71
Address CR changes
sebelga Oct 15, 2024
e0a6a18
Merge branch 'stateful-sidenav/welcome-tour' of github.com:sebelga/ki…
sebelga Oct 15, 2024
bdd0ea4
Merge remote-tracking branch 'upstream/main' into stateful-sidenav/we…
sebelga Oct 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions x-pack/plugins/spaces/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,8 @@ export const API_VERSIONS = {
v1: '2023-10-31',
},
};

/**
* The setting to control whether the Space Solution Tour is shown.
*/
export const SHOW_SPACE_SOLUTION_TOUR_SETTING = 'showSpaceSolutionTour';

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { getSpacesFeatureDescription } from '../../constants';
interface Props {
id: string;
isLoading: boolean;
toggleSpaceSelector: () => void;
onClickManageSpaceBtn: () => void;
capabilities: Capabilities;
navigateToApp: ApplicationStart['navigateToApp'];
}
Expand All @@ -45,7 +45,7 @@ export const SpacesDescription: FC<Props> = (props: Props) => {
<ManageSpacesButton
size="s"
style={{ width: `100%` }}
onClick={props.toggleSpaceSelector}
onClick={props.onClickManageSpaceBtn}
capabilities={props.capabilities}
navigateToApp={props.navigateToApp}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ interface Props {
spaces: Space[];
serverBasePath: string;
toggleSpaceSelector: () => void;
onClickManageSpaceBtn: () => void;
intl: InjectedIntl;
capabilities: Capabilities;
navigateToApp: ApplicationStart['navigateToApp'];
Expand Down Expand Up @@ -218,7 +219,7 @@ class SpacesMenuUI extends Component<Props> {
key="manageSpacesButton"
className="spcMenu__manageButton"
size="s"
onClick={this.props.toggleSpaceSelector}
onClick={this.props.onClickManageSpaceBtn}
capabilities={this.props.capabilities}
navigateToApp={this.props.navigateToApp}
/>
Expand Down
5 changes: 5 additions & 0 deletions x-pack/plugins/spaces/public/nav_control/nav_control.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import ReactDOM from 'react-dom';
import type { CoreStart } from '@kbn/core/public';
import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render';

import { initTour } from './solution_view_tour';
import type { EventTracker } from '../analytics';
import type { ConfigType } from '../config';
import type { SpacesManager } from '../spaces_manager';
Expand All @@ -22,6 +23,8 @@ export function initSpacesNavControl(
config: ConfigType,
eventTracker: EventTracker
) {
const { showTour$, onFinishTour } = initTour(core, spacesManager);

core.chrome.navControls.registerLeft({
order: 1000,
mount(targetDomElement: HTMLElement) {
Expand All @@ -47,6 +50,8 @@ export function initSpacesNavControl(
navigateToUrl={core.application.navigateToUrl}
allowSolutionVisibility={config.allowSolutionVisibility}
eventTracker={eventTracker}
showTour$={showTour$}
onFinishTour={onFinishTour}
/>
</Suspense>
</KibanaRenderContextProvider>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import {
EuiFieldSearch,
EuiHeaderSectionItemButton,
EuiPopover,
EuiSelectable,
EuiSelectableListItem,
} from '@elastic/eui';
Expand All @@ -18,7 +17,7 @@ import * as Rx from 'rxjs';

import { findTestSubject, mountWithIntl } from '@kbn/test-jest-helpers';

import { NavControlPopover } from './nav_control_popover';
import { NavControlPopover, type Props as NavControlPopoverProps } from './nav_control_popover';
import type { Space } from '../../common';
import { EventTracker } from '../analytics';
import { SpaceAvatarInternal } from '../space_avatar/space_avatar_internal';
Expand Down Expand Up @@ -49,7 +48,12 @@ const reportEvent = jest.fn();
const eventTracker = new EventTracker({ reportEvent });

describe('NavControlPopover', () => {
async function setup(spaces: Space[], allowSolutionVisibility = false, activeSpace?: Space) {
async function setup(
spaces: Space[],
allowSolutionVisibility = false,
activeSpace?: Space,
props?: Partial<NavControlPopoverProps>
) {
const spacesManager = spacesManagerMock.create();
spacesManager.getSpaces = jest.fn().mockResolvedValue(spaces);

Expand All @@ -68,6 +72,9 @@ describe('NavControlPopover', () => {
navigateToUrl={jest.fn()}
allowSolutionVisibility={allowSolutionVisibility}
eventTracker={eventTracker}
showTour$={Rx.of(false)}
onFinishTour={jest.fn()}
{...props}
/>
);

Expand All @@ -81,7 +88,7 @@ describe('NavControlPopover', () => {
it('renders without crashing', () => {
const spacesManager = spacesManagerMock.create();

const { baseElement } = render(
const { baseElement, queryByTestId } = render(
<NavControlPopover
spacesManager={spacesManager as unknown as SpacesManager}
serverBasePath={'/server-base-path'}
Expand All @@ -91,9 +98,12 @@ describe('NavControlPopover', () => {
navigateToUrl={jest.fn()}
allowSolutionVisibility={false}
eventTracker={eventTracker}
showTour$={Rx.of(false)}
onFinishTour={jest.fn()}
/>
);
expect(baseElement).toMatchSnapshot();
expect(queryByTestId('spaceSolutionTour')).toBeNull();
});

it('renders a SpaceAvatar with the active space', async () => {
Expand All @@ -117,6 +127,8 @@ describe('NavControlPopover', () => {
navigateToUrl={jest.fn()}
allowSolutionVisibility={false}
eventTracker={eventTracker}
showTour$={Rx.of(false)}
onFinishTour={jest.fn()}
/>
);

Expand Down Expand Up @@ -223,20 +235,29 @@ describe('NavControlPopover', () => {
});

it('can close its popover', async () => {
jest.useFakeTimers();
const wrapper = await setup(mockSpaces);

expect(findTestSubject(wrapper, 'spaceMenuPopoverPanel').exists()).toEqual(false); // closed

// Open the popover
await act(async () => {
wrapper.find(EuiHeaderSectionItemButton).find('button').simulate('click');
});
wrapper.update();
expect(wrapper.find(EuiPopover).props().isOpen).toEqual(true);
expect(findTestSubject(wrapper, 'spaceMenuPopoverPanel').exists()).toEqual(true); // open

// Close the popover
await act(async () => {
wrapper.find(EuiPopover).props().closePopover();
wrapper.find(EuiHeaderSectionItemButton).find('button').simulate('click');
});
act(() => {
jest.runAllTimers();
});
wrapper.update();
expect(findTestSubject(wrapper, 'spaceMenuPopoverPanel').exists()).toEqual(false); // closed

expect(wrapper.find(EuiPopover).props().isOpen).toEqual(false);
jest.useRealTimers();
});

it('should render solution for spaces', async () => {
Expand Down Expand Up @@ -301,4 +322,42 @@ describe('NavControlPopover', () => {
space_id_prev: 'space-1',
});
});

it('should show the solution view tour', async () => {
jest.useFakeTimers(); // the unerlying EUI tour component has a timeout that needs to be flushed for the test to pass
sebelga marked this conversation as resolved.
Show resolved Hide resolved

const spaces: Space[] = [
{
id: 'space-1',
name: 'Space-1',
disabledFeatures: [],
solution: 'classic',
},
];

const activeSpace = spaces[0];
const showTour$ = new Rx.BehaviorSubject(true);
const onFinishTour = jest.fn().mockImplementation(() => {
showTour$.next(false);
});

const wrapper = await setup(spaces, true /** allowSolutionVisibility **/, activeSpace, {
showTour$,
onFinishTour,
});

expect(findTestSubject(wrapper, 'spaceSolutionTour').exists()).toBe(true);

act(() => {
findTestSubject(wrapper, 'closeTourBtn').simulate('click');
});
act(() => {
jest.runAllTimers();
});
wrapper.update();

expect(findTestSubject(wrapper, 'spaceSolutionTour').exists()).toBe(false);

jest.useRealTimers();
});
});
Loading