From 2107d57675da943c0b0990a45c6bd88e30428092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Tue, 17 May 2022 11:48:20 +0200 Subject: [PATCH 01/18] Update TableListView table to render "updatedAt" metadata --- .../table_list_view.test.tsx.snap | 10 +- .../table_list_view/table_list_view.test.tsx | 110 +++++++++++++- .../table_list_view/table_list_view.tsx | 138 ++++++++++++++---- 3 files changed, 222 insertions(+), 36 deletions(-) diff --git a/src/plugins/kibana_react/public/table_list_view/__snapshots__/table_list_view.test.tsx.snap b/src/plugins/kibana_react/public/table_list_view/__snapshots__/table_list_view.test.tsx.snap index a0c34cfdfee07..a5aefe60ac62c 100644 --- a/src/plugins/kibana_react/public/table_list_view/__snapshots__/table_list_view.test.tsx.snap +++ b/src/plugins/kibana_react/public/table_list_view/__snapshots__/table_list_view.test.tsx.snap @@ -129,6 +129,7 @@ exports[`TableListView render list view 1`] = ` } /> } + onChange={[Function]} pagination={ Object { "initialPageIndex": 0, @@ -155,7 +156,14 @@ exports[`TableListView render list view 1`] = ` "toolsLeft": undefined, } } - sorting={true} + sorting={ + Object { + "sort": Object { + "direction": "asc", + "field": "columnTitle", + }, + } + } tableCaption="test caption" tableLayout="fixed" /> diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx index 13423047bc3f0..8fb08a78214a3 100644 --- a/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx +++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx @@ -7,13 +7,23 @@ */ import { EuiEmptyPrompt } from '@elastic/eui'; -import { shallowWithIntl } from '@kbn/test-jest-helpers'; +import { shallowWithIntl, registerTestBed, TestBed } from '@kbn/test-jest-helpers'; import { ToastsStart } from '@kbn/core/public'; import React from 'react'; +import { act } from 'react-dom/test-utils'; import { themeServiceMock, applicationServiceMock } from '@kbn/core/public/mocks'; -import { TableListView } from './table_list_view'; +import { TableListView, TableListViewProps } from './table_list_view'; -const requiredProps = { +jest.mock('lodash', () => { + const original = jest.requireActual('lodash'); + + return { + ...original, + debounce: (handler: () => void) => handler, + }; +}); + +const requiredProps: TableListViewProps> = { entityName: 'test', entityNamePlural: 'tests', listingLimit: 5, @@ -30,6 +40,14 @@ const requiredProps = { }; describe('TableListView', () => { + beforeAll(() => { + jest.useFakeTimers(); + }); + + afterAll(() => { + jest.useRealTimers(); + }); + test('render default empty prompt', async () => { const component = shallowWithIntl(); @@ -81,4 +99,90 @@ describe('TableListView', () => { expect(component).toMatchSnapshot(); }); + + describe('default columns', () => { + const tableColumns = [ + { + field: 'columnTitle', + name: 'Title', + sortable: true, + }, + { + field: 'description', + name: 'Description', + sortable: true, + }, + ]; + + const hits = [ + { + columnTitle: 'Item 1', + description: 'Item 1 description', + updatedAt: new Date(new Date().setDate(new Date().getDate() - 2)), + }, + { + columnTitle: 'Item 2', + description: 'Item 2 description', + // This is the latest updated and should come first in the table + updatedAt: new Date(new Date().setDate(new Date().getDate() - 1)), + }, + ]; + + const findItems = jest.fn(() => Promise.resolve({ total: hits.length, hits })); + + const defaultProps: TableListViewProps> = { + ...requiredProps, + tableColumns, + findItems, + createItem: () => undefined, + }; + + const setup = registerTestBed(TableListView, { defaultProps }); + + test('should add a "Last updated" column if "updatedAt" is provided', async () => { + let testBed: TestBed; + + await act(async () => { + testBed = await setup(); + }); + + const { component, table } = testBed!; + component.update(); + + const { tableCellsValues } = table.getMetaData('itemsInMemTable'); + + expect(tableCellsValues).toEqual([ + ['Item 2', 'Item 2 description', 'a day ago'], // Comes first as it is the latest updated + ['Item 1', 'Item 1 description', '2 days ago'], + ]); + }); + + test('should not add a "Last updated" column if no "updatedAt" is provided', async () => { + let testBed: TestBed; + + await act(async () => { + testBed = await setup({ + findItems: jest.fn(() => + Promise.resolve({ + total: hits.length, + hits: hits.map((hit) => { + const { updatedAt, ...rest } = hit; + return rest; + }), + }) + ), + }); + }); + + const { component, table } = testBed!; + component.update(); + + const { tableCellsValues } = table.getMetaData('itemsInMemTable'); + + expect(tableCellsValues).toEqual([ + ['Item 1', 'Item 1 description'], // Sorted by title + ['Item 2', 'Item 2 description'], + ]); + }); + }); }); diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx index ece2fa37cc832..5be25eb31bb52 100644 --- a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx +++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx @@ -13,6 +13,9 @@ import { EuiConfirmModal, EuiEmptyPrompt, EuiInMemoryTable, + Criteria, + PropertySort, + Direction, EuiLink, EuiSpacer, EuiTableActionsColumnType, @@ -23,6 +26,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { ThemeServiceStart, HttpFetchError, ToastsStart, ApplicationStart } from '@kbn/core/public'; import { debounce, keyBy, sortBy, uniq } from 'lodash'; import React from 'react'; +import moment from 'moment'; import { KibanaPageTemplate } from '../page_template'; import { toMountPoint } from '../util'; @@ -64,6 +68,7 @@ export interface TableListViewProps { export interface TableListViewState { items: V[]; hasInitialFetchReturned: boolean; + hasUpdatedAtMetadata: boolean | null; isFetchingItems: boolean; isDeletingItems: boolean; showDeleteModal: boolean; @@ -72,6 +77,10 @@ export interface TableListViewState { filter: string; selectedIds: string[]; totalItems: number; + tableSort: { + field: keyof V; + direction: Direction; + }; } // saved object client does not support sorting by title because title is only mapped as analyzed @@ -79,7 +88,7 @@ export interface TableListViewState { // and not supporting server-side paging. // This component does not try to tackle these problems (yet) and is just feature matching the legacy component // TODO support server side sorting/paging once title and description are sortable on the server. -class TableListView extends React.Component< +class TableListView extends React.Component< TableListViewProps, TableListViewState > { @@ -94,16 +103,22 @@ class TableListView extends React.Component< initialPageSize: props.initialPageSize, pageSizeOptions: uniq([10, 20, 50, props.initialPageSize]).sort(), }; + this.state = { items: [], totalItems: 0, hasInitialFetchReturned: false, + hasUpdatedAtMetadata: null, isFetchingItems: false, isDeletingItems: false, showDeleteModal: false, showLimitError: false, filter: props.initialFilter, selectedIds: [], + tableSort: { + field: 'columnTitle', + direction: 'asc', + }, }; } @@ -120,6 +135,28 @@ class TableListView extends React.Component< this.fetchItems(); } + componentDidUpdate(prevProps: TableListViewProps, prevState: TableListViewState) { + if (this.state.hasUpdatedAtMetadata === null && prevState.items !== this.state.items) { + // We check if the saved object have the "updatedAt" metadata + // to render or not that column in the table + const hasUpdatedAtMetadata = Boolean( + this.state.items.find((item) => Boolean(item.updatedAt)) + ); + + this.setState((prev) => { + return { + hasUpdatedAtMetadata, + tableSort: hasUpdatedAtMetadata + ? { + field: 'updatedAt', + direction: 'desc' as const, + } + : prev.tableSort, + }; + }); + } + } + debouncedFetch = debounce(async (filter: string) => { try { const response = await this.props.findItems(filter); @@ -420,6 +457,12 @@ class TableListView extends React.Component< ); } + onTableChange(criteria: Criteria) { + if (criteria.sort) { + this.setState({ tableSort: criteria.sort }); + } + } + renderTable() { const { searchFilters } = this.props; @@ -435,24 +478,6 @@ class TableListView extends React.Component< } : undefined; - const actions: EuiTableActionsColumnType['actions'] = [ - { - name: i18n.translate('kibana-react.tableListView.listing.table.editActionName', { - defaultMessage: 'Edit', - }), - description: i18n.translate( - 'kibana-react.tableListView.listing.table.editActionDescription', - { - defaultMessage: 'Edit', - } - ), - icon: 'pencil', - type: 'icon', - enabled: (v) => !(v as unknown as { error: string })?.error, - onClick: this.props.editItem, - }, - ]; - const search = { onChange: this.setFilter.bind(this), toolsLeft: this.renderToolsLeft(), @@ -464,17 +489,6 @@ class TableListView extends React.Component< filters: searchFilters ?? [], }; - const columns = this.props.tableColumns.slice(); - if (this.props.editItem) { - columns.push({ - name: i18n.translate('kibana-react.tableListView.listing.table.actionTitle', { - defaultMessage: 'Actions', - }), - width: '100px', - actions, - }); - } - const noItemsMessage = ( extends React.Component< values={{ entityNamePlural: this.props.entityNamePlural }} /> ); + return ( extends React.Component< ); } + getTableColumns() { + const columns = this.props.tableColumns.slice(); + + // Add "Last update" column + if (this.state.hasUpdatedAtMetadata) { + const renderUpdatedAt = (dateTime: string) => { + const updatedAt = moment(dateTime); + + if (updatedAt.diff(moment(), 'days') > -7) { + return updatedAt.fromNow(); + } + return updatedAt.format('L @ LT'); + }; + + columns.push({ + field: 'updatedAt', + name: i18n.translate('kibana-react.tableListView.lastUpdatedColumnTitle', { + defaultMessage: 'Last updated', + }), + render: (field: string, record) => ( + {renderUpdatedAt(record.updatedAt as string)} + ), + sortable: true, + }); + } + + // Add "Actions" column + if (this.props.editItem) { + const actions: EuiTableActionsColumnType['actions'] = [ + { + name: i18n.translate('kibana-react.tableListView.listing.table.editActionName', { + defaultMessage: 'Edit', + }), + description: i18n.translate( + 'kibana-react.tableListView.listing.table.editActionDescription', + { + defaultMessage: 'Edit', + } + ), + icon: 'pencil', + type: 'icon', + enabled: (v) => !(v as unknown as { error: string })?.error, + onClick: this.props.editItem, + }, + ]; + + columns.push({ + name: i18n.translate('kibana-react.tableListView.listing.table.actionTitle', { + defaultMessage: 'Actions', + }), + width: '100px', + actions, + }); + } + + return columns; + } + renderCreateButton() { if (this.props.createItem) { return ( From 90a7b692511a99bf635a3b3397698f9a277a7c90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Tue, 17 May 2022 14:18:54 +0200 Subject: [PATCH 02/18] Use i18n FormattedRelative instead of moment.fromNow() --- .../table_list_view/table_list_view.test.tsx | 57 +++++++++++++++---- .../table_list_view/table_list_view.tsx | 14 +++-- 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx index 8fb08a78214a3..88756ec03130d 100644 --- a/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx +++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx @@ -10,6 +10,7 @@ import { EuiEmptyPrompt } from '@elastic/eui'; import { shallowWithIntl, registerTestBed, TestBed } from '@kbn/test-jest-helpers'; import { ToastsStart } from '@kbn/core/public'; import React from 'react'; +import moment, { Moment } from 'moment'; import { act } from 'react-dom/test-utils'; import { themeServiceMock, applicationServiceMock } from '@kbn/core/public/mocks'; import { TableListView, TableListViewProps } from './table_list_view'; @@ -101,6 +102,8 @@ describe('TableListView', () => { }); describe('default columns', () => { + let testBed: TestBed; + const tableColumns = [ { field: 'columnTitle', @@ -114,17 +117,20 @@ describe('TableListView', () => { }, ]; + const twoDaysAgo = new Date(new Date().setDate(new Date().getDate() - 2)); + const yesterday = new Date(new Date().setDate(new Date().getDate() - 1)); + const hits = [ { columnTitle: 'Item 1', description: 'Item 1 description', - updatedAt: new Date(new Date().setDate(new Date().getDate() - 2)), + updatedAt: twoDaysAgo, }, { columnTitle: 'Item 2', description: 'Item 2 description', // This is the latest updated and should come first in the table - updatedAt: new Date(new Date().setDate(new Date().getDate() - 1)), + updatedAt: yesterday, }, ]; @@ -140,8 +146,6 @@ describe('TableListView', () => { const setup = registerTestBed(TableListView, { defaultProps }); test('should add a "Last updated" column if "updatedAt" is provided', async () => { - let testBed: TestBed; - await act(async () => { testBed = await setup(); }); @@ -152,23 +156,54 @@ describe('TableListView', () => { const { tableCellsValues } = table.getMetaData('itemsInMemTable'); expect(tableCellsValues).toEqual([ - ['Item 2', 'Item 2 description', 'a day ago'], // Comes first as it is the latest updated + ['Item 2', 'Item 2 description', 'yesterday'], // Comes first as it is the latest updated ['Item 1', 'Item 1 description', '2 days ago'], ]); }); - test('should not add a "Last updated" column if no "updatedAt" is provided', async () => { - let testBed: TestBed; + test('should not display relative time for items updated more than 7 days ago', async () => { + const updatedAtValues: Moment[] = []; + + const updatedHits = hits.map(({ columnTitle, description }, i) => { + const updatedAt = new Date(new Date().setDate(new Date().getDate() - (7 + i))); + updatedAtValues[i] = moment(updatedAt); + + return { + columnTitle, + description, + updatedAt, + }; + }); + + await act(async () => { + testBed = await setup({ + findItems: jest.fn(() => + Promise.resolve({ + total: updatedHits.length, + hits: updatedHits, + }) + ), + }); + }); + const { component, table } = testBed!; + component.update(); + + const { tableCellsValues } = table.getMetaData('itemsInMemTable'); + + expect(tableCellsValues).toEqual([ + ['Item 1', 'Item 1 description', updatedAtValues[0].format('L @ LT')], + ['Item 2', 'Item 2 description', updatedAtValues[1].format('L @ LT')], + ]); + }); + + test('should not add a "Last updated" column if no "updatedAt" is provided', async () => { await act(async () => { testBed = await setup({ findItems: jest.fn(() => Promise.resolve({ total: hits.length, - hits: hits.map((hit) => { - const { updatedAt, ...rest } = hit; - return rest; - }), + hits: hits.map(({ columnTitle, description }) => ({ columnTitle, description })), }) ), }); diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx index 5be25eb31bb52..45879a9bb90b6 100644 --- a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx +++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx @@ -22,7 +22,7 @@ import { SearchFilterConfig, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; +import { FormattedMessage, FormattedRelative } from '@kbn/i18n-react'; import { ThemeServiceStart, HttpFetchError, ToastsStart, ApplicationStart } from '@kbn/core/public'; import { debounce, keyBy, sortBy, uniq } from 'lodash'; import React from 'react'; @@ -525,9 +525,13 @@ class TableListView extends React.Componen const updatedAt = moment(dateTime); if (updatedAt.diff(moment(), 'days') > -7) { - return updatedAt.fromNow(); + return ( + + {(formattedDate: string) => {formattedDate}} + + ); } - return updatedAt.format('L @ LT'); + return {updatedAt.format('L @ LT')}; }; columns.push({ @@ -535,9 +539,7 @@ class TableListView extends React.Componen name: i18n.translate('kibana-react.tableListView.lastUpdatedColumnTitle', { defaultMessage: 'Last updated', }), - render: (field: string, record) => ( - {renderUpdatedAt(record.updatedAt as string)} - ), + render: (field: string, record) => renderUpdatedAt(record.updatedAt as string), sortable: true, }); } From 13fd0f1d8cee0ed3f89a9e6eeccb94944deaa2d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Tue, 17 May 2022 14:31:42 +0200 Subject: [PATCH 03/18] Dashboard: add updatedAt metadata to table items --- .../public/services/saved_object_loader.ts | 20 ++++++++++++------- .../table_list_view/table_list_view.tsx | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/plugins/dashboard/public/services/saved_object_loader.ts b/src/plugins/dashboard/public/services/saved_object_loader.ts index 3c406357c0294..780daa2939aa4 100644 --- a/src/plugins/dashboard/public/services/saved_object_loader.ts +++ b/src/plugins/dashboard/public/services/saved_object_loader.ts @@ -98,12 +98,16 @@ export class SavedObjectLoader { mapHitSource( source: Record, id: string, - references: SavedObjectReference[] = [] - ) { - source.id = id; - source.url = this.urlFor(id); - source.references = references; - return source; + references: SavedObjectReference[] = [], + updatedAt?: string + ): Record { + return { + ...source, + id, + url: this.urlFor(id), + references, + updatedAt, + }; } /** @@ -116,12 +120,14 @@ export class SavedObjectLoader { attributes, id, references = [], + updatedAt, }: { attributes: Record; id: string; references?: SavedObjectReference[]; + updatedAt?: string; }) { - return this.mapHitSource(attributes, id, references); + return this.mapHitSource(attributes, id, references, updatedAt); } /** diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx index 45879a9bb90b6..f4a891151a152 100644 --- a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx +++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx @@ -116,7 +116,7 @@ class TableListView extends React.Componen filter: props.initialFilter, selectedIds: [], tableSort: { - field: 'columnTitle', + field: '', direction: 'asc', }, }; From 53a0a94be9887d7ae82b72c05126cc00a19dc01b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Tue, 17 May 2022 14:55:14 +0200 Subject: [PATCH 04/18] Handle the case where one item does not have updatedAt metadata --- .../table_list_view.test.tsx.snap | 2 +- .../table_list_view/table_list_view.test.tsx | 37 ++++++++++++++++--- .../table_list_view/table_list_view.tsx | 4 ++ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/plugins/kibana_react/public/table_list_view/__snapshots__/table_list_view.test.tsx.snap b/src/plugins/kibana_react/public/table_list_view/__snapshots__/table_list_view.test.tsx.snap index a5aefe60ac62c..9cce39bad620d 100644 --- a/src/plugins/kibana_react/public/table_list_view/__snapshots__/table_list_view.test.tsx.snap +++ b/src/plugins/kibana_react/public/table_list_view/__snapshots__/table_list_view.test.tsx.snap @@ -160,7 +160,7 @@ exports[`TableListView render list view 1`] = ` Object { "sort": Object { "direction": "asc", - "field": "columnTitle", + "field": "", }, } } diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx index 88756ec03130d..78435dd97e871 100644 --- a/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx +++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx @@ -106,7 +106,7 @@ describe('TableListView', () => { const tableColumns = [ { - field: 'columnTitle', + field: 'title', name: 'Title', sortable: true, }, @@ -122,12 +122,12 @@ describe('TableListView', () => { const hits = [ { - columnTitle: 'Item 1', + title: 'Item 1', description: 'Item 1 description', updatedAt: twoDaysAgo, }, { - columnTitle: 'Item 2', + title: 'Item 2', description: 'Item 2 description', // This is the latest updated and should come first in the table updatedAt: yesterday, @@ -164,12 +164,12 @@ describe('TableListView', () => { test('should not display relative time for items updated more than 7 days ago', async () => { const updatedAtValues: Moment[] = []; - const updatedHits = hits.map(({ columnTitle, description }, i) => { + const updatedHits = hits.map(({ title, description }, i) => { const updatedAt = new Date(new Date().setDate(new Date().getDate() - (7 + i))); updatedAtValues[i] = moment(updatedAt); return { - columnTitle, + title, description, updatedAt, }; @@ -192,6 +192,7 @@ describe('TableListView', () => { const { tableCellsValues } = table.getMetaData('itemsInMemTable'); expect(tableCellsValues).toEqual([ + // Renders the datetime with this format: "05/10/2022 @ 2:34 PM" ['Item 1', 'Item 1 description', updatedAtValues[0].format('L @ LT')], ['Item 2', 'Item 2 description', updatedAtValues[1].format('L @ LT')], ]); @@ -203,7 +204,7 @@ describe('TableListView', () => { findItems: jest.fn(() => Promise.resolve({ total: hits.length, - hits: hits.map(({ columnTitle, description }) => ({ columnTitle, description })), + hits: hits.map(({ title, description }) => ({ title, description })), }) ), }); @@ -219,5 +220,29 @@ describe('TableListView', () => { ['Item 2', 'Item 2 description'], ]); }); + + test('should not display anything if there is no updatedAt metadata for an item', async () => { + await act(async () => { + testBed = await setup({ + findItems: jest.fn(() => + Promise.resolve({ + total: hits.length + 1, + hits: [...hits, { title: 'Item 3', description: 'Item 3 description' }], + }) + ), + }); + }); + + const { component, table } = testBed!; + component.update(); + + const { tableCellsValues } = table.getMetaData('itemsInMemTable'); + + expect(tableCellsValues).toEqual([ + ['Item 2', 'Item 2 description', 'yesterday'], + ['Item 1', 'Item 1 description', '2 days ago'], + ['Item 3', 'Item 3 description', ''], // Empty column as no updatedAt provided + ]); + }); }); }); diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx index f4a891151a152..cde520271b76d 100644 --- a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx +++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx @@ -522,6 +522,10 @@ class TableListView extends React.Componen // Add "Last update" column if (this.state.hasUpdatedAtMetadata) { const renderUpdatedAt = (dateTime: string) => { + if (!dateTime) { + return ; + } + const updatedAt = moment(dateTime); if (updatedAt.diff(moment(), 'days') > -7) { From ac816e5f42119d1209d38670806bb6e540e5442f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Tue, 17 May 2022 15:05:03 +0200 Subject: [PATCH 05/18] Visualizations: add updatedAt metadata to table items --- .../visualizations/public/utils/saved_visualize_utils.ts | 4 ++++ x-pack/plugins/lens/public/vis_type_alias.ts | 3 ++- x-pack/plugins/maps/public/maps_vis_type_alias.ts | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/plugins/visualizations/public/utils/saved_visualize_utils.ts b/src/plugins/visualizations/public/utils/saved_visualize_utils.ts index 5b8ba8ce04cb4..9e95d69dfb3db 100644 --- a/src/plugins/visualizations/public/utils/saved_visualize_utils.ts +++ b/src/plugins/visualizations/public/utils/saved_visualize_utils.ts @@ -64,10 +64,12 @@ export function mapHitSource( attributes, id, references, + updatedAt, }: { attributes: SavedObjectAttributes; id: string; references: SavedObjectReference[]; + updatedAt: string; } ) { const newAttributes: { @@ -76,6 +78,7 @@ export function mapHitSource( url: string; savedObjectType?: string; editUrl?: string; + updatedAt?: string; type?: BaseVisType; icon?: BaseVisType['icon']; image?: BaseVisType['image']; @@ -85,6 +88,7 @@ export function mapHitSource( id, references, url: urlFor(id), + updatedAt, ...attributes, }; diff --git a/x-pack/plugins/lens/public/vis_type_alias.ts b/x-pack/plugins/lens/public/vis_type_alias.ts index be8a5620ce614..11a97ae82470f 100644 --- a/x-pack/plugins/lens/public/vis_type_alias.ts +++ b/x-pack/plugins/lens/public/vis_type_alias.ts @@ -31,12 +31,13 @@ export const getLensAliasConfig = (): VisTypeAlias => ({ docTypes: ['lens'], searchFields: ['title^3'], toListItem(savedObject) { - const { id, type, attributes } = savedObject; + const { id, type, updatedAt, attributes } = savedObject; const { title, description } = attributes as { title: string; description?: string }; return { id, title, description, + updatedAt, editUrl: getEditPath(id), editApp: 'lens', icon: 'lensApp', diff --git a/x-pack/plugins/maps/public/maps_vis_type_alias.ts b/x-pack/plugins/maps/public/maps_vis_type_alias.ts index e6dad590b037a..6d424955a5efe 100644 --- a/x-pack/plugins/maps/public/maps_vis_type_alias.ts +++ b/x-pack/plugins/maps/public/maps_vis_type_alias.ts @@ -38,12 +38,14 @@ export function getMapsVisTypeAlias(visualizations: VisualizationsSetup) { docTypes: [MAP_SAVED_OBJECT_TYPE], searchFields: ['title^3'], toListItem(savedObject: SavedObject) { - const { id, type, attributes } = savedObject as MapSavedObject; + const { id, type, updatedAt, attributes } = savedObject as MapSavedObject; const { title, description } = attributes; + return { id, title, description, + updatedAt, editUrl: getEditPath(id), editApp: APP_ID, icon: APP_ICON, From 232ae4013b2b262b1ec48e69930453551bb638cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Tue, 17 May 2022 15:05:47 +0200 Subject: [PATCH 06/18] [core] Fix case for "updatedAt" prop on SavedObject --- src/core/types/saved_objects.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/types/saved_objects.ts b/src/core/types/saved_objects.ts index 3a97c2fd6f010..ed705d18b591d 100644 --- a/src/core/types/saved_objects.ts +++ b/src/core/types/saved_objects.ts @@ -74,7 +74,7 @@ export interface SavedObject { /** An opaque version number which changes on each successful write operation. Can be used for implementing optimistic concurrency control. */ version?: string; /** Timestamp of the last time this document had been updated. */ - updated_at?: string; + updatedAt?: string; error?: SavedObjectError; /** {@inheritdoc SavedObjectAttributes} */ attributes: T; From 8cbdfa92d6c5069b32e411e592115ef0a9da0bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Tue, 17 May 2022 15:08:43 +0200 Subject: [PATCH 07/18] Maps: add updatedAt metadata to table items --- x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx b/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx index 5aa8e7877628a..9278f08bd4d2d 100644 --- a/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx +++ b/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx @@ -113,6 +113,7 @@ async function findMaps(searchQuery: string) { title: savedObject.attributes.title, description: savedObject.attributes.description, references: savedObject.references, + updatedAt: savedObject.updatedAt, }; }), }; From 71ecd9b3f53f8c844f4859f69d5417d7106e8778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Tue, 17 May 2022 15:16:07 +0200 Subject: [PATCH 08/18] Refactor TS typing --- .../public/table_list_view/table_list_view.tsx | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx index cde520271b76d..b2b9cba748140 100644 --- a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx +++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx @@ -77,7 +77,7 @@ export interface TableListViewState { filter: string; selectedIds: string[]; totalItems: number; - tableSort: { + tableSort?: { field: keyof V; direction: Direction; }; @@ -88,7 +88,7 @@ export interface TableListViewState { // and not supporting server-side paging. // This component does not try to tackle these problems (yet) and is just feature matching the legacy component // TODO support server side sorting/paging once title and description are sortable on the server. -class TableListView extends React.Component< +class TableListView extends React.Component< TableListViewProps, TableListViewState > { @@ -115,10 +115,6 @@ class TableListView extends React.Componen showLimitError: false, filter: props.initialFilter, selectedIds: [], - tableSort: { - field: '', - direction: 'asc', - }, }; } @@ -140,7 +136,7 @@ class TableListView extends React.Componen // We check if the saved object have the "updatedAt" metadata // to render or not that column in the table const hasUpdatedAtMetadata = Boolean( - this.state.items.find((item) => Boolean(item.updatedAt)) + this.state.items.find((item: { updatedAt?: string }) => Boolean(item.updatedAt)) ); this.setState((prev) => { @@ -148,7 +144,7 @@ class TableListView extends React.Componen hasUpdatedAtMetadata, tableSort: hasUpdatedAtMetadata ? { - field: 'updatedAt', + field: 'updatedAt' as keyof V, direction: 'desc' as const, } : prev.tableSort, @@ -521,11 +517,10 @@ class TableListView extends React.Componen // Add "Last update" column if (this.state.hasUpdatedAtMetadata) { - const renderUpdatedAt = (dateTime: string) => { + const renderUpdatedAt = (dateTime?: string) => { if (!dateTime) { return ; } - const updatedAt = moment(dateTime); if (updatedAt.diff(moment(), 'days') > -7) { @@ -543,7 +538,8 @@ class TableListView extends React.Componen name: i18n.translate('kibana-react.tableListView.lastUpdatedColumnTitle', { defaultMessage: 'Last updated', }), - render: (field: string, record) => renderUpdatedAt(record.updatedAt as string), + render: (field: string, record: { updatedAt?: string }) => + renderUpdatedAt(record.updatedAt), sortable: true, }); } From 75272ca788e6fb0a08b1b0bb95e3f1c6dea3e403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Tue, 17 May 2022 15:23:05 +0200 Subject: [PATCH 09/18] Graph: add updatedAt metadata to table items --- x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts b/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts index 72cca61832ca0..202d13f9cd539 100644 --- a/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts +++ b/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts @@ -53,6 +53,7 @@ function mapHits(hit: any, url: string): GraphWorkspaceSavedObject { const source = hit.attributes; source.id = hit.id; source.url = url; + source.updatedAt = hit.updatedAt; source.icon = 'fa-share-alt'; // looks like a graph return source; } From 00420916475b2c877a9ff7e47bea2bba6945754c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Tue, 17 May 2022 15:41:39 +0200 Subject: [PATCH 10/18] Revert "[core] Fix case for "updatedAt" prop on SavedObject" This reverts commit a14161805945fbe9538827c5bc7bff8919d55eab. --- src/core/types/saved_objects.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/types/saved_objects.ts b/src/core/types/saved_objects.ts index ed705d18b591d..3a97c2fd6f010 100644 --- a/src/core/types/saved_objects.ts +++ b/src/core/types/saved_objects.ts @@ -74,7 +74,7 @@ export interface SavedObject { /** An opaque version number which changes on each successful write operation. Can be used for implementing optimistic concurrency control. */ version?: string; /** Timestamp of the last time this document had been updated. */ - updatedAt?: string; + updated_at?: string; error?: SavedObjectError; /** {@inheritdoc SavedObjectAttributes} */ attributes: T; From 88c203dca5f86f38aff0e6a4393e6423b8ff3523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Tue, 17 May 2022 15:53:29 +0200 Subject: [PATCH 11/18] Fix TS types --- .../visualizations/public/utils/saved_visualize_utils.ts | 2 +- .../public/vis_types/vis_type_alias_registry.ts | 4 ++-- x-pack/plugins/maps/common/map_saved_object_type.ts | 5 ++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/plugins/visualizations/public/utils/saved_visualize_utils.ts b/src/plugins/visualizations/public/utils/saved_visualize_utils.ts index 9e95d69dfb3db..f5444b6269e22 100644 --- a/src/plugins/visualizations/public/utils/saved_visualize_utils.ts +++ b/src/plugins/visualizations/public/utils/saved_visualize_utils.ts @@ -69,7 +69,7 @@ export function mapHitSource( attributes: SavedObjectAttributes; id: string; references: SavedObjectReference[]; - updatedAt: string; + updatedAt?: string; } ) { const newAttributes: { diff --git a/src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts b/src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts index 2945aaa1a0cc8..f113a0a212fe6 100644 --- a/src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts +++ b/src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { SavedObject } from '@kbn/core/types/saved_objects'; +import type { SimpleSavedObject } from '@kbn/core/public'; import { BaseVisType } from './base_vis_type'; export type VisualizationStage = 'experimental' | 'beta' | 'production'; @@ -30,7 +30,7 @@ export interface VisualizationListItem { export interface VisualizationsAppExtension { docTypes: string[]; searchFields?: string[]; - toListItem: (savedObject: SavedObject) => VisualizationListItem; + toListItem: (savedObject: SimpleSavedObject) => VisualizationListItem; } export interface VisTypeAlias { diff --git a/x-pack/plugins/maps/common/map_saved_object_type.ts b/x-pack/plugins/maps/common/map_saved_object_type.ts index b37c1af5949c1..5a8216ea49030 100644 --- a/x-pack/plugins/maps/common/map_saved_object_type.ts +++ b/x-pack/plugins/maps/common/map_saved_object_type.ts @@ -6,8 +6,7 @@ */ /* eslint-disable @typescript-eslint/consistent-type-definitions */ - -import { SavedObject } from '@kbn/core/types/saved_objects'; +import type { SimpleSavedObject } from '@kbn/core/public'; export type MapSavedObjectAttributes = { title: string; @@ -17,4 +16,4 @@ export type MapSavedObjectAttributes = { uiStateJSON?: string; }; -export type MapSavedObject = SavedObject; +export type MapSavedObject = SimpleSavedObject; From aca69bf8bba7f4747f598a53df3c164385fee22d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Wed, 18 May 2022 08:57:06 +0100 Subject: [PATCH 12/18] Apply suggestions from Caroline code review Co-authored-by: Caroline Horn <549577+cchaos@users.noreply.github.com> --- .../public/table_list_view/table_list_view.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx index b2b9cba748140..948563984987a 100644 --- a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx +++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx @@ -526,11 +526,19 @@ class TableListView extends React.Component< if (updatedAt.diff(moment(), 'days') > -7) { return ( - {(formattedDate: string) => {formattedDate}} + {(formattedDate: string) => ( + + {formattedDate} + + )} ); } - return {updatedAt.format('L @ LT')}; + return ( + + {updatedAt.format('LL')} + + ); }; columns.push({ @@ -541,6 +549,7 @@ class TableListView extends React.Component< render: (field: string, record: { updatedAt?: string }) => renderUpdatedAt(record.updatedAt), sortable: true, + width: '150px', }); } From a7d1a53077807af4ec1a71fe5d73949cf1e9d0a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Wed, 18 May 2022 11:21:50 +0200 Subject: [PATCH 13/18] Fix maps TS types --- x-pack/plugins/maps/common/map_saved_object_type.ts | 3 --- x-pack/plugins/maps/public/maps_vis_type_alias.ts | 6 ++++-- x-pack/plugins/maps/server/maps_telemetry/find_maps.ts | 6 +++--- .../index_pattern_stats/index_pattern_stats_collector.ts | 5 +++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/maps/common/map_saved_object_type.ts b/x-pack/plugins/maps/common/map_saved_object_type.ts index 5a8216ea49030..f16683f56ef6d 100644 --- a/x-pack/plugins/maps/common/map_saved_object_type.ts +++ b/x-pack/plugins/maps/common/map_saved_object_type.ts @@ -6,7 +6,6 @@ */ /* eslint-disable @typescript-eslint/consistent-type-definitions */ -import type { SimpleSavedObject } from '@kbn/core/public'; export type MapSavedObjectAttributes = { title: string; @@ -15,5 +14,3 @@ export type MapSavedObjectAttributes = { layerListJSON?: string; uiStateJSON?: string; }; - -export type MapSavedObject = SimpleSavedObject; diff --git a/x-pack/plugins/maps/public/maps_vis_type_alias.ts b/x-pack/plugins/maps/public/maps_vis_type_alias.ts index 6d424955a5efe..911e886a8199e 100644 --- a/x-pack/plugins/maps/public/maps_vis_type_alias.ts +++ b/x-pack/plugins/maps/public/maps_vis_type_alias.ts @@ -7,8 +7,9 @@ import { i18n } from '@kbn/i18n'; import type { VisualizationsSetup, VisualizationStage } from '@kbn/visualizations-plugin/public'; +import type { SimpleSavedObject } from '@kbn/core/public'; import type { SavedObject } from '@kbn/core/types/saved_objects'; -import type { MapSavedObject } from '../common/map_saved_object_type'; +import type { MapSavedObjectAttributes } from '../common/map_saved_object_type'; import { APP_ID, APP_ICON, @@ -38,7 +39,8 @@ export function getMapsVisTypeAlias(visualizations: VisualizationsSetup) { docTypes: [MAP_SAVED_OBJECT_TYPE], searchFields: ['title^3'], toListItem(savedObject: SavedObject) { - const { id, type, updatedAt, attributes } = savedObject as MapSavedObject; + const { id, type, updatedAt, attributes } = + savedObject as SimpleSavedObject; const { title, description } = attributes; return { diff --git a/x-pack/plugins/maps/server/maps_telemetry/find_maps.ts b/x-pack/plugins/maps/server/maps_telemetry/find_maps.ts index cab4b98ffd784..213c1a6cde3ee 100644 --- a/x-pack/plugins/maps/server/maps_telemetry/find_maps.ts +++ b/x-pack/plugins/maps/server/maps_telemetry/find_maps.ts @@ -6,13 +6,13 @@ */ import { asyncForEach } from '@kbn/std'; -import { ISavedObjectsRepository } from '@kbn/core/server'; +import type { ISavedObjectsRepository, SavedObject } from '@kbn/core/server'; import { MAP_SAVED_OBJECT_TYPE } from '../../common/constants'; -import { MapSavedObject, MapSavedObjectAttributes } from '../../common/map_saved_object_type'; +import type { MapSavedObjectAttributes } from '../../common/map_saved_object_type'; export async function findMaps( savedObjectsClient: Pick, - callback: (savedObject: MapSavedObject) => Promise + callback: (savedObject: SavedObject) => Promise ) { let nextPage = 1; let hasMorePages = false; diff --git a/x-pack/plugins/maps/server/maps_telemetry/index_pattern_stats/index_pattern_stats_collector.ts b/x-pack/plugins/maps/server/maps_telemetry/index_pattern_stats/index_pattern_stats_collector.ts index ad1c0239963b4..dcbc9c884275d 100644 --- a/x-pack/plugins/maps/server/maps_telemetry/index_pattern_stats/index_pattern_stats_collector.ts +++ b/x-pack/plugins/maps/server/maps_telemetry/index_pattern_stats/index_pattern_stats_collector.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { SavedObject } from '@kbn/core/server'; import { asyncForEach } from '@kbn/std'; import { KBN_FIELD_TYPES } from '@kbn/field-types'; import { DataViewsService } from '@kbn/data-views-plugin/common'; @@ -15,7 +16,7 @@ import { ESSearchSourceDescriptor, LayerDescriptor, } from '../../../common/descriptor_types'; -import { MapSavedObject } from '../../../common/map_saved_object_type'; +import type { MapSavedObjectAttributes } from '../../../common/map_saved_object_type'; import { IndexPatternStats } from './types'; /* @@ -29,7 +30,7 @@ export class IndexPatternStatsCollector { this._indexPatternsService = indexPatternService; } - async push(savedObject: MapSavedObject) { + async push(savedObject: SavedObject) { let layerList: LayerDescriptor[] = []; try { const { attributes } = injectReferences(savedObject); From 19d0fb92467ee4fa64a926e4e201c14574a155c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Wed, 18 May 2022 11:22:19 +0200 Subject: [PATCH 14/18] Add missing EuiToolTip import --- .../kibana_react/public/table_list_view/table_list_view.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx index 948563984987a..ac617acc6c092 100644 --- a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx +++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx @@ -20,6 +20,7 @@ import { EuiSpacer, EuiTableActionsColumnType, SearchFilterConfig, + EuiToolTip, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage, FormattedRelative } from '@kbn/i18n-react'; From 3c225a4d21ba2e22919b51e9be2c79c6a31a169a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Wed, 18 May 2022 13:03:03 +0200 Subject: [PATCH 15/18] Update jest snapshot --- .../__snapshots__/table_list_view.test.tsx.snap | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/plugins/kibana_react/public/table_list_view/__snapshots__/table_list_view.test.tsx.snap b/src/plugins/kibana_react/public/table_list_view/__snapshots__/table_list_view.test.tsx.snap index 9cce39bad620d..2ad9af679e8c6 100644 --- a/src/plugins/kibana_react/public/table_list_view/__snapshots__/table_list_view.test.tsx.snap +++ b/src/plugins/kibana_react/public/table_list_view/__snapshots__/table_list_view.test.tsx.snap @@ -158,10 +158,7 @@ exports[`TableListView render list view 1`] = ` } sorting={ Object { - "sort": Object { - "direction": "asc", - "field": "", - }, + "sort": undefined, } } tableCaption="test caption" From a0fbd2e9033bf2d84062185e1d9be3f85f0ceb46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Wed, 18 May 2022 13:05:08 +0200 Subject: [PATCH 16/18] Fix jest test --- .../public/table_list_view/table_list_view.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx index 78435dd97e871..5ee2988a47acb 100644 --- a/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx +++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx @@ -193,8 +193,8 @@ describe('TableListView', () => { expect(tableCellsValues).toEqual([ // Renders the datetime with this format: "05/10/2022 @ 2:34 PM" - ['Item 1', 'Item 1 description', updatedAtValues[0].format('L @ LT')], - ['Item 2', 'Item 2 description', updatedAtValues[1].format('L @ LT')], + ['Item 1', 'Item 1 description', updatedAtValues[0].format('LL')], + ['Item 2', 'Item 2 description', updatedAtValues[1].format('LL')], ]); }); From 2dae9f0762911c1384eb9ff71bd196a7d718423a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Wed, 18 May 2022 14:59:34 +0200 Subject: [PATCH 17/18] Display dash "-" instead of blank space when no updatedAt value --- .../public/table_list_view/table_list_view.test.tsx | 2 +- .../public/table_list_view/table_list_view.tsx | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx index 5ee2988a47acb..ba76a6b879e61 100644 --- a/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx +++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx @@ -241,7 +241,7 @@ describe('TableListView', () => { expect(tableCellsValues).toEqual([ ['Item 2', 'Item 2 description', 'yesterday'], ['Item 1', 'Item 1 description', '2 days ago'], - ['Item 3', 'Item 3 description', ''], // Empty column as no updatedAt provided + ['Item 3', 'Item 3 description', '-'], // Empty column as no updatedAt provided ]); }); }); diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx index ac617acc6c092..78eddd0c529ea 100644 --- a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx +++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx @@ -520,7 +520,15 @@ class TableListView extends React.Component< if (this.state.hasUpdatedAtMetadata) { const renderUpdatedAt = (dateTime?: string) => { if (!dateTime) { - return ; + return ( + + - + + ); } const updatedAt = moment(dateTime); From 1bf0f802d8fb660248727924943343ae9270e822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Thu, 19 May 2022 17:12:34 +0200 Subject: [PATCH 18/18] Update copy for unknown updated_at --- .../kibana_react/public/table_list_view/table_list_view.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx index 78eddd0c529ea..5baaaa78b76ec 100644 --- a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx +++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx @@ -523,7 +523,7 @@ class TableListView extends React.Component< return ( -