Skip to content

Commit

Permalink
[RAC] Add loading and empty states to the alerts table - Take II (ela…
Browse files Browse the repository at this point in the history
…stic#110504)

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
Alejandro Fernández Gómez and kibanamachine committed Sep 3, 2021
1 parent c13f6ad commit 343b22c
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 144 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* 2.0.
*/

import { EuiLoadingContent, EuiPanel } from '@elastic/eui';
import { isEmpty } from 'lodash/fp';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { connect, ConnectedProps, useDispatch } from 'react-redux';
Expand Down Expand Up @@ -369,11 +368,7 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
}, [dispatch, defaultTimelineModel, filterManager, tGridEnabled, timelineId]);

if (loading || indexPatternsLoading || isEmpty(selectedPatterns)) {
return (
<EuiPanel hasBorder={false} hasShadow={false} paddingSize="none">
<EuiLoadingContent data-test-subj="loading-alerts-panel" />
</EuiPanel>
);
return null;
}

return (
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
106 changes: 42 additions & 64 deletions x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,12 @@
import type { AlertConsumers as AlertConsumersTyped } from '@kbn/rule-data-utils';
// @ts-expect-error
import { AlertConsumers as AlertConsumersNonTyped } from '@kbn/rule-data-utils/target_node/alerts_as_data_rbac';
import {
EuiEmptyPrompt,
EuiFlexGroup,
EuiFlexItem,
EuiPanel,
EuiLoadingContent,
} from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui';
import { isEmpty } from 'lodash/fp';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import styled from 'styled-components';
import { useDispatch } from 'react-redux';

import { FormattedMessage } from '@kbn/i18n/react';
import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
import { Direction, EntityType } from '../../../../common/search_strategy';
import type { DocValueFields } from '../../../../common/search_strategy';
Expand Down Expand Up @@ -53,6 +46,7 @@ import { SELECTOR_TIMELINE_GLOBAL_CONTAINER, UpdatedFlexGroup, UpdatedFlexItem }
import { Sort } from '../body/sort';
import { InspectButton, InspectButtonContainer } from '../../inspect';
import { SummaryViewSelector, ViewSelection } from '../event_rendered_view/selector';
import { TGridLoading, TGridEmpty } from '../shared';

const AlertConsumers: typeof AlertConsumersTyped = AlertConsumersNonTyped;

Expand Down Expand Up @@ -269,6 +263,8 @@ const TGridIntegratedComponent: React.FC<TGridIntegratedProps> = ({
[deletedEventIds.length, totalCount]
);

const hasAlerts = totalCountMinusDeleted > 0;

const nonDeletedEvents = useMemo(() => events.filter((e) => !deletedEventIds.includes(e._id)), [
deletedEventIds,
events,
Expand Down Expand Up @@ -300,7 +296,7 @@ const TGridIntegratedComponent: React.FC<TGridIntegratedProps> = ({
data-test-subj="events-viewer-panel"
$isFullScreen={globalFullScreen}
>
{isFirstUpdate.current && <EuiLoadingContent data-test-subj="loading-alerts-panel" />}
{isFirstUpdate.current && <TGridLoading height="short" />}

{graphOverlay}

Expand All @@ -325,61 +321,43 @@ const TGridIntegratedComponent: React.FC<TGridIntegratedProps> = ({
</UpdatedFlexGroup>

{!graphEventId && graphOverlay == null && (
<FullWidthFlexGroup
$visible={!graphEventId && graphOverlay == null}
gutterSize="none"
>
<ScrollableFlexItem grow={1}>
{totalCountMinusDeleted === 0 && loading === false && (
<EuiEmptyPrompt
title={
<h2>
<FormattedMessage
id="xpack.timelines.tGrid.noResultsMatchSearchCriteriaTitle"
defaultMessage="No results match your search criteria"
/>
</h2>
}
titleSize="s"
body={
<p>
<FormattedMessage
id="xpack.timelines.tGrid.noResultsMatchSearchCriteriaDescription"
defaultMessage="Try searching over a longer period of time or modifying your search."
/>
</p>
}
/>
)}
{totalCountMinusDeleted > 0 && (
<StatefulBody
hasAlertsCrud={hasAlertsCrud}
activePage={pageInfo.activePage}
browserFields={browserFields}
filterQuery={filterQuery}
data={nonDeletedEvents}
defaultCellActions={defaultCellActions}
id={id}
isEventViewer={true}
itemsPerPageOptions={itemsPerPageOptions}
loadPage={loadPage}
onRuleChange={onRuleChange}
pageSize={itemsPerPage}
renderCellValue={renderCellValue}
rowRenderers={rowRenderers}
tabType={TimelineTabs.query}
tableView={tableView}
totalItems={totalCountMinusDeleted}
unit={unit}
filterStatus={filterStatus}
leadingControlColumns={leadingControlColumns}
trailingControlColumns={trailingControlColumns}
refetch={refetch}
indexNames={indexNames}
/>
)}
</ScrollableFlexItem>
</FullWidthFlexGroup>
<>
{!hasAlerts && !loading && <TGridEmpty height="short" />}
{hasAlerts && (
<FullWidthFlexGroup
$visible={!graphEventId && graphOverlay == null}
gutterSize="none"
>
<ScrollableFlexItem grow={1}>
<StatefulBody
hasAlertsCrud={hasAlertsCrud}
activePage={pageInfo.activePage}
browserFields={browserFields}
filterQuery={filterQuery}
data={nonDeletedEvents}
defaultCellActions={defaultCellActions}
id={id}
isEventViewer={true}
itemsPerPageOptions={itemsPerPageOptions}
loadPage={loadPage}
onRuleChange={onRuleChange}
pageSize={itemsPerPage}
renderCellValue={renderCellValue}
rowRenderers={rowRenderers}
tabType={TimelineTabs.query}
tableView={tableView}
totalItems={totalCountMinusDeleted}
unit={unit}
filterStatus={filterStatus}
leadingControlColumns={leadingControlColumns}
trailingControlColumns={trailingControlColumns}
refetch={refetch}
indexNames={indexNames}
/>
</ScrollableFlexItem>
</FullWidthFlexGroup>
)}
</>
)}
</EventsContainerLoading>
)}
Expand Down
90 changes: 90 additions & 0 deletions x-pack/plugins/timelines/public/components/t_grid/shared/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* 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 React from 'react';
import {
EuiPanel,
EuiFlexGroup,
EuiFlexItem,
EuiLoadingSpinner,
EuiImage,
EuiText,
EuiTitle,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
import type { CoreStart } from '../../../../../../../src/core/public';

const heights = {
tall: 490,
short: 250,
};

export const TGridLoading: React.FC<{ height?: keyof typeof heights }> = ({ height = 'tall' }) => {
return (
<EuiPanel color="subdued">
<EuiFlexGroup
style={{ height: heights[height] }}
alignItems="center"
justifyContent="center"
data-test-subj="loading-alerts-panel"
>
<EuiFlexItem grow={false}>
<EuiLoadingSpinner size="xl" />
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
);
};

const panelStyle = {
maxWidth: 500,
};

export const TGridEmpty: React.FC<{ height?: keyof typeof heights }> = ({ height = 'tall' }) => {
const { http } = useKibana<CoreStart>().services;

return (
<EuiPanel color="subdued">
<EuiFlexGroup style={{ height: heights[height] }} alignItems="center" justifyContent="center">
<EuiFlexItem grow={false}>
<EuiPanel hasBorder={true} style={panelStyle}>
<EuiFlexGroup>
<EuiFlexItem>
<EuiText size="s">
<EuiTitle>
<h3>
<FormattedMessage
id="xpack.timelines.tgrid.empty.title"
defaultMessage="No results match your search criteria"
/>
</h3>
</EuiTitle>
<p>
<FormattedMessage
id="xpack.timelines.tgrid.empty.description"
defaultMessage="Try searching over a longer period of time or modifying your search"
/>
</p>
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiImage
size="200"
alt=""
url={http.basePath.prepend(
'/plugins/timelines/assets/illustration_product_no_results_magnifying_glass.svg'
)}
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiLoadingContent } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiFlexItem } from '@elastic/eui';
import { isEmpty } from 'lodash/fp';
import React, { useEffect, useMemo, useState, useRef } from 'react';
import styled from 'styled-components';
Expand Down Expand Up @@ -39,10 +38,16 @@ import type { State } from '../../../store/t_grid';
import { useTimelineEvents } from '../../../container';
import { StatefulBody } from '../body';
import { LastUpdatedAt } from '../..';
import { SELECTOR_TIMELINE_GLOBAL_CONTAINER, UpdatedFlexItem, UpdatedFlexGroup } from '../styles';
import {
SELECTOR_TIMELINE_GLOBAL_CONTAINER,
UpdatedFlexItem,
UpdatedFlexGroup,
FullWidthFlexGroup,
} from '../styles';
import { InspectButton, InspectButtonContainer } from '../../inspect';
import { useFetchIndex } from '../../../container/source';
import { AddToCaseAction } from '../../actions/timeline/cases/add_to_case_action';
import { TGridLoading, TGridEmpty } from '../shared';

export const EVENTS_VIEWER_HEADER_HEIGHT = 90; // px
const STANDALONE_ID = 'standalone-t-grid';
Expand All @@ -68,12 +73,6 @@ const EventsContainerLoading = styled.div.attrs(({ className = '' }) => ({
flex-direction: column;
`;

const FullWidthFlexGroup = styled(EuiFlexGroup)<{ $visible: boolean }>`
overflow: hidden;
margin: 0;
display: ${({ $visible }) => ($visible ? 'flex' : 'none')};
`;

const ScrollableFlexItem = styled(EuiFlexItem)`
overflow: auto;
`;
Expand Down Expand Up @@ -255,6 +254,8 @@ const TGridStandaloneComponent: React.FC<TGridStandaloneProps> = ({
() => (totalCount > 0 ? totalCount - deletedEventIds.length : 0),
[deletedEventIds.length, totalCount]
);
const hasAlerts = totalCountMinusDeleted > 0;

const activeCaseFlowId = useSelector((state: State) => tGridSelectors.activeCaseFlowId(state));
const selectedEvent = useMemo(() => {
const matchedEvent = events.find((event) => event.ecs._id === activeCaseFlowId);
Expand Down Expand Up @@ -338,14 +339,14 @@ const TGridStandaloneComponent: React.FC<TGridStandaloneProps> = ({
return (
<InspectButtonContainer data-test-subj="events-viewer-panel">
<AlertsTableWrapper>
{isFirstUpdate.current && <EuiLoadingContent data-test-subj="loading-alerts-panel" />}
{isFirstUpdate.current && <TGridLoading />}
{canQueryTimeline ? (
<>
<EventsContainerLoading
data-timeline-id={STANDALONE_ID}
data-test-subj={`events-container-loading-${loading}`}
>
<UpdatedFlexGroup gutterSize="s" justifyContent="flexEnd" alignItems="baseline">
<UpdatedFlexGroup gutterSize="s" justifyContent="flexEnd" alignItems="center">
<UpdatedFlexItem grow={false} $show={!loading}>
<InspectButton title={justTitle} inspect={inspect} loading={loading} />
</UpdatedFlexItem>
Expand All @@ -354,28 +355,9 @@ const TGridStandaloneComponent: React.FC<TGridStandaloneProps> = ({
</UpdatedFlexItem>
</UpdatedFlexGroup>

{totalCountMinusDeleted === 0 && loading === false && (
<EuiEmptyPrompt
title={
<h2>
<FormattedMessage
id="xpack.timelines.tGrid.noResultsMatchSearchCriteriaTitle"
defaultMessage="No results match your search criteria"
/>
</h2>
}
titleSize="s"
body={
<p>
<FormattedMessage
id="xpack.timelines.tGrid.noResultsMatchSearchCriteriaDescription"
defaultMessage="Try searching over a longer period of time or modifying your search."
/>
</p>
}
/>
)}
{totalCountMinusDeleted > 0 && (
{!hasAlerts && !loading && <TGridEmpty />}

{hasAlerts && (
<FullWidthFlexGroup direction="row" $visible={!graphEventId} gutterSize="none">
<ScrollableFlexItem grow={1}>
<StatefulBody
Expand Down
7 changes: 7 additions & 0 deletions x-pack/plugins/timelines/public/components/t_grid/styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,13 @@ export const HideShowContainer = styled.div.attrs<{ $isVisible: boolean }>(
})
)<{ $isVisible: boolean }>``;

export const FullWidthFlexGroup = styled(EuiFlexGroup)<{ $visible?: boolean }>`
overflow: hidden;
margin: 0;
min-height: 490px;
display: ${({ $visible = true }) => ($visible ? 'flex' : 'none')};
`;

export const UpdatedFlexGroup = styled(EuiFlexGroup)`
position: absolute;
z-index: ${({ theme }) => theme.eui.euiZLevel1};
Expand Down
Loading

0 comments on commit 343b22c

Please sign in to comment.