From 007c3413df5ef87246fb398c662ba54c31fe08ef Mon Sep 17 00:00:00 2001 From: "Quynh Nguyen (Quinn)" <43350163+qn895@users.noreply.github.com> Date: Mon, 2 Oct 2023 09:45:34 -0500 Subject: [PATCH] [ML] Add Create a data view button to index or saved search selector in ML pages and Transforms management (#166668) Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/ml/public/application/app.tsx | 2 +- .../create_data_view_button.tsx | 59 +++++++++++++++++++ .../create_data_view_button/index.ts | 8 +++ .../contexts/kibana/kibana_context.ts | 4 +- .../source_selection/source_selection.tsx | 13 ++-- .../new_job/pages/index_or_search/page.tsx | 24 +++++--- x-pack/plugins/transform/kibana.jsonc | 1 + .../transform/public/app/app_dependencies.tsx | 2 + .../public/app/mount_management_section.ts | 2 + .../search_selection/search_selection.tsx | 54 +++++++++++++++-- .../transform_management_section.tsx | 2 +- x-pack/plugins/transform/public/plugin.ts | 2 + x-pack/plugins/transform/tsconfig.json | 3 +- 13 files changed, 152 insertions(+), 24 deletions(-) create mode 100644 x-pack/plugins/ml/public/application/components/create_data_view_button/create_data_view_button.tsx create mode 100644 x-pack/plugins/ml/public/application/components/create_data_view_button/index.ts diff --git a/x-pack/plugins/ml/public/application/app.tsx b/x-pack/plugins/ml/public/application/app.tsx index e403222815b9a..843f277c11eb5 100644 --- a/x-pack/plugins/ml/public/application/app.tsx +++ b/x-pack/plugins/ml/public/application/app.tsx @@ -83,13 +83,13 @@ const App: FC = ({ coreStart, deps, appMountParams, isServerless, mlFe kibanaVersion: deps.kibanaVersion, share: deps.share, data: deps.data, + dataViewEditor: deps.dataViewEditor, security: deps.security, licenseManagement: deps.licenseManagement, storage: localStorage, embeddable: deps.embeddable, maps: deps.maps, triggersActionsUi: deps.triggersActionsUi, - dataViewEditor: deps.dataViewEditor, dataVisualizer: deps.dataVisualizer, usageCollection: deps.usageCollection, fieldFormats: deps.fieldFormats, diff --git a/x-pack/plugins/ml/public/application/components/create_data_view_button/create_data_view_button.tsx b/x-pack/plugins/ml/public/application/components/create_data_view_button/create_data_view_button.tsx new file mode 100644 index 0000000000000..069b5589eb058 --- /dev/null +++ b/x-pack/plugins/ml/public/application/components/create_data_view_button/create_data_view_button.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiButton } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import React, { useCallback, useEffect, useRef } from 'react'; +import { useMlKibana } from '../../contexts/kibana'; + +export const CreateDataViewButton = ({ + onDataViewCreated, + allowAdHocDataView = false, +}: { + onDataViewCreated: (id: string, type: string, name?: string) => void; + allowAdHocDataView?: boolean; +}) => { + const { dataViewEditor } = useMlKibana().services; + const canEditDataView = Boolean(dataViewEditor?.userPermissions.editDataView()); + const closeDataViewEditorRef = useRef<() => void | undefined>(); + + const createNewDataView = useCallback(() => { + closeDataViewEditorRef.current = dataViewEditor?.openEditor({ + onSave: async (dataView) => { + if (dataView.id && onDataViewCreated) { + onDataViewCreated(dataView.id, 'index-pattern', dataView.name); + } + }, + + allowAdHocDataView, + }); + }, [onDataViewCreated, dataViewEditor, allowAdHocDataView]); + + useEffect(function cleanUpFlyout() { + return () => { + // Close the editor when unmounting + if (closeDataViewEditorRef.current) { + closeDataViewEditorRef.current(); + } + }; + }, []); + + return canEditDataView ? ( + + + + ) : null; +}; diff --git a/x-pack/plugins/ml/public/application/components/create_data_view_button/index.ts b/x-pack/plugins/ml/public/application/components/create_data_view_button/index.ts new file mode 100644 index 0000000000000..ef0244c8a1c17 --- /dev/null +++ b/x-pack/plugins/ml/public/application/components/create_data_view_button/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export { CreateDataViewButton } from './create_data_view_button'; diff --git a/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts b/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts index f9bd1fe2315b3..3e999cb1d8aa4 100644 --- a/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts +++ b/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts @@ -29,13 +29,13 @@ import type { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-manag import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import type { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public'; import type { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public'; -import { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; +import type { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; import type { MlServicesContext } from '../../app'; interface StartPlugins { data: DataPublicPluginStart; - dataViews: DataViewsPublicPluginStart; dataViewEditor: DataViewEditorStart; + dataViews: DataViewsPublicPluginStart; security?: SecurityPluginSetup; licenseManagement?: LicenseManagementUIPluginSetup; share: SharePluginStart; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx index 29498b5ec8ef5..89c16fbb93050 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx @@ -11,6 +11,7 @@ import { i18n } from '@kbn/i18n'; import { getNestedProperty } from '@kbn/ml-nested-property'; import { SavedObjectFinder } from '@kbn/saved-objects-finder-plugin/public'; import type { SavedObjectCommon } from '@kbn/saved-objects-finder-plugin/common'; +import { CreateDataViewButton } from '../../../../../components/create_data_view_button'; import { useMlKibana, useNavigateToPath } from '../../../../../contexts/kibana'; import { useToastNotificationService } from '../../../../../services/toast_notification_service'; import { @@ -38,8 +39,8 @@ export const SourceSelection: FC = () => { const onSearchSelected = async ( id: string, type: string, - fullName: string, - savedObject: SavedObjectCommon + fullName?: string, + savedObject?: SavedObjectCommon ) => { // Kibana data views including `:` are cross-cluster search indices // and are not supported by Data Frame Analytics yet. For saved searches @@ -47,7 +48,7 @@ export const SourceSelection: FC = () => { // the selection before redirecting and show an error callout instead. let dataViewName = ''; - if (type === 'index-pattern') { + if (type === 'index-pattern' && savedObject) { dataViewName = getNestedProperty(savedObject, 'attributes.title'); } else if (type === 'search') { try { @@ -71,7 +72,7 @@ export const SourceSelection: FC = () => { } } - if (isCcsIndexPattern(dataViewName)) { + if (isCcsIndexPattern(dataViewName) && savedObject) { setIsCcsCallOut(true); if (type === 'search') { setCcsCallOutBodyText( @@ -157,7 +158,9 @@ export const SourceSelection: FC = () => { contentClient: contentManagement.client, uiSettings, }} - /> + > + + diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx index c4b81907e52b9..0bfa0ad5acdb7 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx @@ -5,11 +5,12 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { FC, useCallback } from 'react'; import { EuiPageBody, EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { SavedObjectFinder } from '@kbn/saved-objects-finder-plugin/public'; +import { CreateDataViewButton } from '../../../../components/create_data_view_button'; import { useMlKibana, useNavigateToPath } from '../../../../contexts/kibana'; import { MlPageHeader } from '../../../../components/page_header'; @@ -23,13 +24,16 @@ export const Page: FC = ({ nextStepPath }) => { const { contentManagement, uiSettings } = useMlKibana().services; const navigateToPath = useNavigateToPath(); - const onObjectSelection = (id: string, type: string) => { - navigateToPath( - `${nextStepPath}?${type === 'index-pattern' ? 'index' : 'savedSearchId'}=${encodeURIComponent( - id - )}` - ); - }; + const onObjectSelection = useCallback( + (id: string, type: string, name?: string) => { + navigateToPath( + `${nextStepPath}?${ + type === 'index-pattern' ? 'index' : 'savedSearchId' + }=${encodeURIComponent(id)}` + ); + }, + [navigateToPath, nextStepPath] + ); return (
@@ -75,7 +79,9 @@ export const Page: FC = ({ nextStepPath }) => { contentClient: contentManagement.client, uiSettings, }} - /> + > + +
diff --git a/x-pack/plugins/transform/kibana.jsonc b/x-pack/plugins/transform/kibana.jsonc index 4baea3243370a..ef3577846238a 100644 --- a/x-pack/plugins/transform/kibana.jsonc +++ b/x-pack/plugins/transform/kibana.jsonc @@ -29,6 +29,7 @@ "contentManagement", ], "optionalPlugins": [ + "dataViewEditor", "security", "usageCollection", "spaces", diff --git a/x-pack/plugins/transform/public/app/app_dependencies.tsx b/x-pack/plugins/transform/public/app/app_dependencies.tsx index 93d74ca706d43..05c59bb66baa8 100644 --- a/x-pack/plugins/transform/public/app/app_dependencies.tsx +++ b/x-pack/plugins/transform/public/app/app_dependencies.tsx @@ -37,6 +37,7 @@ import { ChartsPluginStart } from '@kbn/charts-plugin/public'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; import type { SettingsStart } from '@kbn/core-ui-settings-browser'; +import type { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; import type { GetMlSharedImportsReturnType } from '../shared_imports'; export interface AppDependencies { @@ -45,6 +46,7 @@ export interface AppDependencies { charts: ChartsPluginStart; chrome: ChromeStart; data: DataPublicPluginStart; + dataViewEditor?: DataViewEditorStart; dataViews: DataViewsPublicPluginStart; docLinks: DocLinksStart; fieldFormats: FieldFormatsStart; diff --git a/x-pack/plugins/transform/public/app/mount_management_section.ts b/x-pack/plugins/transform/public/app/mount_management_section.ts index f00596e1326b4..e6aad082acd6e 100644 --- a/x-pack/plugins/transform/public/app/mount_management_section.ts +++ b/x-pack/plugins/transform/public/app/mount_management_section.ts @@ -46,6 +46,7 @@ export async function mountManagementSection( const { data, dataViews, + dataViewEditor, share, spaces, triggersActionsUi, @@ -69,6 +70,7 @@ export async function mountManagementSection( application, chrome, data, + dataViewEditor, dataViews, docLinks, http, diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx index 3f2bd7fb70c0c..75731baf92c06 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx @@ -5,22 +5,49 @@ * 2.0. */ -import { EuiModalBody, EuiModalHeader, EuiModalHeaderTitle } from '@elastic/eui'; +import { EuiButton, EuiModalBody, EuiModalHeader, EuiModalHeaderTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import React, { type FC } from 'react'; +import React, { type FC, Fragment, useCallback, useEffect, useRef } from 'react'; import { SavedObjectFinder } from '@kbn/saved-objects-finder-plugin/public'; import { useAppDependencies } from '../../../../app_dependencies'; interface SearchSelectionProps { onSearchSelected: (searchId: string, searchType: string) => void; + onCloseModal: () => void; } const fixedPageSize: number = 8; -export const SearchSelection: FC = ({ onSearchSelected }) => { - const { contentManagement, uiSettings } = useAppDependencies(); +export const SearchSelection: FC = ({ onSearchSelected, onCloseModal }) => { + const { contentManagement, uiSettings, dataViewEditor } = useAppDependencies(); + + const canEditDataView = Boolean(dataViewEditor?.userPermissions.editDataView()); + + const closeDataViewEditor = useRef<() => void | undefined>(); + + const createNewDataView = useCallback(() => { + onCloseModal(); + closeDataViewEditor.current = dataViewEditor?.openEditor({ + onSave: async (dataView) => { + if (dataView.id) { + onSearchSelected(dataView.id, 'index-pattern'); + } + }, + + allowAdHocDataView: true, + }); + }, [dataViewEditor, onCloseModal, onSearchSelected]); + + useEffect(function cleanUpFlyout() { + return () => { + // Close the editor when unmounting + if (closeDataViewEditor.current) { + closeDataViewEditor.current(); + } + }; + }, []); return ( <> @@ -72,7 +99,24 @@ export const SearchSelection: FC = ({ onSearchSelected }) ]} fixedPageSize={fixedPageSize} services={{ contentClient: contentManagement.client, uiSettings }} - /> + > + {canEditDataView ? ( + + + + ) : ( + + )} + ); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx index 7e1f2ccd3bc09..b88d7fc88a7ce 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx @@ -330,7 +330,7 @@ export const TransformManagement: FC = () => { className="transformCreateTransformSearchDialog" data-test-subj="transformSelectSourceModal" > - + )} diff --git a/x-pack/plugins/transform/public/plugin.ts b/x-pack/plugins/transform/public/plugin.ts index 03b99ab85ad27..098b55765a889 100644 --- a/x-pack/plugins/transform/public/plugin.ts +++ b/x-pack/plugins/transform/public/plugin.ts @@ -24,12 +24,14 @@ import type { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-manag import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import type { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public'; import type { PluginInitializerContext } from '@kbn/core/public'; +import type { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; import { registerFeature } from './register_feature'; import { getTransformHealthRuleType } from './alerting'; export interface PluginsDependencies { charts: ChartsPluginStart; data: DataPublicPluginStart; + dataViewEditor?: DataViewEditorStart; unifiedSearch: UnifiedSearchPublicPluginStart; dataViews: DataViewsPublicPluginStart; management: ManagementSetup; diff --git a/x-pack/plugins/transform/tsconfig.json b/x-pack/plugins/transform/tsconfig.json index 7b41f101c15c1..d58a875eec9c5 100644 --- a/x-pack/plugins/transform/tsconfig.json +++ b/x-pack/plugins/transform/tsconfig.json @@ -68,7 +68,8 @@ "@kbn/ebt-tools", "@kbn/content-management-plugin", "@kbn/react-kibana-mount", - "@kbn/core-plugins-server" + "@kbn/core-plugins-server", + "@kbn/data-view-editor-plugin" ], "exclude": [ "target/**/*",