diff --git a/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx index 9593c6c81c31e..d1ff933ecad8f 100644 --- a/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx +++ b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx @@ -23,6 +23,18 @@ import { act } from 'react-dom/test-utils'; import { ReactWrapper } from 'enzyme'; import { setUnifiedDocViewerServices } from '@kbn/unified-doc-viewer-plugin/public/plugin'; import { mockUnifiedDocViewerServices } from '@kbn/unified-doc-viewer-plugin/public/__mocks__'; +import { FlyoutCustomization, useDiscoverCustomization } from '../../customizations'; +import { EuiFlexItem } from '@elastic/eui'; + +const mockFlyoutCustomization: FlyoutCustomization = { + id: 'flyout', + actions: {}, +}; + +jest.mock('../../customizations', () => ({ + ...jest.requireActual('../../customizations'), + useDiscoverCustomization: jest.fn(), +})); const waitNextTick = () => new Promise((resolve) => setTimeout(resolve, 0)); @@ -94,6 +106,13 @@ describe('Discover flyout', function () { return { component, props }; }; + beforeEach(() => { + mockFlyoutCustomization.actions.defaultActions = undefined; + jest.clearAllMocks(); + + (useDiscoverCustomization as jest.Mock).mockImplementation(() => mockFlyoutCustomization); + }); + it('should be rendered correctly using an data view without timefield', async () => { const { component, props } = await mountComponent({}); @@ -206,4 +225,45 @@ describe('Discover flyout', function () { const flyoutTitle = findTestSubject(component, 'docTableRowDetailsTitle'); expect(flyoutTitle.text()).toBe('Expanded row'); }); + + describe('when customizations actions exists', () => { + it('should display actions added by getActionItems', async () => { + mockFlyoutCustomization.actions = { + getActionItems: jest.fn(() => [ + { + id: 'action-item-1', + enabled: true, + Content: () => Action 1, + }, + { + id: 'action-item-2', + enabled: true, + Content: () => Action 2, + }, + ]), + }; + + const { component } = await mountComponent({}); + + const action1 = findTestSubject(component, 'customActionItem1'); + const action2 = findTestSubject(component, 'customActionItem2'); + + expect(action1.text()).toBe('Action 1'); + expect(action2.text()).toBe('Action 2'); + }); + + it('should allow disabling default actions', async () => { + mockFlyoutCustomization.actions = { + defaultActions: { + viewSingleDocument: { disabled: true }, + viewSurroundingDocument: { disabled: true }, + }, + }; + + const { component } = await mountComponent({}); + + const singleDocumentView = findTestSubject(component, 'docTableRowAction'); + expect(singleDocumentView.length).toBeFalsy(); + }); + }); }); diff --git a/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx index a9130df52738e..7c0598abbfe18 100644 --- a/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx +++ b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx @@ -15,23 +15,19 @@ import { EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, - EuiIconTip, EuiTitle, - EuiButtonEmpty, - EuiText, EuiSpacer, EuiPortal, EuiPagination, - EuiHideFor, keys, } from '@elastic/eui'; import type { Filter, Query, AggregateQuery } from '@kbn/es-query'; import type { DataTableRecord } from '@kbn/discover-utils/types'; import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; import { UnifiedDocViewer } from '@kbn/unified-doc-viewer-plugin/public'; -import { useNavigationProps } from '../../hooks/use_navigation_props'; import { useDiscoverServices } from '../../hooks/use_discover_services'; import { isTextBasedQuery } from '../../application/main/utils/is_text_based_query'; +import { useFlyoutActions } from './use_flyout_actions'; export interface DiscoverGridFlyoutProps { savedSearchId?: string; @@ -104,9 +100,14 @@ export function DiscoverGridFlyout({ [activePage, setPage] ); - const { singleDocHref, contextViewHref, onOpenSingleDoc, onOpenContextView } = useNavigationProps( - { dataView, rowIndex: hit.raw._index, rowId: hit.raw._id, columns, filters, savedSearchId } - ); + const { flyoutActions } = useFlyoutActions({ + dataView, + rowIndex: hit.raw._index, + rowId: hit.raw._id, + columns, + filters, + savedSearchId, + }); return ( @@ -136,77 +137,8 @@ export function DiscoverGridFlyout({ - {!isPlainRecord && ( - <> - - - - - {i18n.translate('discover.grid.tableRow.viewText', { - defaultMessage: 'View:', - })} - - - - - - {/* eslint-disable-next-line @elastic/eui/href-or-on-click */} - - {i18n.translate('discover.grid.tableRow.viewSingleDocumentLinkTextSimple', { - defaultMessage: 'Single document', - })} - - - {dataView.isTimeBased() && dataView.id && ( - - - {/* eslint-disable-next-line @elastic/eui/href-or-on-click */} - - {i18n.translate( - 'discover.grid.tableRow.viewSurroundingDocumentsLinkTextSimple', - { - defaultMessage: 'Surrounding documents', - } - )} - - - - - - - )} - - )} + {!isPlainRecord && + flyoutActions.map((action) => action.enabled && )} {activePage !== -1 && ( ; + href: string; +} + +const staticViewDocumentItem = { + id: 'viewDocument', + enabled: true, + Content: () => , +}; + +export const useFlyoutActions = (navigationProps: UseNavigationProps) => { + const { dataView } = navigationProps; + const { singleDocHref, contextViewHref, onOpenSingleDoc, onOpenContextView } = + useNavigationProps(navigationProps); + + const flyoutCustomization = useDiscoverCustomization('flyout'); + + const { + viewSingleDocument = { disabled: false }, + viewSurroundingDocument = { disabled: false }, + } = flyoutCustomization?.actions?.defaultActions ?? {}; + const customActions = [...(flyoutCustomization?.actions?.getActionItems?.() ?? [])]; + + const flyoutActions = [ + { + id: 'singleDocument', + enabled: !viewSingleDocument.disabled, + Content: () => , + }, + { + id: 'surroundingDocument', + enabled: Boolean(!viewSurroundingDocument.disabled && dataView.isTimeBased() && dataView.id), + Content: () => , + }, + ...customActions, + ]; + + const hasEnabledActions = flyoutActions.some((action) => action.enabled); + + if (hasEnabledActions) { + flyoutActions.unshift(staticViewDocumentItem); + } + + return { flyoutActions, hasEnabledActions }; +}; + +const ViewDocument = () => { + return ( + + + + + {i18n.translate('discover.grid.tableRow.viewText', { + defaultMessage: 'View:', + })} + + + + + ); +}; + +const SingleDocument = (props: FlyoutActionProps) => { + return ( + + + {i18n.translate('discover.grid.tableRow.viewSingleDocumentLinkTextSimple', { + defaultMessage: 'Single document', + })} + + + ); +}; + +const SurroundingDocuments = (props: FlyoutActionProps) => { + return ( + + + + {i18n.translate('discover.grid.tableRow.viewSurroundingDocumentsLinkTextSimple', { + defaultMessage: 'Surrounding documents', + })} + + + + + + + ); +}; diff --git a/src/plugins/discover/public/customizations/customization_service.ts b/src/plugins/discover/public/customizations/customization_service.ts index 0b57ba37e07dc..15175c8bad1ae 100644 --- a/src/plugins/discover/public/customizations/customization_service.ts +++ b/src/plugins/discover/public/customizations/customization_service.ts @@ -8,12 +8,14 @@ import { filter, map, Observable, startWith, Subject } from 'rxjs'; import type { + FlyoutCustomization, SearchBarCustomization, TopNavCustomization, UnifiedHistogramCustomization, } from './customization_types'; export type DiscoverCustomization = + | FlyoutCustomization | SearchBarCustomization | TopNavCustomization | UnifiedHistogramCustomization; diff --git a/src/plugins/discover/public/customizations/customization_types/flyout_customization.ts b/src/plugins/discover/public/customizations/customization_types/flyout_customization.ts new file mode 100644 index 0000000000000..6ec0fe9dec60a --- /dev/null +++ b/src/plugins/discover/public/customizations/customization_types/flyout_customization.ts @@ -0,0 +1,30 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export interface FlyoutDefaultActionItem { + disabled?: boolean; +} + +export interface FlyoutDefaultActions { + viewSingleDocument?: FlyoutDefaultActionItem; + viewSurroundingDocument?: FlyoutDefaultActionItem; +} + +export interface FlyoutActionItem { + id: string; + Content: React.ElementType; + enabled: boolean; +} + +export interface FlyoutCustomization { + id: 'flyout'; + actions: { + defaultActions?: FlyoutDefaultActions; + getActionItems?: () => FlyoutActionItem[]; + }; +} diff --git a/src/plugins/discover/public/customizations/customization_types/index.ts b/src/plugins/discover/public/customizations/customization_types/index.ts index e920a68574b93..effb7fccf207c 100644 --- a/src/plugins/discover/public/customizations/customization_types/index.ts +++ b/src/plugins/discover/public/customizations/customization_types/index.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +export * from './flyout_customization'; export * from './search_bar_customization'; export * from './top_nav_customization'; export * from './histogram_customization'; diff --git a/src/plugins/discover/public/index.ts b/src/plugins/discover/public/index.ts index ca3c58a4d2899..42033c2ebfdb5 100644 --- a/src/plugins/discover/public/index.ts +++ b/src/plugins/discover/public/index.ts @@ -25,6 +25,7 @@ export type { RegisterCustomizationProfile, DiscoverCustomization, DiscoverCustomizationService, + FlyoutCustomization, SearchBarCustomization, UnifiedHistogramCustomization, TopNavCustomization, diff --git a/x-pack/plugins/log_explorer/public/customizations/log_explorer_profile.tsx b/x-pack/plugins/log_explorer/public/customizations/log_explorer_profile.tsx index ee8f7ffbc9779..c5d98b9b24101 100644 --- a/x-pack/plugins/log_explorer/public/customizations/log_explorer_profile.tsx +++ b/x-pack/plugins/log_explorer/public/customizations/log_explorer_profile.tsx @@ -95,6 +95,19 @@ export const createLogExplorerProfileCustomizations = }, }); + /** + * Hide flyout actions to prevent rendering hard-coded actions. + */ + customizations.set({ + id: 'flyout', + actions: { + defaultActions: { + viewSingleDocument: { disabled: true }, + viewSurroundingDocument: { disabled: true }, + }, + }, + }); + return () => { if (stateSubscription) { stateSubscription.unsubscribe();