Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Security Solution] Discover Timeline Integration URL Sync + Fixes #163305

Merged
merged 39 commits into from
Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
e88eb3c
fix: chart drag time select
logeekal Jul 25, 2023
5e2322a
fix: remove saperate instance of filter manager
logeekal Jul 26, 2023
e6f85fe
incremental + cypress tests
logeekal Aug 2, 2023
7c8ab33
incremental commit 2 - state management working
logeekal Aug 4, 2023
9a49dd0
fix: override lens trigger
logeekal Aug 7, 2023
7934b9b
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Aug 7, 2023
eb4bd14
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Aug 7, 2023
4b5ca55
cleanup: remove unncessary changes
logeekal Aug 7, 2023
c89c7c9
Merge main ➡️ current branch
logeekal Aug 8, 2023
bf1e79b
fix: tests
logeekal Aug 9, 2023
d96de65
fix: state sync
logeekal Aug 10, 2023
76ab819
Merge branch 'main' into fix/discover_tab_url_sync_fixes
logeekal Aug 10, 2023
9a35ea0
fix: more tests + lens import remove
logeekal Aug 10, 2023
19798f2
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Aug 10, 2023
94c2418
discoverInTimeline feature flag should be false by default
logeekal Aug 10, 2023
7049c10
fix: stop discover sync
logeekal Aug 10, 2023
842d5ea
refactor: cypress feature flag
logeekal Aug 10, 2023
95d4ee2
fix: more fixes + tests
logeekal Aug 14, 2023
75d8e04
refactor: add memoize
logeekal Aug 14, 2023
4a0ba9f
fix: types
logeekal Aug 14, 2023
721d26c
refactor: skip tests
logeekal Aug 14, 2023
db07cc0
Merge main ➡️ current branch
logeekal Aug 14, 2023
fa18ca7
chore: remove unncessary changes
logeekal Aug 14, 2023
7f0e552
fix: review feedback
logeekal Aug 16, 2023
9142901
Merge main ➡️ current branch
logeekal Aug 16, 2023
130f5a1
Merge branch 'main' into fix/discover_tab_url_sync_fixes
logeekal Aug 16, 2023
2fce8f0
test: more unit tests
logeekal Aug 17, 2023
7a8000b
Merge branch 'main' into fix/discover_tab_url_sync_fixes
logeekal Aug 21, 2023
ff085d5
fix: types
logeekal Aug 21, 2023
8b66bf1
Merge branch 'main' into fix/discover_tab_url_sync_fixes
logeekal Aug 21, 2023
08b01bb
fix: add tests in serverless
logeekal Aug 23, 2023
69ebb48
refactor: syncstate -> set + replace URL state
logeekal Aug 23, 2023
8300e46
test: unit test for embedded mode
logeekal Aug 23, 2023
dd23497
misc feedback
logeekal Aug 23, 2023
f59b1ec
fix: remove unncessary code
logeekal Aug 23, 2023
828f5ab
Merge branch 'main' into fix/discover_tab_url_sync_fixes
logeekal Aug 24, 2023
456be46
Merge branch 'main' into fix/discover_tab_url_sync_fixes
logeekal Aug 28, 2023
fc171ed
Merge branch 'main' into fix/discover_tab_url_sync_fixes
logeekal Aug 28, 2023
76fd62f
fix: refactor based on main changes
logeekal Aug 29, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,14 @@ export const FieldList: React.FC<FieldListProps> = ({
css={containerStyle}
className={className}
>
{isProcessing && <EuiProgress size="xs" color="accent" position="absolute" />}
{isProcessing && (
<EuiProgress
size="xs"
color="accent"
position="absolute"
data-test-subj="fieldListLoading"
davismcphee marked this conversation as resolved.
Show resolved Hide resolved
/>
)}
{!!prepend && <EuiFlexItem grow={false}>{prepend}</EuiFlexItem>}
<EuiFlexItem grow={true}>{children}</EuiFlexItem>
{!!append && <EuiFlexItem grow={false}>{append}</EuiFlexItem>}
Expand Down
1 change: 1 addition & 0 deletions src/plugins/data/public/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const createStartContract = (): Start => {
actions: {
createFiltersFromValueClickAction: jest.fn().mockResolvedValue(['yes']),
createFiltersFromRangeSelectAction: jest.fn(),
createFiltersFromMultiValueClickAction: jest.fn(),
},
datatableUtilities: createDatatableUtilitiesMock(),
search: searchServiceMock.createStartContract(),
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/data/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
import {
createFiltersFromValueClickAction,
createFiltersFromRangeSelectAction,
createFiltersFromMultiValueClickAction,
createMultiValueClickActionDefinition,
createValueClickActionDefinition,
createSelectRangeActionDefinition,
Expand Down Expand Up @@ -167,6 +168,7 @@ export class DataPublicPlugin
actions: {
createFiltersFromValueClickAction,
createFiltersFromRangeSelectAction,
createFiltersFromMultiValueClickAction,
},
datatableUtilities,
fieldFormats,
Expand Down
7 changes: 6 additions & 1 deletion src/plugins/data/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ import { ScreenshotModePluginStart } from '@kbn/screenshot-mode-plugin/public';
import { SharePluginStart } from '@kbn/share-plugin/public';
import { ManagementSetup } from '@kbn/management-plugin/public';
import { DatatableUtilitiesService } from '../common';
import { createFiltersFromRangeSelectAction, createFiltersFromValueClickAction } from './actions';
import {
createFiltersFromMultiValueClickAction,
createFiltersFromRangeSelectAction,
createFiltersFromValueClickAction,
} from './actions';
import type { ISearchSetup, ISearchStart } from './search';
import { QuerySetup, QueryStart } from './query';
import { DataViewsContract } from './data_views';
Expand Down Expand Up @@ -55,6 +59,7 @@ export interface DataPublicPluginSetup {
export interface DataPublicPluginStartActions {
createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction;
createFiltersFromRangeSelectAction: typeof createFiltersFromRangeSelectAction;
createFiltersFromMultiValueClickAction: typeof createFiltersFromMultiValueClickAction;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,11 @@ const IndexPatternEditorFlyoutContentComponent = ({

return (
<FlyoutPanels.Group flyoutClassName={'indexPatternEditorFlyout'} maxWidth={1180}>
<FlyoutPanels.Item className="fieldEditor__mainFlyoutPanel" border="right">
<FlyoutPanels.Item
className="fieldEditor__mainFlyoutPanel"
data-test-subj="indexPatternEditorFlyout"
border="right"
>
<EuiTitle data-test-subj="flyoutTitle">
<h2>{editData ? editorTitleEditMode : editorTitle}</h2>
</EuiTitle>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,13 @@ function DiscoverDocumentsComponent({
</>
)}
{isDataLoading && (
<EuiProgress size="xs" color="accent" position="absolute" css={progressStyle} />
<EuiProgress
data-test-subj="discoverDataGridUpdating"
size="xs"
color="accent"
position="absolute"
css={progressStyle}
/>
)}
</EuiFlexItem>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ import {
import { createMockUnifiedHistogramApi } from '@kbn/unified-histogram-plugin/public/mocks';
import { checkHitCount, sendErrorTo } from '../../hooks/use_saved_search_messages';
import type { InspectorAdapters } from '../../hooks/use_inspector';
import { UnifiedHistogramCustomization } from '../../../../customizations/customization_types/histogram_customization';
import { useDiscoverCustomization } from '../../../../customizations';
import { DiscoverCustomizationId } from '../../../../customizations/customization_service';

const mockData = dataPluginMock.createStartContract();
let mockQueryState = {
Expand Down Expand Up @@ -71,6 +74,19 @@ jest.mock('../../hooks/use_saved_search_messages', () => {
sendErrorTo: jest.fn(originalModule.sendErrorTo),
};
});
jest.mock('../../../../customizations', () => ({
...jest.requireActual('../../../../customizations'),
useDiscoverCustomization: jest.fn(),
}));

let mockUseCustomizations = false;

const mockHistogramCustomization: UnifiedHistogramCustomization = {
id: 'unified_histogram',
onFilter: jest.fn(),
onBrushEnd: jest.fn(),
withDefaultActions: true,
};

const mockCheckHitCount = checkHitCount as jest.MockedFunction<typeof checkHitCount>;

Expand Down Expand Up @@ -126,6 +142,23 @@ describe('useDiscoverHistogram', () => {
return { hook, initialProps };
};

beforeEach(() => {
mockUseCustomizations = false;
jest.clearAllMocks();

(useDiscoverCustomization as jest.Mock).mockImplementation((id: DiscoverCustomizationId) => {
if (!mockUseCustomizations) {
return undefined;
}
switch (id) {
case 'unified_histogram':
return mockHistogramCustomization;
default:
throw new Error(`Unknown customization id: ${id}`);
}
});
});

describe('initialization', () => {
it('should return the expected parameters from getCreationOptions', async () => {
const { hook } = await renderUseDiscoverHistogram();
Expand Down Expand Up @@ -447,4 +480,19 @@ describe('useDiscoverHistogram', () => {
expect(api.refetch).toHaveBeenCalled();
});
});

describe('customization', () => {
test('should use custom values provided by customization fwk ', async () => {
mockUseCustomizations = true;
const stateContainer = getStateContainer();
const { hook } = await renderUseDiscoverHistogram({ stateContainer });

expect(hook.result.current.onFilter).toEqual(mockHistogramCustomization.onFilter);
expect(hook.result.current.onBrushEnd).toEqual(mockHistogramCustomization.onBrushEnd);
expect(hook.result.current.withDefaultActions).toEqual(
mockHistogramCustomization.withDefaultActions
);
expect(hook.result.current.disabledActions).toBeUndefined();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
} from 'rxjs';
import useObservable from 'react-use/lib/useObservable';
import type { RequestAdapter } from '@kbn/inspector-plugin/common';
import { useDiscoverCustomization } from '../../../../customizations';
import { useDiscoverServices } from '../../../../hooks/use_discover_services';
import { getUiActions } from '../../../../kibana_services';
import { FetchStatus } from '../../../types';
Expand Down Expand Up @@ -302,6 +303,8 @@ export const useDiscoverHistogram = ({

const dataView = useInternalStateSelector((state) => state.dataView!);

const histogramCustomization = useDiscoverCustomization('unified_histogram');

return {
ref,
getCreationOptions,
Expand All @@ -312,6 +315,10 @@ export const useDiscoverHistogram = ({
timeRange,
relativeTimeRange,
columns,
onFilter: histogramCustomization?.onFilter,
onBrushEnd: histogramCustomization?.onBrushEnd,
withDefaultActions: histogramCustomization?.withDefaultActions,
disabledActions: histogramCustomization?.disabledActions,
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,12 @@ export function DiscoverMainRoute({
dataViewEditor,
} = services;
const { id: savedSearchId } = useParams<DiscoverLandingParams>();

const stateContainer = useSingleton<DiscoverStateContainer>(() =>
getDiscoverStateContainer({
history,
services,
mode,
})
);
const { customizationService, isInitialized: isCustomizationServiceInitialized } =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { merge } from 'rxjs';
import { AggregateQuery, Query, TimeRange } from '@kbn/es-query';
import { loadSavedSearch as loadSavedSearchFn } from './load_saved_search';
import { restoreStateFromSavedSearch } from '../../../services/saved_searches/restore_from_saved_search';
import { FetchStatus } from '../../types';
import { DiscoverDisplayMode, FetchStatus } from '../../types';
import { changeDataView } from '../hooks/utils/change_data_view';
import { buildStateSubscribe } from '../hooks/utils/build_state_subscribe';
import { addLog } from '../../../utils/add_log';
Expand Down Expand Up @@ -64,6 +64,11 @@ interface DiscoverStateContainerParams {
* core ui settings service
*/
services: DiscoverServices;
/*
* mode in which discover is running
*
* */
mode?: DiscoverDisplayMode;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense, embedded | standalone. What do you think about a 2nd prop, an appId to redirect if mode === 'embedded'

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I understand this suggestion. Are you referring to redirecting requests to Discover to another app based on an appId prop?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, for determining path, if discover is being used at a different path in both security and observability serverless modes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

guess that might not work with locators and the like, as those run during discover setup. Probably makes more sense to do something at a config level then? maybe a discover.location setting that we set only in serverless.obit.yml/serverless.security.yml?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to add parameter in discover.locator called, appId where locator will develop the URL based on the appID given?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, for determining path, if discover is being used at a different path in both security and observability serverless modes.

Observability currently doesn't use Discover at a different path or embedded in another app. They're using the profile functionality in the customization framework to customize Discover as a top level app, so their use case around URLs and paths is a bit different (and already supported).

guess that might not work with locators and the like, as those run during discover setup.

Yeah I agree, I don't think this would be possible through the container component.

Probably makes more sense to do something at a config level then? maybe a discover.location setting that we set only in serverless.obit.yml/serverless.security.yml?

I'd like for the Security redirecting logic not to live in the Discover codebase or be owned/maintained by the Data Discovery team, so I'd prefer not to take this approach. I'd be open to a YAML config that disables access to Discover as a top level app or similar, but owning and maintaining the redirect logic should be the responsibility of the Security Solution.

Does it make sense to add parameter in discover.locator called, appId where locator will develop the URL based on the appID given?

I'd also prefer to avoid this since it would introduce knowledge of the Security redirect logic directly into the Discover codebase.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Observability currently doesn't use Discover at a different path or embedded in another app. They're using the profile functionality in the customization framework to customize Discover as a top level app, so their use case around URLs and paths is a bit different (and already supported).

In light of today's Discover Working Stream, scratch this -- looks like Observability will be embedding the Discover container now (I just learned of this now). With that said, they seem to be planning to include the main Discover app in their project, so their use case around URLs and redirecting is still different since existing links will presumably continue to take users to the main Discover app.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@davismcphee thanks for the info. What do you think if client can pass callback to locator to provide a client specific location. This will prevent any other plugin's logic in Discover?

cc: @kqualters-elastic

}

export interface LoadParams {
Expand Down Expand Up @@ -188,6 +193,7 @@ export interface DiscoverStateContainer {
export function getDiscoverStateContainer({
history,
services,
mode = 'standalone',
}: DiscoverStateContainerParams): DiscoverStateContainer {
const storeInSessionStorage = services.uiSettings.get('state:storeInSessionStorage');
const toasts = services.core.notifications.toasts;
Expand All @@ -198,6 +204,7 @@ export function getDiscoverStateContainer({
const stateStorage = createKbnUrlStateStorage({
useHash: storeInSessionStorage,
history,
useHashQuery: mode !== 'embedded',
logeekal marked this conversation as resolved.
Show resolved Hide resolved
davismcphee marked this conversation as resolved.
Show resolved Hide resolved
...(toasts && withNotifyOnErrors(toasts)),
});

Expand Down
2 changes: 1 addition & 1 deletion src/plugins/discover/public/build_services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
*/

import { History } from 'history';
import { memoize } from 'lodash';

import {
Capabilities,
Expand Down Expand Up @@ -52,6 +51,7 @@ import type { LensPublicStart } from '@kbn/lens-plugin/public';
import type { UiActionsStart } from '@kbn/ui-actions-plugin/public';
import type { SettingsStart } from '@kbn/core-ui-settings-browser';
import type { ContentClient } from '@kbn/content-management-plugin/public';
import { memoize } from 'lodash';
import type { ServerlessPluginStart } from '@kbn/serverless/public';
import { getHistory } from './kibana_services';
import { DiscoverStartPlugins } from './plugin';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const TestComponent = (props: Partial<DiscoverContainerInternalProps>) => {
return (
<DiscoverContainerInternal
overrideServices={props.overrideServices ?? mockOverrideService}
customize={props.customize ?? customizeMock}
customizationCallbacks={props.customizationCallbacks ?? [customizeMock]}
isDev={props.isDev ?? false}
scopedHistory={props.scopedHistory ?? (history() as ScopedHistory<unknown>)}
getDiscoverServices={getDiscoverServicesMock}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ export interface DiscoverContainerInternalProps {
overrideServices: Partial<DiscoverServices>;
getDiscoverServices: () => Promise<DiscoverServices>;
scopedHistory: ScopedHistory;
customize: CustomizationCallback;
customizationCallbacks: CustomizationCallback[];
isDev: boolean;
isLoading?: boolean;
}

const discoverContainerWrapperCss = css`
Expand All @@ -45,12 +46,12 @@ const discoverContainerWrapperCss = css`
export const DiscoverContainerInternal = ({
overrideServices,
scopedHistory,
customize,
customizationCallbacks,
isDev,
getDiscoverServices,
isLoading = false,
}: DiscoverContainerInternalProps) => {
const [discoverServices, setDiscoverServices] = useState<DiscoverServices | undefined>();
const customizationCallbacks = useMemo(() => [customize], [customize]);
const [initialized, setInitialized] = useState(false);

useEffect(() => {
Expand All @@ -68,7 +69,7 @@ export const DiscoverContainerInternal = ({
return { ...discoverServices, ...overrideServices };
}, [discoverServices, overrideServices]);

if (!initialized || !services) {
if (!initialized || !services || isLoading) {
return (
<EuiFlexGroup css={discoverContainerWrapperCss}>
<LoadingIndicator type="spinner" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ export const DiscoverGrid = ({

if (!rowCount && loadingState === DataLoadingState.loading) {
return (
<div className="euiDataGrid__loading">
<div className="euiDataGrid__loading" data-test-subj="discoverDataGridLoading">
<EuiText size="xs" color="subdued">
<EuiLoadingSpinner />
<EuiSpacer size="s" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@
*/

import { filter, map, Observable, startWith, Subject } from 'rxjs';
import type { SearchBarCustomization, TopNavCustomization } from './customization_types';
import type {
SearchBarCustomization,
TopNavCustomization,
UnifiedHistogramCustomization,
} from './customization_types';

export type DiscoverCustomization = SearchBarCustomization | TopNavCustomization;
export type DiscoverCustomization =
| SearchBarCustomization
| TopNavCustomization
| UnifiedHistogramCustomization;

export type DiscoverCustomizationId = DiscoverCustomization['id'];

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* 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.
*/

import type { UnifiedHistogramContainerProps } from '@kbn/unified-histogram-plugin/public';

interface UnifiedHistogramCustomizationId {
id: 'unified_histogram';
}

export type UnifiedHistogramCustomization = UnifiedHistogramCustomizationId &
Pick<
UnifiedHistogramContainerProps,
'onFilter' | 'onBrushEnd' | 'withDefaultActions' | 'disabledActions'
>;
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@

export * from './search_bar_customization';
export * from './top_nav_customization';
export * from './histogram_customization';
1 change: 1 addition & 0 deletions src/plugins/discover/public/customizations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@
export * from './customization_types';
export * from './customization_provider';
export * from './types';
export type { DiscoverCustomization, DiscoverCustomizationService } from './customization_service';
5 changes: 5 additions & 0 deletions src/plugins/discover/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ export type {
DiscoverProfileId,
DiscoverProfileOptions,
RegisterCustomizationProfile,
DiscoverCustomization,
DiscoverCustomizationService,
SearchBarCustomization,
UnifiedHistogramCustomization,
TopNavCustomization,
} from './customizations';
export { SEARCH_EMBEDDABLE_TYPE, SEARCH_EMBEDDABLE_CELL_ACTIONS_TRIGGER_ID } from './embeddable';
export { loadSharingDataHelpers } from './utils';

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ export const CodeEditor: React.FC<Props> = ({
const { CopyButton } = useCopy({ isCopyable, value });

return (
<div className="kibanaCodeEditor" onKeyDown={onKeyDown}>
<div className="kibanaCodeEditor" onKeyDown={onKeyDown} data-test-subj="kibanaCodeEditor">
{renderPrompt()}

<FullScreenDisplay>
Expand Down
1 change: 1 addition & 0 deletions src/plugins/unified_histogram/public/chart/chart.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ async function mountComponent({
onResetChartHeight: jest.fn(),
onChartHiddenChange: jest.fn(),
onTimeIntervalChange: jest.fn(),
withDefaultActions: undefined,
};

let instance: ReactWrapper = {} as ReactWrapper;
Expand Down
Loading