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][Detections] Improves Table UI (consistent dates) #117643

Expand Up @@ -166,5 +166,27 @@ describe('formatted_date', () => {

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

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

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

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

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 @@ -146,8 +149,12 @@ export const FormattedRelativePreferenceDate = React.memo<FormattedRelativePrefe
}
const date = maybeDate.toDate();
return (
<LocalizedDateTooltip date={date}>
{moment(date).add(1, 'hours').isBefore(new Date()) ? (
<LocalizedDateTooltip
date={date}
fieldName={tooltipFieldName}
className={tooltipAnchorClassName}
>
{moment(date).add(relativeThresholdInHrs, 'hours').isBefore(new Date()) ? (
xcrzx marked this conversation as resolved.
Show resolved Hide resolved
<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,7 +36,6 @@ 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';
Expand Down Expand Up @@ -200,9 +199,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={24}
value={value}
tooltipAnchorClassName="eui-textTruncate"
/>
);
},
width: '14%',
Expand All @@ -228,9 +230,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={24}
xcrzx marked this conversation as resolved.
Show resolved Hide resolved
value={value}
tooltipAnchorClassName="eui-textTruncate"
/>
);
},
sortable: true,
Expand Down Expand Up @@ -410,9 +415,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={24}
value={value}
tooltipAnchorClassName="eui-textTruncate"
/>
);
},
width: '20%',
Expand Down
Expand Up @@ -10,6 +10,8 @@ import { EuiButtonIcon, EuiBasicTableColumn, EuiToolTip } from '@elastic/eui';

import type { NamespaceType } from '@kbn/securitysolution-io-ts-list-types';
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 +86,29 @@ export const getAllExceptionListsColumns = (
truncateText: true,
dataType: 'date',
width: '14%',
render: (value: ExceptionListInfo['created_at']) => (
<FormattedRelativePreferenceDate
relativeThresholdInHrs={24}
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={24}
value={value}
tooltipFieldName={i18n.LIST_DATE_UPDATED_TITLE}
tooltipAnchorClassName="eui-textTruncate"
/>
),
},
{
align: 'center',
Expand Down