Skip to content

Commit

Permalink
[Security Solution][Detections] Improves Table UI (consistent dates) (#…
Browse files Browse the repository at this point in the history
…117643) (#118084)

[Security Solution][Detections] Improves Table UI (consistent dates) (#117643)

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>

Co-authored-by: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com>
  • Loading branch information
kibanamachine and vitaliidm committed Nov 9, 2021
1 parent 2bc289e commit 058f7f1
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 19 deletions.
1 change: 1 addition & 0 deletions x-pack/plugins/security_solution/common/constants.ts
Expand Up @@ -69,6 +69,7 @@ export const DEFAULT_RULE_REFRESH_IDLE_VALUE = 2700000 as const; // ms
export const DEFAULT_RULE_NOTIFICATION_QUERY_SIZE = 100 as const;
export const SECURITY_FEATURE_ID = 'Security' as const;
export const DEFAULT_SPACE_ID = 'default' as const;
export const DEFAULT_RELATIVE_DATE_THRESHOLD = 24 as const;

// Document path where threat indicator fields are expected. Fields are used
// to enrich signals, and are copied to threat.enrichments.
Expand Down
Expand Up @@ -166,5 +166,28 @@ describe('formatted_date', () => {

expect(wrapper.text()).toBe(getEmptyValue());
});

test('renders time as relative under 24hrs, configured through relativeThresholdInHrs', () => {
const timeThwentyThreeHrsAgo = new Date(
new Date().getTime() - 23 * 60 * 60 * 1000
).toISOString();
const wrapper = shallow(
<FormattedRelativePreferenceDate
relativeThresholdInHrs={24}
value={timeThwentyThreeHrsAgo}
/>
);

expect(wrapper.find('[data-test-subj="relative-time"]').exists()).toBe(true);
});

test('renders time as absolute over 24hrs, configured through relativeThresholdInHrs', () => {
const timeThirtyHrsAgo = new Date(new Date().getTime() - 30 * 60 * 60 * 1000).toISOString();
const wrapper = shallow(
<FormattedRelativePreferenceDate relativeThresholdInHrs={24} value={timeThirtyHrsAgo} />
);

expect(wrapper.find('[data-test-subj="preference-time"]').exists()).toBe(true);
});
});
});
Expand Up @@ -124,19 +124,22 @@ export interface FormattedRelativePreferenceDateProps {
* @see https://momentjs.com/docs/#/displaying/format/
*/
dateFormat?: string;
relativeThresholdInHrs?: number;
tooltipFieldName?: string;
tooltipAnchorClassName?: string;
}
/**
* Renders the specified date value according to under/over one hour
* Under an hour = relative format
* Over an hour = in a format determined by the user's preferences (can be overridden via prop),
* Renders the specified date value according to under/over configured by relativeThresholdInHrs in hours (default 1 hr)
* Under the relativeThresholdInHrs = relative format
* Over the relativeThresholdInHrs = in a format determined by the user's preferences (can be overridden via prop),
* with a tooltip that renders:
* - the name of the field
* - a humanized relative date (e.g. 16 minutes ago)
* - a long representation of the date that includes the day of the week (e.g. Thursday, March 21, 2019 6:47pm)
* - the raw date value (e.g. 2019-03-22T00:47:46Z)
*/
export const FormattedRelativePreferenceDate = React.memo<FormattedRelativePreferenceDateProps>(
({ value, dateFormat }) => {
({ value, dateFormat, tooltipFieldName, tooltipAnchorClassName, relativeThresholdInHrs = 1 }) => {
if (value == null) {
return getOrEmptyTagFromValue(value);
}
Expand All @@ -145,9 +148,17 @@ export const FormattedRelativePreferenceDate = React.memo<FormattedRelativePrefe
return getOrEmptyTagFromValue(value);
}
const date = maybeDate.toDate();
const shouldDisplayPreferenceTime = moment(date)
.add(relativeThresholdInHrs, 'hours')
.isBefore(new Date());

return (
<LocalizedDateTooltip date={date}>
{moment(date).add(1, 'hours').isBefore(new Date()) ? (
<LocalizedDateTooltip
date={date}
fieldName={tooltipFieldName}
className={tooltipAnchorClassName}
>
{shouldDisplayPreferenceTime ? (
<PreferenceFormattedDate
data-test-subj="preference-time"
value={date}
Expand Down
Expand Up @@ -14,15 +14,15 @@ import {
EuiIcon,
EuiLink,
} from '@elastic/eui';
import { FormattedMessage, FormattedRelative } from '@kbn/i18n/react';
import { FormattedMessage } from '@kbn/i18n/react';
import * as H from 'history';
import { sum } from 'lodash';
import React, { Dispatch } from 'react';

import { isMlRule } from '../../../../../../common/machine_learning/helpers';
import { Rule, RuleStatus } from '../../../../containers/detection_engine/rules';
import { getEmptyTagValue } from '../../../../../common/components/empty_value';
import { FormattedDate } from '../../../../../common/components/formatted_date';
import { FormattedRelativePreferenceDate } from '../../../../../common/components/formatted_date';
import { getRuleDetailsUrl } from '../../../../../common/components/link_to/redirect_to_detection_engine';
import { ActionToaster } from '../../../../../common/components/toasters';
import { getStatusColor } from '../../../../components/rules/rule_status/helpers';
Expand All @@ -36,13 +36,16 @@ import {
exportRulesAction,
} from './actions';
import { RulesTableAction } from '../../../../containers/detection_engine/rules/rules_table';
import { LocalizedDateTooltip } from '../../../../../common/components/localized_date_tooltip';
import { LinkAnchor } from '../../../../../common/components/links';
import { getToolTipContent, canEditRuleWithActions } from '../../../../../common/utils/privileges';
import { PopoverTooltip } from './popover_tooltip';
import { TagsDisplay } from './tag_display';
import { getRuleStatusText } from '../../../../../../common/detection_engine/utils';
import { APP_UI_ID, SecurityPageName } from '../../../../../../common/constants';
import {
APP_UI_ID,
SecurityPageName,
DEFAULT_RELATIVE_DATE_THRESHOLD,
} from '../../../../../../common/constants';
import { DocLinksStart, NavigateToAppOptions } from '../../../../../../../../../src/core/public';

export const getActions = (
Expand Down Expand Up @@ -200,9 +203,12 @@ export const getColumns = ({
return value == null ? (
getEmptyTagValue()
) : (
<LocalizedDateTooltip fieldName={i18n.COLUMN_LAST_COMPLETE_RUN} date={new Date(value)}>
<FormattedRelative value={value} />
</LocalizedDateTooltip>
<FormattedRelativePreferenceDate
tooltipFieldName={i18n.COLUMN_LAST_COMPLETE_RUN}
relativeThresholdInHrs={DEFAULT_RELATIVE_DATE_THRESHOLD}
value={value}
tooltipAnchorClassName="eui-textTruncate"
/>
);
},
width: '14%',
Expand All @@ -228,9 +234,12 @@ export const getColumns = ({
return value == null ? (
getEmptyTagValue()
) : (
<LocalizedDateTooltip fieldName={i18n.COLUMN_LAST_UPDATE} date={new Date(value)}>
<FormattedDate value={value} fieldName={'last rule update date'} />
</LocalizedDateTooltip>
<FormattedRelativePreferenceDate
tooltipFieldName={i18n.COLUMN_LAST_UPDATE}
relativeThresholdInHrs={DEFAULT_RELATIVE_DATE_THRESHOLD}
value={value}
tooltipAnchorClassName="eui-textTruncate"
/>
);
},
sortable: true,
Expand Down Expand Up @@ -410,9 +419,12 @@ export const getMonitoringColumns = (
return value == null ? (
getEmptyTagValue()
) : (
<LocalizedDateTooltip fieldName={i18n.COLUMN_LAST_COMPLETE_RUN} date={new Date(value)}>
<FormattedRelative value={value} />
</LocalizedDateTooltip>
<FormattedRelativePreferenceDate
tooltipFieldName={i18n.COLUMN_LAST_COMPLETE_RUN}
relativeThresholdInHrs={DEFAULT_RELATIVE_DATE_THRESHOLD}
value={value}
tooltipAnchorClassName="eui-textTruncate"
/>
);
},
width: '20%',
Expand Down
Expand Up @@ -9,7 +9,10 @@ import React from 'react';
import { EuiButtonIcon, EuiBasicTableColumn, EuiToolTip } from '@elastic/eui';

import type { NamespaceType } from '@kbn/securitysolution-io-ts-list-types';
import { DEFAULT_RELATIVE_DATE_THRESHOLD } from '../../../../../../../common/constants';
import { FormatUrl } from '../../../../../../common/components/link_to';
import { FormattedRelativePreferenceDate } from '../../../../../../common/components/formatted_date';

import * as i18n from './translations';
import { ExceptionListInfo } from './use_all_exception_lists';
import { ExceptionOverflowDisplay } from './exceptions_overflow_display';
Expand Down Expand Up @@ -84,13 +87,29 @@ export const getAllExceptionListsColumns = (
truncateText: true,
dataType: 'date',
width: '14%',
render: (value: ExceptionListInfo['created_at']) => (
<FormattedRelativePreferenceDate
relativeThresholdInHrs={DEFAULT_RELATIVE_DATE_THRESHOLD}
value={value}
tooltipFieldName={i18n.LIST_DATE_CREATED_TITLE}
tooltipAnchorClassName="eui-textTruncate"
/>
),
},
{
align: 'left',
field: 'updated_at',
name: i18n.LIST_DATE_UPDATED_TITLE,
truncateText: true,
width: '14%',
render: (value: ExceptionListInfo['updated_at']) => (
<FormattedRelativePreferenceDate
relativeThresholdInHrs={DEFAULT_RELATIVE_DATE_THRESHOLD}
value={value}
tooltipFieldName={i18n.LIST_DATE_UPDATED_TITLE}
tooltipAnchorClassName="eui-textTruncate"
/>
),
},
{
align: 'center',
Expand Down

0 comments on commit 058f7f1

Please sign in to comment.