Skip to content

Commit

Permalink
[ES|QL] Present ES|QL as an equal to data views on the "no data views…
Browse files Browse the repository at this point in the history
…" screen (elastic#194077)

## Summary

Resolves elastic#176291

### Screenshots

#### Discover/Dashboard/Visualize
<img width="1517" alt="image"
src="https://github.com/user-attachments/assets/c8fb4faf-8d2d-4043-a757-6f092d1fceb3">

#### Stack Management > Data view
<img width="1519" alt="image"
src="https://github.com/user-attachments/assets/bb3f28bd-0ce9-4c49-ace1-1be875e17ba3">

#### If User does not have privilege to create a Data View
<img width="1336" alt="image"
src="https://github.com/user-attachments/assets/bb3f4cbc-8213-41c0-bf09-bd47a9d264e4">

### Checklist

Delete any items that are not applicable to this PR.

- [x] Use a new SVG resource for the ES|QL illustration
- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [x] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [ ] Any UI touched in this PR does not create any new axe failures
(run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))
- [x] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [x] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Liam Thompson <32779855+leemthompo@users.noreply.github.com>
Co-authored-by: Andrea Del Rio <delrio.andre@gmail.com>
(cherry picked from commit 56e1e68)
  • Loading branch information
tsullivan committed Oct 9, 2024
1 parent a3da125 commit 709f9b1
Show file tree
Hide file tree
Showing 36 changed files with 2,132 additions and 234 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ import { getHasApiKeys$ } from '../lib/get_has_api_keys';
export interface Props {
/** Handler for successfully creating a new data view. */
onDataViewCreated: (dataView: unknown) => void;
/** Handler for when try ES|QL is clicked and user has been navigated to try ES|QL in discover. */
onESQLNavigationComplete?: () => void;
/** if set to true allows creation of an ad-hoc dataview from data view editor */
allowAdHocDataView?: boolean;
/** if the kibana instance is customly branded */
showPlainSpinner: boolean;
/** If the cluster has data, this handler allows the user to try ES|QL */
onTryESQL?: () => void;
/** Handler for when try ES|QL is clicked and user has been navigated to try ES|QL in discover. */
onESQLNavigationComplete?: () => void;
}

type AnalyticsNoDataPageProps = Props &
Expand Down Expand Up @@ -119,9 +121,10 @@ const flavors: {
*/
export const AnalyticsNoDataPage: React.FC<AnalyticsNoDataPageProps> = ({
onDataViewCreated,
onESQLNavigationComplete,
allowAdHocDataView,
showPlainSpinner,
onTryESQL,
onESQLNavigationComplete,
...services
}) => {
const { prependBasePath, kibanaGuideDocLink, getHttp: get, pageFlavor } = services;
Expand All @@ -138,8 +141,9 @@ export const AnalyticsNoDataPage: React.FC<AnalyticsNoDataPageProps> = ({
{...{
noDataConfig,
onDataViewCreated,
onESQLNavigationComplete,
allowAdHocDataView,
onTryESQL,
onESQLNavigationComplete,
showPlainSpinner,
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ export default {

export const Analytics = (params: AnalyticsNoDataPageStorybookParams) => {
return (
<AnalyticsNoDataPageProvider {...mock.getServices(params)}>
<Component {...mock.getProps()} />
<AnalyticsNoDataPageProvider {...mock.getProps(params)} {...mock.getServices(params)}>
<Component {...mock.getProps(params)} />
</AnalyticsNoDataPageProvider>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
getAnalyticsNoDataPageServicesMock,
getAnalyticsNoDataPageServicesMockWithCustomBranding,
} from '@kbn/shared-ux-page-analytics-no-data-mocks';
import { NoDataViewsPrompt } from '@kbn/shared-ux-prompt-no-data-views';

import { AnalyticsNoDataPageProvider } from './services';
import { AnalyticsNoDataPage as Component } from './analytics_no_data_page.component';
Expand All @@ -29,28 +30,86 @@ describe('AnalyticsNoDataPage', () => {
jest.resetAllMocks();
});

it('renders correctly', async () => {
const component = mountWithIntl(
<AnalyticsNoDataPageProvider {...services}>
<AnalyticsNoDataPage onDataViewCreated={onDataViewCreated} allowAdHocDataView={true} />
</AnalyticsNoDataPageProvider>
);
describe('loading state', () => {
it('renders correctly', async () => {
const component = mountWithIntl(
<AnalyticsNoDataPageProvider {...services}>
<AnalyticsNoDataPage onDataViewCreated={onDataViewCreated} allowAdHocDataView={true} />
</AnalyticsNoDataPageProvider>
);

await act(() => new Promise(setImmediate));
await act(() => new Promise(setImmediate));

expect(component.find(Component).length).toBe(1);
expect(component.find(Component).props().onDataViewCreated).toBe(onDataViewCreated);
expect(component.find(Component).props().allowAdHocDataView).toBe(true);
expect(component.find(Component).length).toBe(1);
expect(component.find(Component).props().onDataViewCreated).toBe(onDataViewCreated);
expect(component.find(Component).props().allowAdHocDataView).toBe(true);
});

it('passes correct boolean value to showPlainSpinner', async () => {
const component = mountWithIntl(
<AnalyticsNoDataPageProvider {...servicesWithCustomBranding}>
<AnalyticsNoDataPage onDataViewCreated={onDataViewCreated} allowAdHocDataView={true} />
</AnalyticsNoDataPageProvider>
);

await act(async () => {
component.update();
});

expect(component.find(Component).length).toBe(1);
expect(component.find(Component).props().showPlainSpinner).toBe(true);
});
});

it('passes correct boolean value to showPlainSpinner', () => {
const component = mountWithIntl(
<AnalyticsNoDataPageProvider {...servicesWithCustomBranding}>
<AnalyticsNoDataPage onDataViewCreated={onDataViewCreated} allowAdHocDataView={true} />
</AnalyticsNoDataPageProvider>
);
describe('with ES data', () => {
jest.spyOn(services, 'hasESData').mockResolvedValue(true);
jest.spyOn(services, 'hasUserDataView').mockResolvedValue(false);

it('renders the prompt to create a data view', async () => {
const onTryESQL = jest.fn();

await act(async () => {
const component = mountWithIntl(
<AnalyticsNoDataPageProvider {...services}>
<AnalyticsNoDataPage
onDataViewCreated={onDataViewCreated}
allowAdHocDataView={true}
onTryESQL={onTryESQL}
/>
</AnalyticsNoDataPageProvider>
);

await new Promise(setImmediate);
component.update();

expect(component.find(Component).length).toBe(1);
expect(component.find(NoDataViewsPrompt).length).toBe(1);
});
});

it('renders the prompt to create a data view with a custom onTryESQL action', async () => {
const onTryESQL = jest.fn();

await act(async () => {
const component = mountWithIntl(
<AnalyticsNoDataPageProvider {...services}>
<AnalyticsNoDataPage
onDataViewCreated={onDataViewCreated}
allowAdHocDataView={true}
onTryESQL={onTryESQL}
/>
</AnalyticsNoDataPageProvider>
);

await new Promise(setImmediate);
component.update();

const tryESQLLink = component.find('button[data-test-subj="tryESQLLink"]');
expect(tryESQLLink.length).toBe(1);
tryESQLLink.simulate('click');

expect(component.find(Component).length).toBe(1);
expect(component.find(Component).props().showPlainSpinner).toBe(true);
expect(onTryESQL).toHaveBeenCalled();
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ import { AnalyticsNoDataPage as Component } from './analytics_no_data_page.compo
*/
export const AnalyticsNoDataPage = ({
onDataViewCreated,
onESQLNavigationComplete,
allowAdHocDataView,
onTryESQL,
onESQLNavigationComplete,
}: AnalyticsNoDataPageProps) => {
const { customBranding, ...services } = useServices();
const showPlainSpinner = useObservable(customBranding.hasCustomBranding$) ?? false;
Expand All @@ -33,6 +34,7 @@ export const AnalyticsNoDataPage = ({
allowAdHocDataView={allowAdHocDataView}
onDataViewCreated={onDataViewCreated}
onESQLNavigationComplete={onESQLNavigationComplete}
onTryESQL={onTryESQL}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@kbn/i18n-react",
"@kbn/core-http-browser",
"@kbn/core-http-browser-mocks",
"@kbn/shared-ux-prompt-no-data-views",
],
"exclude": [
"target/**/*",
Expand Down
18 changes: 15 additions & 3 deletions packages/shared-ux/page/analytics_no_data/mocks/src/storybook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@ import type {
} from '@kbn/shared-ux-page-analytics-no-data-types';
import { of } from 'rxjs';

interface PropArguments {
useCustomOnTryESQL: boolean;
}

type ServiceArguments = Pick<AnalyticsNoDataPageServices, 'kibanaGuideDocLink' | 'customBranding'>;

export type Params = ArgumentParams<{}, ServiceArguments> & KibanaNoDataPageStorybookParams;
export type Params = ArgumentParams<PropArguments, ServiceArguments> &
KibanaNoDataPageStorybookParams;

const kibanaNoDataMock = new KibanaNoDataPageStorybookMock();

Expand All @@ -30,7 +35,13 @@ export class StorybookMock extends AbstractStorybookMock<
{},
ServiceArguments
> {
propArguments = {};
propArguments = {
// requires hasESData to be toggled to true
useCustomOnTryESQL: {
control: 'boolean',
defaultValue: false,
},
};
serviceArguments = {
kibanaGuideDocLink: {
control: 'text',
Expand Down Expand Up @@ -59,9 +70,10 @@ export class StorybookMock extends AbstractStorybookMock<
};
}

getProps() {
getProps(params: Params) {
return {
onDataViewCreated: action('onDataViewCreated'),
onTryESQL: params.useCustomOnTryESQL ? action('onTryESQL-from-props') : undefined,
};
}
}
2 changes: 2 additions & 0 deletions packages/shared-ux/page/analytics_no_data/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ export interface AnalyticsNoDataPageProps {
onDataViewCreated: (dataView: unknown) => void;
/** if set to true allows creation of an ad-hoc data view from data view editor */
allowAdHocDataView?: boolean;
/** If the cluster has data, this handler allows the user to try ES|QL */
onTryESQL?: () => void;
/** Handler for when try ES|QL is clicked and user has been navigated to try ES|QL in discover. */
onESQLNavigationComplete?: () => void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ import { useServices } from './services';
*/
export const KibanaNoDataPage = ({
onDataViewCreated,
onESQLNavigationComplete,
noDataConfig,
allowAdHocDataView,
onTryESQL,
onESQLNavigationComplete,
showPlainSpinner,
}: KibanaNoDataPageProps) => {
// These hooks are temporary, until this component is moved to a package.
Expand Down Expand Up @@ -58,8 +59,9 @@ export const KibanaNoDataPage = ({
return (
<NoDataViewsPrompt
onDataViewCreated={onDataViewCreated}
onESQLNavigationComplete={onESQLNavigationComplete}
allowAdHocDataView={allowAdHocDataView}
onTryESQL={onTryESQL}
onESQLNavigationComplete={onESQLNavigationComplete}
/>
);
}
Expand Down
2 changes: 2 additions & 0 deletions packages/shared-ux/page/kibana_no_data/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ export interface KibanaNoDataPageProps {
allowAdHocDataView?: boolean;
/** Set to true if the kibana is customly branded */
showPlainSpinner: boolean;
/** If the cluster has data, this handler allows the user to try ES|QL */
onTryESQL?: () => void;
/** Handler for when try ES|QL is clicked and user has been navigated to try ES|QL in discover. */
onESQLNavigationComplete?: () => void;
}
76 changes: 0 additions & 76 deletions packages/shared-ux/prompt/no_data_views/impl/src/actions.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,14 @@ export const DataViewIllustration = () => {
}
`;

return <img src={svg} css={css} alt="Data view illustration" />;
return (
<img
src={svg}
css={css}
alt="Data view illustration"
data-test-subj="DataViewIllustration"
width="110"
height="100"
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import { FormattedMessage } from '@kbn/i18n-react';

interface Props {
href: string;
['data-test-subj']?: string;
}

export function DocumentationLink({ href }: Props) {
export function DocumentationLink({ href, ['data-test-subj']: dataTestSubj }: Props) {
return (
<dl>
<EuiTitle size="xxs">
Expand All @@ -28,7 +29,7 @@ export function DocumentationLink({ href }: Props) {
</EuiTitle>
&emsp;
<dd className="eui-displayInline">
<EuiLink href={href} target="_blank" external>
<EuiLink href={href} target="_blank" data-test-subj={dataTestSubj} external>
<FormattedMessage
id="sharedUXPackages.noDataViewsPrompt.readDocumentation"
defaultMessage="Read the docs"
Expand Down
Loading

0 comments on commit 709f9b1

Please sign in to comment.