mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Add data CTA to datasource selector (#177958)
## Summary <img width="559" alt="Screenshot 2024-03-04 at 18 14 40" src="78c92804
-cbb0-4167-bb1e-58596fa81440"> Closes https://github.com/elastic/kibana/issues/176675 This PR adds the "Add data" CTA to the data selector. ## Changes * Make data source selector wider per designs * Add button using locator for the URL * Fixes story for the data source selector (it was broken before - this is a boy-scout-rule change) ## Open questions * Should this always be shown or only as long as the "Integrations" tab is active? In the designs there is a "New data view" button instead when data views are selected, but the issue doesn't mention it * This is very similar to the OnboardingLink component in the observability_logs_explorer plugin. However, the datasource selector is defined upstream in the logs_explorer plugin. One alternative would be to pass the button down in a generic manner, but I'm not sure whether it's worth the extra complexity, especially considering where the logs explorer is going. The question is whether this redundancy is OK for now or whether it's worth to resolve it. Another option would be to move this button into the logs_explorer plugin and re-use it from the observability_logs_explorer2696d7fcd3/x-pack/plugins/observability_solution/observability_logs_explorer/public/components/onboarding_link.tsx (L29)
Personally I think moving this button into the logs_explorer plugin and re-use it from the observability_logs_explorer is the best trade-off right now, but interested in your thoughts.
This commit is contained in:
parent
7390350791
commit
4cd65b4a3a
5 changed files with 101 additions and 21 deletions
|
@ -15,13 +15,17 @@ export const UNCATEGORIZED_TAB_ID = 'data-source-selector-uncategorized-tab';
|
|||
export const DATA_VIEWS_PANEL_ID = 'data-source-selector-data-views-panel';
|
||||
export const DATA_VIEWS_TAB_ID = 'data-source-selector-data-views-tab';
|
||||
|
||||
export const DATA_SOURCE_SELECTOR_WIDTH = 400;
|
||||
export const DATA_SOURCE_SELECTOR_WIDTH = 520;
|
||||
|
||||
export const showAllLogsLabel = i18n.translate(
|
||||
'xpack.logsExplorer.dataSourceSelector.showAllLogs',
|
||||
{ defaultMessage: 'Show all logs' }
|
||||
);
|
||||
|
||||
export const addDataLabel = i18n.translate('xpack.logsExplorer.dataSourceSelector.addDataLabel', {
|
||||
defaultMessage: 'Add data',
|
||||
});
|
||||
|
||||
export const integrationsLabel = i18n.translate(
|
||||
'xpack.logsExplorer.dataSourceSelector.integrations',
|
||||
{ defaultMessage: 'Integrations' }
|
||||
|
|
|
@ -11,6 +11,8 @@ import React, { useState } from 'react';
|
|||
import { I18nProvider } from '@kbn/i18n-react';
|
||||
import type { Meta, Story } from '@storybook/react';
|
||||
import { IndexPattern } from '@kbn/io-ts-utils';
|
||||
import { CoreStart } from '@kbn/core/public';
|
||||
import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public';
|
||||
import { DataViewDescriptor } from '../../../common/data_views/models/data_view_descriptor';
|
||||
import {
|
||||
AllDatasetSelection,
|
||||
|
@ -20,6 +22,7 @@ import {
|
|||
import { Dataset, Integration } from '../../../common/datasets';
|
||||
import { DataSourceSelector } from './data_source_selector';
|
||||
import { DataSourceSelectorProps, DataSourceSelectorSearchParams } from './types';
|
||||
import { IsDataViewAvailable } from '../../hooks/use_data_views';
|
||||
|
||||
const meta: Meta<typeof DataSourceSelector> = {
|
||||
component: DataSourceSelector,
|
||||
|
@ -42,6 +45,23 @@ const meta: Meta<typeof DataSourceSelector> = {
|
|||
};
|
||||
export default meta;
|
||||
|
||||
const coreMock = {
|
||||
share: {
|
||||
url: {
|
||||
locators: {
|
||||
get: () => {
|
||||
return {
|
||||
useUrl: () => 'http://localhost:5601/app/logs-explorer',
|
||||
navigate: () => {},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as unknown as CoreStart;
|
||||
|
||||
const KibanaReactContext = createKibanaReactContext(coreMock);
|
||||
|
||||
const DataSourceSelectorTemplate: Story<DataSourceSelectorProps> = (args) => {
|
||||
const [dataSourceSelection, setDataSourceSelection] = useState<DataSourceSelection>(() =>
|
||||
AllDatasetSelection.create()
|
||||
|
@ -63,6 +83,10 @@ const DataSourceSelectorTemplate: Story<DataSourceSelectorProps> = (args) => {
|
|||
setDataSourceSelection(newSelection);
|
||||
};
|
||||
|
||||
const isDataViewAvailable: IsDataViewAvailable = (dataView) => {
|
||||
return true;
|
||||
};
|
||||
|
||||
const filteredIntegrations = integrations.filter((integration) =>
|
||||
integration.name.includes(search.name as string)
|
||||
);
|
||||
|
@ -93,23 +117,26 @@ const DataSourceSelectorTemplate: Story<DataSourceSelectorProps> = (args) => {
|
|||
} = args;
|
||||
|
||||
return (
|
||||
<DataSourceSelector
|
||||
{...args}
|
||||
datasets={Boolean(datasetsError || isLoadingUncategorized) ? [] : sortedDatasets}
|
||||
dataViews={Boolean(dataViewsError || isLoadingDataViews) ? [] : sortedDataViews}
|
||||
dataSourceSelection={dataSourceSelection}
|
||||
integrations={Boolean(integrationsError || isLoadingIntegrations) ? [] : sortedIntegrations}
|
||||
onDataViewsSearch={setSearch}
|
||||
onDataViewsSort={setSearch}
|
||||
onIntegrationsLoadMore={onIntegrationsLoadMore}
|
||||
onIntegrationsSearch={setSearch}
|
||||
onIntegrationsSort={setSearch}
|
||||
onIntegrationsStreamsSearch={setSearch}
|
||||
onIntegrationsStreamsSort={setSearch}
|
||||
onSelectionChange={onSelectionChange}
|
||||
onUncategorizedSearch={setSearch}
|
||||
onUncategorizedSort={setSearch}
|
||||
/>
|
||||
<KibanaReactContext.Provider>
|
||||
<DataSourceSelector
|
||||
{...args}
|
||||
datasets={Boolean(datasetsError || isLoadingUncategorized) ? [] : sortedDatasets}
|
||||
dataViews={Boolean(dataViewsError || isLoadingDataViews) ? [] : sortedDataViews}
|
||||
dataSourceSelection={dataSourceSelection}
|
||||
integrations={Boolean(integrationsError || isLoadingIntegrations) ? [] : sortedIntegrations}
|
||||
isDataViewAvailable={isDataViewAvailable}
|
||||
onDataViewsSearch={setSearch}
|
||||
onDataViewsSort={setSearch}
|
||||
onIntegrationsLoadMore={onIntegrationsLoadMore}
|
||||
onIntegrationsSearch={setSearch}
|
||||
onIntegrationsSort={setSearch}
|
||||
onIntegrationsStreamsSearch={setSearch}
|
||||
onIntegrationsStreamsSort={setSearch}
|
||||
onSelectionChange={onSelectionChange}
|
||||
onUncategorizedSearch={setSearch}
|
||||
onUncategorizedSort={setSearch}
|
||||
/>
|
||||
</KibanaReactContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { EuiContextMenu, EuiHorizontalRule, EuiTab, EuiTabs } from '@elastic/eui';
|
||||
import { EuiContextMenu, EuiFlexGroup, EuiHorizontalRule, EuiTab, EuiTabs } from '@elastic/eui';
|
||||
import styled from '@emotion/styled';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useIntersectionRef } from '../../hooks/use_intersection_ref';
|
||||
|
@ -34,6 +34,7 @@ import {
|
|||
createIntegrationStatusItem,
|
||||
createUncategorizedStatusItem,
|
||||
} from './utils';
|
||||
import { AddDataButton } from './sub_components/add_data_button';
|
||||
|
||||
export function DataSourceSelector({
|
||||
datasets,
|
||||
|
@ -221,7 +222,10 @@ export function DataSourceSelector({
|
|||
closePopover={closePopover}
|
||||
onClick={togglePopover}
|
||||
>
|
||||
<Tabs>{tabEntries}</Tabs>
|
||||
<EuiFlexGroup justifyContent="spaceBetween" alignItems="center">
|
||||
<Tabs bottomBorder={false}>{tabEntries}</Tabs>
|
||||
{(tabId === INTEGRATIONS_TAB_ID || tabId === UNCATEGORIZED_TAB_ID) && <AddDataButton />}
|
||||
</EuiFlexGroup>
|
||||
<EuiHorizontalRule margin="none" />
|
||||
<SearchControls
|
||||
key={panelId}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { EuiButtonEmpty } from '@elastic/eui';
|
||||
import {
|
||||
OBSERVABILITY_ONBOARDING_LOCATOR,
|
||||
ObservabilityOnboardingLocatorParams,
|
||||
} from '@kbn/deeplinks-observability';
|
||||
import { getRouterLinkProps } from '@kbn/router-utils';
|
||||
import React from 'react';
|
||||
import { addDataLabel } from '../constants';
|
||||
import { useKibanaContextForPlugin } from '../../../utils/use_kibana';
|
||||
|
||||
export const AddDataButton: React.FunctionComponent<{}> = ({}) => {
|
||||
const {
|
||||
services: {
|
||||
share: { url: urlService },
|
||||
},
|
||||
} = useKibanaContextForPlugin();
|
||||
const locator = urlService.locators.get<ObservabilityOnboardingLocatorParams>(
|
||||
OBSERVABILITY_ONBOARDING_LOCATOR
|
||||
);
|
||||
|
||||
const onboardingUrl = locator?.useUrl({});
|
||||
|
||||
const navigateToOnboarding = () => {
|
||||
locator?.navigate({});
|
||||
};
|
||||
|
||||
const onboardingLinkProps = getRouterLinkProps({
|
||||
href: onboardingUrl,
|
||||
onClick: navigateToOnboarding,
|
||||
});
|
||||
|
||||
return (
|
||||
<EuiButtonEmpty {...onboardingLinkProps} iconType="plusInCircleFilled" size="xs">
|
||||
{addDataLabel}
|
||||
</EuiButtonEmpty>
|
||||
);
|
||||
};
|
|
@ -8,7 +8,7 @@ import type { ComponentType } from 'react';
|
|||
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
import type { DiscoverSetup, DiscoverStart } from '@kbn/discover-plugin/public';
|
||||
import type { SharePluginSetup } from '@kbn/share-plugin/public';
|
||||
import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
|
||||
import type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public';
|
||||
import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
|
||||
|
@ -36,4 +36,5 @@ export interface LogsExplorerStartDeps {
|
|||
fieldFormats: FieldFormatsStart;
|
||||
navigation: NavigationPublicPluginStart;
|
||||
unifiedSearch: UnifiedSearchPublicPluginStart;
|
||||
share: SharePluginStart;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue