From 6bd371c4b21d8e1dfe6fd2d60d654246eade337d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20G=C3=B3mez?= Date: Tue, 1 Oct 2019 10:18:21 +0200 Subject: [PATCH 1/9] Add `format` option to `useFormattedTime` Allows the consumers of the hook to specify if they want to show the full date and time or just the time. --- .../public/components/formatted_time.tsx | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/components/formatted_time.tsx b/x-pack/legacy/plugins/infra/public/components/formatted_time.tsx index f6a6545920fc5..78255c55df124 100644 --- a/x-pack/legacy/plugins/infra/public/components/formatted_time.tsx +++ b/x-pack/legacy/plugins/infra/public/components/formatted_time.tsx @@ -17,8 +17,25 @@ const getFormattedTime = ( return userFormat ? moment(time).format(userFormat) : moment(time).format(fallbackFormat); }; -export const useFormattedTime = (time: number, fallbackFormat?: string) => { - const [dateFormat] = useKibanaUiSetting('dateFormat'); +interface UseFormattedTimeOptions { + format?: 'dateTime' | 'time'; + fallbackFormat?: string; +} + +export const useFormattedTime = ( + time: number, + { format = 'dateTime', fallbackFormat }: UseFormattedTimeOptions = {} +) => { + // `dateFormat:scaled` is an array of `[key, format]` tuples. + // The hook might return `undefined`, so use a sane default for the `find` later. + const scaledTuples = useKibanaUiSetting('dateFormat:scaled')[0] || [['', undefined]]; + + const formatMap = { + dateTime: useKibanaUiSetting('dateFormat')[0], + time: scaledTuples.find(([key]: [string, string]) => key === '')[1], + }; + + const dateFormat = formatMap[format]; const formattedTime = useMemo(() => getFormattedTime(time, dateFormat, fallbackFormat), [ getFormattedTime, time, From 34b6f3b4b34783f3dbfa67c8f7c7218016ee017c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20G=C3=B3mez?= Date: Tue, 1 Oct 2019 10:21:01 +0200 Subject: [PATCH 2/9] Only show the time in the log stream --- .../logging/log_text_stream/log_entry_timestamp_column.tsx | 2 +- .../logging/log_text_stream/scrollable_log_text_stream_view.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_timestamp_column.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_timestamp_column.tsx index c996342d0c060..056d51313e127 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_timestamp_column.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_timestamp_column.tsx @@ -19,7 +19,7 @@ interface LogEntryTimestampColumnProps { export const LogEntryTimestampColumn = memo( ({ isHighlighted, isHovered, time }) => { - const formattedTime = useFormattedTime(time); + const formattedTime = useFormattedTime(time, { format: 'time' }); return ( diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx index 3c1fb2ceec7f6..15afd8cbbad1b 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx @@ -326,7 +326,7 @@ const WithColumnWidths: React.FunctionComponent<{ }> = ({ children, columnConfigurations, scale }) => { const { CharacterDimensionsProbe, dimensions } = useMeasuredCharacterDimensions(scale); const referenceTime = useMemo(() => Date.now(), []); - const formattedCurrentDate = useFormattedTime(referenceTime); + const formattedCurrentDate = useFormattedTime(referenceTime, { format: 'time' }); const columnWidths = useMemo( () => getColumnWidths(columnConfigurations, dimensions.width, formattedCurrentDate.length), [columnConfigurations, dimensions.width, formattedCurrentDate] From 99e415a7a469eccbf186ddb593b12787ce9a2555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20G=C3=B3mez?= Date: Wed, 2 Oct 2019 11:10:11 +0200 Subject: [PATCH 3/9] Add `localizedDate` util --- .../infra/public/utils/formatters/datetime.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 x-pack/legacy/plugins/infra/public/utils/formatters/datetime.ts diff --git a/x-pack/legacy/plugins/infra/public/utils/formatters/datetime.ts b/x-pack/legacy/plugins/infra/public/utils/formatters/datetime.ts new file mode 100644 index 0000000000000..732bc7fe74bf9 --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/utils/formatters/datetime.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export function localizedDate(dateTime: number | Date, locale: string = i18n.getLocale()) { + const formatter = new Intl.DateTimeFormat(locale, { + year: 'numeric', + month: 'short', + day: 'numeric', + }); + + return formatter.format(dateTime); +} From aca953b2c63f2e033f75a92962efeaf9b3b69ec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20G=C3=B3mez?= Date: Tue, 1 Oct 2019 15:15:41 +0200 Subject: [PATCH 4/9] Add `LogDateRow` component --- .../logging/log_text_stream/log_date_row.tsx | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_date_row.tsx diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_date_row.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_date_row.tsx new file mode 100644 index 0000000000000..fbc450950b828 --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_date_row.tsx @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiTitle } from '@elastic/eui'; +import { localizedDate } from '../../../utils/formatters/datetime'; + +interface LogDateRowProps { + timestamp: number; +} + +/** + * Show a row with the date in the log stream + */ +export const LogDateRow: React.FC = ({ timestamp }) => { + const formattedDate = localizedDate(timestamp); + + return ( + + + +

{formattedDate}

+
+
+ + + +
+ ); +}; From b11526f1ae6ba3b02faea7ce9a4f613a505417a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20G=C3=B3mez?= Date: Tue, 1 Oct 2019 15:21:22 +0200 Subject: [PATCH 5/9] Show a date marker in the stream when the date changes --- .../scrollable_log_text_stream_view.tsx | 74 +++++++++++-------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx index 15afd8cbbad1b..d439308194d18 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx @@ -6,7 +6,8 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import React, { useMemo } from 'react'; +import React, { Fragment, useMemo } from 'react'; +import moment from 'moment'; import euiStyled from '../../../../../../common/eui_styled_components'; import { TextScale } from '../../../../common/log_text_scale'; @@ -26,6 +27,7 @@ import { MeasurableItemView } from './measurable_item_view'; import { VerticalScrollPanel } from './vertical_scroll_panel'; import { getColumnWidths, LogEntryColumnWidths } from './log_entry_column'; import { useMeasuredCharacterDimensions } from './text_styles'; +import { LogDateRow } from './log_date_row'; interface ScrollableLogTextStreamViewProps { columnConfigurations: LogColumnConfiguration[]; @@ -188,35 +190,47 @@ export class ScrollableLogTextStreamView extends React.PureComponent< isStreaming={false} lastStreamingUpdate={null} /> - {items.map(item => ( - - {itemMeasureRef => ( - - )} - - ))} + {items.map((item, idx) => { + const currentTimestamp = item.logEntry.key.time; + let showDate = false; + + if (idx > 0) { + const prevTimestamp = items[idx - 1].logEntry.key.time; + showDate = !moment(currentTimestamp).isSame(prevTimestamp, 'day'); + } + + return ( + + {showDate && } + + {itemMeasureRef => ( + + )} + + + ); + })} Date: Tue, 1 Oct 2019 16:06:55 +0200 Subject: [PATCH 6/9] Show date of the first log line in the table header I tweaked the `RendererResult` type to allow returning strings as well in the renderer of `WithLogPosition`. --- .../log_text_stream/column_headers.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx index 3d78c8d728fc6..fd2aeaf909cd7 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx @@ -20,6 +20,8 @@ import { LogEntryColumnWidths, } from './log_entry_column'; import { ASSUMED_SCROLLBAR_WIDTH } from './vertical_scroll_panel'; +import { WithLogPosition } from '../../../containers/logs/with_log_position'; +import { localizedDate } from '../../../utils/formatters/datetime'; export const LogColumnHeaders: React.FunctionComponent<{ columnConfigurations: LogColumnConfiguration[]; @@ -30,13 +32,16 @@ export const LogColumnHeaders: React.FunctionComponent<{ {columnConfigurations.map(columnConfiguration => { if (isTimestampLogColumnConfiguration(columnConfiguration)) { return ( - - Timestamp - + + {({ firstVisiblePosition }) => ( + + {firstVisiblePosition ? localizedDate(firstVisiblePosition.time) : 'Timestamp'} + + )} + ); } else if (isMessageLogColumnConfiguration(columnConfiguration)) { return ( From 4dc92ff9274af6b735a7c30c12df524f51bc151c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20G=C3=B3mez?= Date: Tue, 1 Oct 2019 16:08:59 +0200 Subject: [PATCH 7/9] Tweak timestamp column to follow design --- .../logging/log_text_stream/log_entry_timestamp_column.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_timestamp_column.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_timestamp_column.tsx index 056d51313e127..884e5ff0a5bde 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_timestamp_column.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/log_entry_timestamp_column.tsx @@ -45,11 +45,8 @@ const TimestampColumnContent = LogEntryColumnContent.extend.attrs<{ isHovered: boolean; isHighlighted: boolean; }>({})` - background-color: ${props => props.theme.eui.euiColorLightestShade}; - border-right: solid 2px ${props => props.theme.eui.euiColorLightShade}; color: ${props => props.theme.eui.euiColorDarkShade}; overflow: hidden; - text-align: right; text-overflow: clip; white-space: pre; From 54282cffe214aea2da1217473fb6f998c356922f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20G=C3=B3mez?= Date: Wed, 2 Oct 2019 17:16:13 +0200 Subject: [PATCH 8/9] Add shadow to the log table header Make the wrapper relative to ensure the shadow stays on top of the rows, even when they are hovered. --- .../components/logging/log_text_stream/column_headers.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx index fd2aeaf909cd7..56a84d258c907 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx @@ -5,6 +5,7 @@ */ import React from 'react'; +import { transparentize } from 'polished'; import euiStyled from '../../../../../../common/eui_styled_components'; import { @@ -88,13 +89,16 @@ const LogColumnHeadersWrapper = euiStyled.div.attrs({ justify-content: flex-start; overflow: hidden; padding-right: ${ASSUMED_SCROLLBAR_WIDTH}px; + border-bottom: ${props => props.theme.eui.euiBorderThin}; + box-shadow: 0 2px 2px -1px ${props => transparentize(0.3, props.theme.eui.euiColorLightShade)}; + position: relative; + z-index: 1; `; const LogColumnHeaderWrapper = LogEntryColumn.extend.attrs({ role: 'columnheader', })` align-items: center; - border-bottom: ${props => props.theme.eui.euiBorderThick}; display: flex; flex-direction: row; height: 32px; From 0347e3ebc823bddb17104ad8b0d302db928febbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20G=C3=B3mez?= Date: Fri, 4 Oct 2019 16:51:53 +0200 Subject: [PATCH 9/9] Adjust the spec expectation --- .../test/functional/apps/infra/logs_source_configuration.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/test/functional/apps/infra/logs_source_configuration.ts b/x-pack/test/functional/apps/infra/logs_source_configuration.ts index 3447e03a680e1..183acf3a980ee 100644 --- a/x-pack/test/functional/apps/infra/logs_source_configuration.ts +++ b/x-pack/test/functional/apps/infra/logs_source_configuration.ts @@ -66,7 +66,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.common.navigateToActualUrl('infraLogs', 'logs/stream'); const columnHeaderLabels = await infraLogStream.getColumnHeaderLabels(); - expect(columnHeaderLabels).to.eql(['Timestamp', 'event.dataset', 'Message']); + expect(columnHeaderLabels).to.eql(['Oct 17, 2018', 'event.dataset', 'Message']); const logStreamEntries = await infraLogStream.getStreamEntries(); expect(logStreamEntries.length).to.be.greaterThan(0); @@ -98,7 +98,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // TODO: make test more robust // expect(columnHeaderLabels).to.eql(['host.name', 'Timestamp']); - expect(columnHeaderLabels).to.eql(['Timestamp', 'host.name']); + expect(columnHeaderLabels).to.eql(['Oct 17, 2018', 'host.name']); const logStreamEntries = await infraLogStream.getStreamEntries();