From 4af89667c2d45365da2280d690a0ed1939c4ff33 Mon Sep 17 00:00:00 2001 From: Quynh Nguyen <43350163+qn895@users.noreply.github.com> Date: Tue, 14 Dec 2021 11:49:52 -0600 Subject: [PATCH] [ML] Add Maps ui action to Index data visualizer/Discover's Field statistics (#120846) * Add map UI actions to dv * Fix maps logo, comment * Add permission check for ui actions * Remove unnecessary json stringify because it no longer includes query object Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/data_visualizer/kibana.json | 6 +- .../field_data_row/action_menu/actions.ts | 126 ++++++++++++------ .../index_data_visualizer_view.tsx | 40 ++---- .../grid_embeddable/grid_embeddable.tsx | 1 + .../hooks/use_data_visualizer_grid_data.ts | 6 +- .../index_data_visualizer.tsx | 14 +- .../plugins/data_visualizer/public/plugin.ts | 2 + 7 files changed, 115 insertions(+), 80 deletions(-) diff --git a/x-pack/plugins/data_visualizer/kibana.json b/x-pack/plugins/data_visualizer/kibana.json index 8a4695cf08524..e8bca61a51ee8 100644 --- a/x-pack/plugins/data_visualizer/kibana.json +++ b/x-pack/plugins/data_visualizer/kibana.json @@ -10,7 +10,8 @@ "embeddable", "share", "discover", - "fileUpload" + "fileUpload", + "uiActions" ], "optionalPlugins": [ "security", @@ -26,7 +27,8 @@ "maps", "esUiShared", "fieldFormats", - "charts" + "charts", + "uiActions" ], "extraPublicDirs": [ "common" diff --git a/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/actions.ts b/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/actions.ts index 8476e53b9143f..831cf8aab02a9 100644 --- a/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/actions.ts +++ b/x-pack/plugins/data_visualizer/public/application/common/components/field_data_row/action_menu/actions.ts @@ -17,14 +17,16 @@ import { dataVisualizerRefresh$, Refresh, } from '../../../../index_data_visualizer/services/timefilter_refresh_service'; +import { JOB_FIELD_TYPES } from '../../../../../../common'; +import { VISUALIZE_GEO_FIELD_TRIGGER } from '../../../../../../../../../src/plugins/ui_actions/public'; export function getActions( indexPattern: IndexPattern, services: Partial, combinedQuery: CombinedQuery, - actionFlyoutRef: MutableRefObject<(() => void | undefined) | undefined> + dataViewEditorRef: MutableRefObject<(() => void | undefined) | undefined> | undefined ): Array> { - const { lens: lensPlugin, data } = services; + const { lens: lensPlugin, maps: mapsPlugin, data } = services; const actions: Array> = []; const filters = data?.query.filterManager.getFilters() ?? []; @@ -36,7 +38,7 @@ export function getActions( dataVisualizerRefresh$.next(refresh); }; // Navigate to Lens with prefilled chart for data field - if (lensPlugin !== undefined) { + if (services.application?.capabilities?.visualize?.show === true && lensPlugin !== undefined) { const canUseLensEditor = lensPlugin?.canUseEditor(); actions.push({ name: i18n.translate('xpack.dataVisualizer.index.dataGrid.exploreInLensTitle', { @@ -62,53 +64,93 @@ export function getActions( }); } - // Allow to edit data view field - if (services.dataViewFieldEditor?.userPermissions.editIndexPattern()) { + if ( + services?.uiActions && + mapsPlugin && + services.application?.capabilities?.maps?.show === true + ) { actions.push({ - name: i18n.translate('xpack.dataVisualizer.index.dataGrid.editDataViewFieldTitle', { - defaultMessage: 'Edit data view field', + name: i18n.translate('xpack.dataVisualizer.index.dataGrid.exploreInMapsTitle', { + defaultMessage: 'Explore in Maps', }), - description: i18n.translate( - 'xpack.dataVisualizer.index.dataGrid.editDataViewFieldDescription', - { - defaultMessage: 'Edit data view field', - } - ), - type: 'icon', - icon: 'indexEdit', - onClick: (item: FieldVisConfig) => { - actionFlyoutRef.current = services.dataViewFieldEditor?.openEditor({ - ctx: { dataView: indexPattern }, - fieldName: item.fieldName, - onSave: refreshPage, - }); - }, - 'data-test-subj': 'dataVisualizerActionEditIndexPatternFieldButton', - }); - actions.push({ - name: i18n.translate('xpack.dataVisualizer.index.dataGrid.deleteDataViewFieldTitle', { - defaultMessage: 'Delete data view field', + description: i18n.translate('xpack.dataVisualizer.index.dataGrid.exploreInMapsDescription', { + defaultMessage: 'Explore in Maps', }), - description: i18n.translate( - 'xpack.dataVisualizer.index.dataGrid.deleteIndexPatternFieldDescription', - { - defaultMessage: 'Delete data view field', - } - ), type: 'icon', - icon: 'trash', + icon: 'gisApp', available: (item: FieldVisConfig) => { - return item.deletable === true; + return item.type === JOB_FIELD_TYPES.GEO_POINT || item.type === JOB_FIELD_TYPES.GEO_SHAPE; }, - onClick: (item: FieldVisConfig) => { - actionFlyoutRef.current = services.dataViewFieldEditor?.openDeleteModal({ - ctx: { dataView: indexPattern }, - fieldName: item.fieldName!, - onDelete: refreshPage, - }); + onClick: async (item: FieldVisConfig) => { + if (services?.uiActions && indexPattern) { + const triggerOptions = { + indexPatternId: indexPattern.id, + fieldName: item.fieldName, + contextualFields: [], + }; + const testActions = await services?.uiActions.getTriggerCompatibleActions( + VISUALIZE_GEO_FIELD_TRIGGER, + triggerOptions + ); + + if (testActions.length > 0 && testActions[0] !== undefined) { + services?.uiActions.getTrigger(VISUALIZE_GEO_FIELD_TRIGGER).exec(triggerOptions); + } + } }, - 'data-test-subj': 'dataVisualizerActionDeleteIndexPatternFieldButton', + 'data-test-subj': 'dataVisualizerActionViewInMapsButton', }); } + + if (dataViewEditorRef !== undefined) { + // Allow to edit data view field + if (services.dataViewFieldEditor?.userPermissions.editIndexPattern()) { + actions.push({ + name: i18n.translate('xpack.dataVisualizer.index.dataGrid.editDataViewFieldTitle', { + defaultMessage: 'Edit data view field', + }), + description: i18n.translate( + 'xpack.dataVisualizer.index.dataGrid.editDataViewFieldDescription', + { + defaultMessage: 'Edit data view field', + } + ), + type: 'icon', + icon: 'indexEdit', + onClick: (item: FieldVisConfig) => { + dataViewEditorRef.current = services.dataViewFieldEditor?.openEditor({ + ctx: { dataView: indexPattern }, + fieldName: item.fieldName, + onSave: refreshPage, + }); + }, + 'data-test-subj': 'dataVisualizerActionEditIndexPatternFieldButton', + }); + actions.push({ + name: i18n.translate('xpack.dataVisualizer.index.dataGrid.deleteDataViewFieldTitle', { + defaultMessage: 'Delete data view field', + }), + description: i18n.translate( + 'xpack.dataVisualizer.index.dataGrid.deleteIndexPatternFieldDescription', + { + defaultMessage: 'Delete data view field', + } + ), + type: 'icon', + icon: 'trash', + available: (item: FieldVisConfig) => { + return item.deletable === true; + }, + onClick: (item: FieldVisConfig) => { + dataViewEditorRef.current = services.dataViewFieldEditor?.openDeleteModal({ + ctx: { dataView: indexPattern }, + fieldName: item.fieldName!, + onDelete: refreshPage, + }); + }, + 'data-test-subj': 'dataVisualizerActionDeleteIndexPatternFieldButton', + }); + } + } return actions; } diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx index 7e6ae7de011dc..760b045c06893 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx @@ -19,8 +19,6 @@ import { EuiSpacer, EuiTitle, } from '@elastic/eui'; -import { EuiTableActionsColumnType } from '@elastic/eui/src/components/basic_table/table_types'; -import { FormattedMessage } from '@kbn/i18n-react'; import { Required } from 'utility-types'; import { i18n } from '@kbn/i18n'; import { Filter } from '@kbn/es-query'; @@ -34,7 +32,6 @@ import { import { FieldVisConfig } from '../../../common/components/stats_table/types'; import type { TotalFieldsStats } from '../../../common/components/stats_table/components/field_count_stats'; import { OverallStats } from '../../types/overall_stats'; -import { getActions } from '../../../common/components/field_data_row/action_menu'; import { IndexBasedDataVisualizerExpandedRow } from '../../../common/components/expanded_row/index_based_expanded_row'; import { DATA_VISUALIZER_INDEX_VIEWER } from '../../constants/index_data_visualizer_viewer'; import { DataVisualizerIndexBasedAppState } from '../../types/index_data_visualizer_state'; @@ -232,6 +229,7 @@ export const IndexDataVisualizerView: FC = (dataVi indexPattern: currentIndexPattern, savedSearch: currentSavedSearch, visibleFieldNames, + allowEditDataView: true, }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [currentIndexPattern.id, currentSavedSearch?.id, visibleFieldNames]); @@ -247,6 +245,7 @@ export const IndexDataVisualizerView: FC = (dataVi timefilter, setLastRefresh, progress, + extendedColumns, } = useDataVisualizerGridData(input, dataVisualizerListState, setGlobalState); useEffect(() => { @@ -381,34 +380,13 @@ export const IndexDataVisualizerView: FC = (dataVi }; }, []); - // Inject custom action column for the index based visualizer - // Hide the column completely if no access to any of the plugins - const extendedColumns = useMemo(() => { - const actions = getActions( - currentIndexPattern, - services, - { - searchQueryLanguage, - searchString, - }, - actionFlyoutRef - ); - if (!Array.isArray(actions) || actions.length < 1) return; - - const actionColumn: EuiTableActionsColumnType = { - name: ( - - ), - actions, - width: '100px', - }; - - return [actionColumn]; - }, [currentIndexPattern, services, searchQueryLanguage, searchString]); - + useEffect(() => { + // Update data query manager if input string is updated + data?.query.queryString.setQuery({ + query: searchString, + language: searchQueryLanguage, + }); + }, [data, searchQueryLanguage, searchString]); const helpLink = docLinks.links.ml.guide; return ( diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/grid_embeddable/grid_embeddable.tsx b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/grid_embeddable/grid_embeddable.tsx index 32dc19078e9ab..243420b4745c9 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/grid_embeddable/grid_embeddable.tsx +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/grid_embeddable/grid_embeddable.tsx @@ -49,6 +49,7 @@ export interface DataVisualizerGridInput { visibleFieldNames?: string[]; filters?: Filter[]; showPreviewByDefault?: boolean; + allowEditDataView?: boolean; /** * Callback to add a filter to filter bar */ diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_data_visualizer_grid_data.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_data_visualizer_grid_data.ts index e6e7a96e0329f..5975404241334 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_data_visualizer_grid_data.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_data_visualizer_grid_data.ts @@ -492,12 +492,12 @@ export const useDataVisualizerGridData = ( const extendedColumns = useMemo(() => { const actions = getActions( input.indexPattern, - { lens: services.lens }, + services, { searchQueryLanguage, searchString, }, - actionFlyoutRef + input.allowEditDataView ? actionFlyoutRef : undefined ); if (!Array.isArray(actions) || actions.length < 1) return; @@ -510,7 +510,7 @@ export const useDataVisualizerGridData = ( }; return [actionColumn]; - }, [input.indexPattern, services, searchQueryLanguage, searchString]); + }, [input.indexPattern, services, searchQueryLanguage, searchString, input.allowEditDataView]); return { progress: combinedProgress, diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/index_data_visualizer.tsx b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/index_data_visualizer.tsx index 0970938f8099f..79c44163b58c8 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/index_data_visualizer.tsx +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/index_data_visualizer.tsx @@ -178,8 +178,17 @@ export const DataVisualizerUrlStateContextProvider: FC = ({ additionalLinks }) => { const coreStart = getCoreStart(); - const { data, maps, embeddable, share, security, fileUpload, lens, dataViewFieldEditor } = - getPluginsStart(); + const { + data, + maps, + embeddable, + share, + security, + fileUpload, + lens, + dataViewFieldEditor, + uiActions, + } = getPluginsStart(); const services = { data, maps, @@ -189,6 +198,7 @@ export const IndexDataVisualizer: FC<{ additionalLinks: ResultLink[] }> = ({ add fileUpload, lens, dataViewFieldEditor, + uiActions, ...coreStart, }; diff --git a/x-pack/plugins/data_visualizer/public/plugin.ts b/x-pack/plugins/data_visualizer/public/plugin.ts index e1c6acf5c65a8..39476bef54da4 100644 --- a/x-pack/plugins/data_visualizer/public/plugin.ts +++ b/x-pack/plugins/data_visualizer/public/plugin.ts @@ -23,6 +23,7 @@ import { getMaxBytesFormatted } from './application/common/util/get_max_bytes'; import { registerHomeAddData, registerHomeFeatureCatalogue } from './register_home'; import { registerEmbeddables } from './application/index_data_visualizer/embeddables'; import { FieldFormatsStart } from '../../../../src/plugins/field_formats/public'; +import { UiActionsStart } from '../../../../src/plugins/ui_actions/public'; export interface DataVisualizerSetupDependencies { home?: HomePublicPluginSetup; @@ -38,6 +39,7 @@ export interface DataVisualizerStartDependencies { lens?: LensPublicStart; dataViewFieldEditor?: IndexPatternFieldEditorStart; fieldFormats: FieldFormatsStart; + uiActions?: UiActionsStart; } export type DataVisualizerPluginSetup = ReturnType;