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

[SIEM] Fix Inspect query 'request timestamp' value changes when curso… #54223

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -59,179 +59,178 @@ interface Props {
kqlMode: KqlMode;
onChangeItemsPerPage: OnChangeItemsPerPage;
query: Query;
showInspect: boolean;
start: number;
sort: Sort;
timelineTypeContext: TimelineTypeContextProps;
toggleColumn: (column: ColumnHeader) => void;
utilityBar?: (totalCount: number) => React.ReactNode;
}

export const EventsViewer = React.memo<Props>(
({
browserFields,
columns,
const EventsViewerComponent: React.FC<Props> = ({
browserFields,
columns,
dataProviders,
deletedEventIds,
end,
filters,
headerFilterGroup,
height = DEFAULT_EVENTS_VIEWER_HEIGHT,
id,
indexPattern,
isLive,
itemsPerPage,
itemsPerPageOptions,
kqlMode,
onChangeItemsPerPage,
query,
start,
sort,
timelineTypeContext,
toggleColumn,
utilityBar,
}) => {
const columnsHeader = isEmpty(columns) ? defaultHeaders : columns;
const kibana = useKibana();
const combinedQueries = combineQueries({
config: esQuery.getEsQueryConfig(kibana.services.uiSettings),
dataProviders,
deletedEventIds,
end,
filters,
headerFilterGroup,
height = DEFAULT_EVENTS_VIEWER_HEIGHT,
id,
indexPattern,
isLive,
itemsPerPage,
itemsPerPageOptions,
browserFields,
filters,
kqlQuery: query,
kqlMode,
onChangeItemsPerPage,
query,
showInspect,
start,
sort,
timelineTypeContext,
toggleColumn,
utilityBar,
}) => {
const columnsHeader = isEmpty(columns) ? defaultHeaders : columns;
const kibana = useKibana();
const combinedQueries = combineQueries({
config: esQuery.getEsQueryConfig(kibana.services.uiSettings),
dataProviders,
indexPattern,
browserFields,
filters,
kqlQuery: query,
kqlMode,
start,
end,
isEventViewer: true,
});
const queryFields = useMemo(
() =>
union(
columnsHeader.map(c => c.id),
timelineTypeContext.queryFields ?? []
),
[columnsHeader, timelineTypeContext.queryFields]
);
end,
isEventViewer: true,
});
const queryFields = useMemo(
() =>
union(
columnsHeader.map(c => c.id),
timelineTypeContext.queryFields ?? []
),
[columnsHeader, timelineTypeContext.queryFields]
);

return (
<EuiPanel data-test-subj="events-viewer-panel" grow={false}>
<AutoSizer detectAnyWindowResize={true} content>
{({ measureRef, content: { width = 0 } }) => (
<>
<WrappedByAutoSizer ref={measureRef}>
<div
data-test-subj="events-viewer-measured"
style={{ height: '0px', width: '100%' }}
/>
</WrappedByAutoSizer>
return (
<EuiPanel data-test-subj="events-viewer-panel" grow={false}>
<AutoSizer detectAnyWindowResize={true} content>
{({ measureRef, content: { width = 0 } }) => (
<>
<WrappedByAutoSizer ref={measureRef}>
<div
data-test-subj="events-viewer-measured"
style={{ height: '0px', width: '100%' }}
/>
</WrappedByAutoSizer>

{combinedQueries != null ? (
<TimelineQuery
fields={queryFields}
filterQuery={combinedQueries.filterQuery}
id={id}
indexPattern={indexPattern}
limit={itemsPerPage}
sortField={{
sortFieldId: sort.columnId,
direction: sort.sortDirection as Direction,
}}
sourceId="default"
>
{({
events,
getUpdatedAt,
inspect,
loading,
loadMore,
pageInfo,
refetch,
totalCount = 0,
}) => {
const totalCountMinusDeleted =
totalCount > 0 ? totalCount - deletedEventIds.length : 0;
{combinedQueries != null ? (
<TimelineQuery
fields={queryFields}
filterQuery={combinedQueries.filterQuery}
id={id}
indexPattern={indexPattern}
limit={itemsPerPage}
sortField={{
sortFieldId: sort.columnId,
direction: sort.sortDirection as Direction,
}}
sourceId="default"
>
{({
events,
getUpdatedAt,
inspect,
loading,
loadMore,
pageInfo,
refetch,
totalCount = 0,
}) => {
const totalCountMinusDeleted =
totalCount > 0 ? totalCount - deletedEventIds.length : 0;

// TODO: Reset eventDeletedIds/eventLoadingIds on refresh/loadmore (getUpdatedAt)
return (
<>
<HeaderSection
id={id}
showInspect={showInspect}
subtitle={
utilityBar
? undefined
: `${
i18n.SHOWING
}: ${totalCountMinusDeleted.toLocaleString()} ${i18n.UNIT(
totalCountMinusDeleted
)}`
}
title={timelineTypeContext?.title ?? i18n.EVENTS}
>
{headerFilterGroup}
</HeaderSection>
// TODO: Reset eventDeletedIds/eventLoadingIds on refresh/loadmore (getUpdatedAt)
return (
<>
<HeaderSection
id={id}
subtitle={
utilityBar
? undefined
: `${
i18n.SHOWING
}: ${totalCountMinusDeleted.toLocaleString()} ${i18n.UNIT(
totalCountMinusDeleted
)}`
}
title={timelineTypeContext?.title ?? i18n.EVENTS}
>
{headerFilterGroup}
</HeaderSection>

{utilityBar?.(totalCountMinusDeleted)}
{utilityBar?.(totalCountMinusDeleted)}

<div
data-test-subj={`events-container-loading-${loading}`}
style={{ width: `${width}px` }}
<div
data-test-subj={`events-container-loading-${loading}`}
style={{ width: `${width}px` }}
>
<ManageTimelineContext
loading={loading}
width={width}
type={timelineTypeContext}
>
<ManageTimelineContext
<TimelineRefetch
id={id}
inputId="global"
inspect={inspect}
loading={loading}
width={width}
type={timelineTypeContext}
>
<TimelineRefetch
id={id}
inputId="global"
inspect={inspect}
loading={loading}
refetch={refetch}
/>
refetch={refetch}
/>

<StatefulBody
browserFields={browserFields}
data={events.filter(e => !deletedEventIds.includes(e._id))}
id={id}
isEventViewer={true}
height={height}
sort={sort}
toggleColumn={toggleColumn}
/>

<StatefulBody
browserFields={browserFields}
data={events.filter(e => !deletedEventIds.includes(e._id))}
id={id}
isEventViewer={true}
height={height}
sort={sort}
toggleColumn={toggleColumn}
/>
<Footer
compact={isCompactFooter(width)}
getUpdatedAt={getUpdatedAt}
hasNextPage={getOr(false, 'hasNextPage', pageInfo)!}
height={footerHeight}
isEventViewer={true}
isLive={isLive}
isLoading={loading}
itemsCount={events.length}
itemsPerPage={itemsPerPage}
itemsPerPageOptions={itemsPerPageOptions}
onChangeItemsPerPage={onChangeItemsPerPage}
onLoadMore={loadMore}
nextCursor={getOr(null, 'endCursor.value', pageInfo)!}
serverSideEventCount={totalCountMinusDeleted}
tieBreaker={getOr(null, 'endCursor.tiebreaker', pageInfo)}
/>
</ManageTimelineContext>
</div>
</>
);
}}
</TimelineQuery>
) : null}
</>
)}
</AutoSizer>
</EuiPanel>
);
};

<Footer
compact={isCompactFooter(width)}
getUpdatedAt={getUpdatedAt}
hasNextPage={getOr(false, 'hasNextPage', pageInfo)!}
height={footerHeight}
isEventViewer={true}
isLive={isLive}
isLoading={loading}
itemsCount={events.length}
itemsPerPage={itemsPerPage}
itemsPerPageOptions={itemsPerPageOptions}
onChangeItemsPerPage={onChangeItemsPerPage}
onLoadMore={loadMore}
nextCursor={getOr(null, 'endCursor.value', pageInfo)!}
serverSideEventCount={totalCountMinusDeleted}
tieBreaker={getOr(null, 'endCursor.tiebreaker', pageInfo)}
/>
</ManageTimelineContext>
</div>
</>
);
}}
</TimelineQuery>
) : null}
</>
)}
</AutoSizer>
</EuiPanel>
);
},
export const EventsViewer = React.memo(
EventsViewerComponent,
(prevProps, nextProps) =>
prevProps.browserFields === nextProps.browserFields &&
prevProps.columns === nextProps.columns &&
Expand All @@ -247,10 +246,8 @@ export const EventsViewer = React.memo<Props>(
prevProps.itemsPerPageOptions === nextProps.itemsPerPageOptions &&
prevProps.kqlMode === nextProps.kqlMode &&
isEqual(prevProps.query, nextProps.query) &&
prevProps.showInspect === nextProps.showInspect &&
prevProps.start === nextProps.start &&
prevProps.sort === nextProps.sort &&
isEqual(prevProps.timelineTypeContext, nextProps.timelineTypeContext) &&
prevProps.utilityBar === nextProps.utilityBar
);
EventsViewer.displayName = 'EventsViewer';
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ describe('StatefulEventsViewer', () => {
).toBe(true);
});

test('it renders a transparent inspect button when it does NOT have mouse focus', async () => {
// InspectButtonContainer controls displaying InspectButton components
test('it renders InspectButtonContainer', async () => {
const wrapper = mount(
<TestProviders>
<MockedProvider mocks={mockEventViewerResponse} addTypename={false}>
Expand All @@ -74,39 +75,6 @@ describe('StatefulEventsViewer', () => {
await wait();
wrapper.update();

expect(
wrapper
.find(`[data-test-subj="transparent-inspect-container"]`)
.first()
.exists()
).toBe(true);
});

test('it renders an opaque inspect button when it has mouse focus', async () => {
const wrapper = mount(
<TestProviders>
<MockedProvider mocks={mockEventViewerResponse} addTypename={false}>
<StatefulEventsViewer
defaultModel={eventsDefaultModel}
end={to}
id={'test-stateful-events-viewer'}
start={from}
/>
</MockedProvider>
</TestProviders>
);

await wait();
wrapper.update();

wrapper.simulate('mouseenter');
wrapper.update();

expect(
wrapper
.find(`[data-test-subj="opaque-inspect-container"]`)
.first()
.exists()
).toBe(true);
expect(wrapper.find(`InspectButtonContainer`).exists()).toBe(true);
});
});
Loading