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

[Content management] Add "Last updated" metadata to TableListView #132321

Merged
merged 21 commits into from
May 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
2107d57
Update TableListView table to render "updatedAt" metadata
sebelga May 17, 2022
90a7b69
Use i18n FormattedRelative instead of moment.fromNow()
sebelga May 17, 2022
13fd0f1
Dashboard: add updatedAt metadata to table items
sebelga May 17, 2022
53a0a94
Handle the case where one item does not have updatedAt metadata
sebelga May 17, 2022
ac816e5
Visualizations: add updatedAt metadata to table items
sebelga May 17, 2022
232ae40
[core] Fix case for "updatedAt" prop on SavedObject
sebelga May 17, 2022
8cbdfa9
Maps: add updatedAt metadata to table items
sebelga May 17, 2022
71ecd9b
Refactor TS typing
sebelga May 17, 2022
75272ca
Graph: add updatedAt metadata to table items
sebelga May 17, 2022
0042091
Revert "[core] Fix case for "updatedAt" prop on SavedObject"
sebelga May 17, 2022
88c203d
Fix TS types
sebelga May 17, 2022
aca69bf
Apply suggestions from Caroline code review
sebelga May 18, 2022
a7d1a53
Fix maps TS types
sebelga May 18, 2022
19d0fb9
Add missing EuiToolTip import
sebelga May 18, 2022
3c225a4
Update jest snapshot
sebelga May 18, 2022
a0fbd2e
Fix jest test
sebelga May 18, 2022
2dae9f0
Display dash "-" instead of blank space when no updatedAt value
sebelga May 18, 2022
e7655b9
Merge branch 'main' into content-management/surface-updated-at
sebelga May 18, 2022
22330ba
Merge branch 'main' into content-management/surface-updated-at
kibanamachine May 19, 2022
1bf0f80
Update copy for unknown updated_at
sebelga May 19, 2022
f0943f5
Merge remote-tracking branch 'upstream/main' into content-management/…
sebelga May 19, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions src/plugins/dashboard/public/services/saved_object_loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,16 @@ export class SavedObjectLoader {
mapHitSource(
source: Record<string, unknown>,
id: string,
references: SavedObjectReference[] = []
) {
source.id = id;
source.url = this.urlFor(id);
source.references = references;
return source;
references: SavedObjectReference[] = [],
updatedAt?: string
): Record<string, unknown> {
return {
...source,
id,
url: this.urlFor(id),
references,
updatedAt,
};
sebelga marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand All @@ -116,12 +120,14 @@ export class SavedObjectLoader {
attributes,
id,
references = [],
updatedAt,
}: {
attributes: Record<string, unknown>;
id: string;
references?: SavedObjectReference[];
updatedAt?: string;
}) {
return this.mapHitSource(attributes, id, references);
return this.mapHitSource(attributes, id, references, updatedAt);
}

/**
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,24 @@
*/

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 moment, { Moment } from 'moment';
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<Record<string, unknown>> = {
entityName: 'test',
entityNamePlural: 'tests',
listingLimit: 5,
Expand All @@ -30,6 +41,14 @@ const requiredProps = {
};

describe('TableListView', () => {
beforeAll(() => {
jest.useFakeTimers();
});

afterAll(() => {
jest.useRealTimers();
});

test('render default empty prompt', async () => {
const component = shallowWithIntl(<TableListView {...requiredProps} />);

Expand Down Expand Up @@ -81,4 +100,149 @@ describe('TableListView', () => {

expect(component).toMatchSnapshot();
});

describe('default columns', () => {
let testBed: TestBed;

const tableColumns = [
{
field: 'title',
name: 'Title',
sortable: true,
},
{
field: 'description',
name: 'Description',
sortable: true,
},
];

const twoDaysAgo = new Date(new Date().setDate(new Date().getDate() - 2));
const yesterday = new Date(new Date().setDate(new Date().getDate() - 1));

const hits = [
{
title: 'Item 1',
description: 'Item 1 description',
updatedAt: twoDaysAgo,
},
{
title: 'Item 2',
description: 'Item 2 description',
// This is the latest updated and should come first in the table
updatedAt: yesterday,
},
];

const findItems = jest.fn(() => Promise.resolve({ total: hits.length, hits }));

const defaultProps: TableListViewProps<Record<string, unknown>> = {
...requiredProps,
tableColumns,
findItems,
createItem: () => undefined,
};

const setup = registerTestBed(TableListView, { defaultProps });

test('should add a "Last updated" column if "updatedAt" is provided', async () => {
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', 'yesterday'], // Comes first as it is the latest updated
['Item 1', 'Item 1 description', '2 days ago'],
]);
});

test('should not display relative time for items updated more than 7 days ago', async () => {
const updatedAtValues: Moment[] = [];

const updatedHits = hits.map(({ title, description }, i) => {
const updatedAt = new Date(new Date().setDate(new Date().getDate() - (7 + i)));
updatedAtValues[i] = moment(updatedAt);

return {
title,
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([
// Renders the datetime with this format: "05/10/2022 @ 2:34 PM"
['Item 1', 'Item 1 description', updatedAtValues[0].format('LL')],
['Item 2', 'Item 2 description', updatedAtValues[1].format('LL')],
]);
});

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(({ title, description }) => ({ title, description })),
})
),
});
});

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'],
]);
});

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
]);
});
});
});
Loading