Skip to content

Commit

Permalink
[Content management] Surface "Last updated" column in Saved object ma…
Browse files Browse the repository at this point in the history
…nagement (#132525)
  • Loading branch information
sebelga authored May 20, 2022
1 parent 24bdc97 commit 8c19c36
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 10 deletions.

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

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 @@ -50,6 +50,10 @@ const defaultProps: TableProps = {
canGoInApp: () => true,
pageIndex: 1,
pageSize: 2,
sort: {
field: 'updated_at',
direction: 'desc',
},
items: [
{
id: '1',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import { ApplicationStart, IBasePath } from '@kbn/core/public';
import React, { PureComponent, Fragment } from 'react';
import moment from 'moment';
import {
EuiSearchBar,
EuiBasicTable,
Expand All @@ -24,9 +25,10 @@ import {
EuiTableFieldDataColumnType,
EuiTableActionsColumnType,
QueryType,
CriteriaWithPagination,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { FormattedMessage, FormattedRelative } from '@kbn/i18n-react';
import { SavedObjectsTaggingApi } from '@kbn/saved-objects-tagging-oss-plugin/public';
import type { SavedObjectManagementTypeInfo } from '../../../../common/types';
import { getDefaultTitle, getSavedObjectLabel } from '../../../lib';
Expand Down Expand Up @@ -55,6 +57,7 @@ export interface TableProps {
goInspectObject: (obj: SavedObjectWithMetadata) => void;
pageIndex: number;
pageSize: number;
sort: CriteriaWithPagination<SavedObjectWithMetadata>['sort'];
items: SavedObjectWithMetadata[];
itemId: string | (() => string);
totalItemCount: number;
Expand Down Expand Up @@ -128,10 +131,59 @@ export class Table extends PureComponent<TableProps, TableState> {
this.setState({ isExportPopoverOpen: false });
};

getUpdatedAtColumn = () => {
const renderUpdatedAt = (dateTime?: string) => {
if (!dateTime) {
return (
<EuiToolTip
content={i18n.translate(
'savedObjectsManagement.objectsTable.table.updatedDateUnknownLabel',
{
defaultMessage: 'Last updated unknown',
}
)}
>
<span>-</span>
</EuiToolTip>
);
}
const updatedAt = moment(dateTime);

if (updatedAt.diff(moment(), 'days') > -7) {
return (
<FormattedRelative value={new Date(dateTime).getTime()}>
{(formattedDate: string) => (
<EuiToolTip content={updatedAt.format('LL LT')}>
<span>{formattedDate}</span>
</EuiToolTip>
)}
</FormattedRelative>
);
}
return (
<EuiToolTip content={updatedAt.format('LL LT')}>
<span>{updatedAt.format('LL')}</span>
</EuiToolTip>
);
};

return {
field: 'updated_at',
name: i18n.translate('savedObjectsManagement.objectsTable.table.lastUpdatedColumnTitle', {
defaultMessage: 'Last updated',
}),
render: (field: string, record: { updated_at?: string }) =>
renderUpdatedAt(record.updated_at),
sortable: true,
width: '150px',
};
};

render() {
const {
pageIndex,
pageSize,
sort,
itemId,
items,
totalItemCount,
Expand Down Expand Up @@ -186,7 +238,7 @@ export class Table extends PureComponent<TableProps, TableState> {
'savedObjectsManagement.objectsTable.table.columnTypeDescription',
{ defaultMessage: 'Type of the saved object' }
),
sortable: false,
sortable: true,
'data-test-subj': 'savedObjectsTableRowType',
render: (type: string, object: SavedObjectWithMetadata) => {
const typeLabel = getSavedObjectLabel(type, allowedTypes);
Expand Down Expand Up @@ -239,6 +291,7 @@ export class Table extends PureComponent<TableProps, TableState> {
'data-test-subj': `savedObjectsTableColumn-${column.id}`,
};
}),
this.getUpdatedAtColumn(),
{
name: i18n.translate('savedObjectsManagement.objectsTable.table.columnActionsName', {
defaultMessage: 'Actions',
Expand Down Expand Up @@ -422,6 +475,7 @@ export class Table extends PureComponent<TableProps, TableState> {
items={items}
columns={columns as any}
pagination={pagination}
sorting={{ sort }}
selection={selection}
onChange={onTableChange}
rowProps={(item) => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import React, { Component } from 'react';
import { debounce } from 'lodash';
// @ts-expect-error
import { saveAs } from '@elastic/filesaver';
import { EuiSpacer, Query } from '@elastic/eui';
import { EuiSpacer, Query, CriteriaWithPagination } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import {
SavedObjectsClientContract,
Expand Down Expand Up @@ -78,6 +78,7 @@ export interface SavedObjectsTableState {
totalCount: number;
page: number;
perPage: number;
sort: CriteriaWithPagination<SavedObjectWithMetadata>['sort'];
savedObjects: SavedObjectWithMetadata[];
savedObjectCounts: Record<string, number>;
activeQuery: Query;
Expand Down Expand Up @@ -114,6 +115,10 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
totalCount: 0,
page: 0,
perPage: props.perPageConfig || 50,
sort: {
field: 'updated_at',
direction: 'desc',
},
savedObjects: [],
savedObjectCounts: props.allowedTypes.reduce((typeToCountMap, type) => {
typeToCountMap[type.name] = 0;
Expand Down Expand Up @@ -211,7 +216,7 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
};

debouncedFindObjects = debounce(async () => {
const { activeQuery: query, page, perPage } = this.state;
const { activeQuery: query, page, perPage, sort } = this.state;
const { notifications, http, allowedTypes, taggingApi } = this.props;
const { queryText, visibleTypes, selectedTags } = parseQuery(query, allowedTypes);

Expand All @@ -228,9 +233,8 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
fields: ['id'],
type: searchTypes,
};
if (findOptions.type.length > 1) {
findOptions.sortField = 'type';
}
findOptions.sortField = sort?.field;
findOptions.sortOrder = sort?.direction;

findOptions.hasReference = getTagFindReferences({ selectedTags, taggingApi });

Expand Down Expand Up @@ -352,14 +356,15 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
);
};

onTableChange = async (table: any) => {
onTableChange = async (table: CriteriaWithPagination<SavedObjectWithMetadata>) => {
const { index: page, size: perPage } = table.page || {};

this.setState(
{
page,
perPage,
selectedSavedObjects: [],
sort: table.sort,
},
this.fetchAllSavedObjects
);
Expand Down Expand Up @@ -653,6 +658,7 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
filteredItemCount,
isSearching,
savedObjectCounts,
sort,
} = this.state;
const { http, taggingApi, allowedTypes, applications } = this.props;

Expand Down Expand Up @@ -700,6 +706,7 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
goInspectObject={this.props.goInspectObject}
pageIndex={page}
pageSize={perPage}
sort={sort}
items={savedObjects}
totalItemCount={filteredItemCount}
isSearching={isSearching}
Expand Down
1 change: 1 addition & 0 deletions src/plugins/saved_objects_management/server/routes/find.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const registerFindRoute = (
search: schema.maybe(schema.string()),
defaultSearchOperator: searchOperatorSchema,
sortField: schema.maybe(schema.string()),
sortOrder: schema.maybe(schema.oneOf([schema.literal('asc'), schema.literal('desc')])),
hasReference: schema.maybe(
schema.oneOf([referenceSchema, schema.arrayOf(referenceSchema)])
),
Expand Down
33 changes: 33 additions & 0 deletions test/api_integration/apis/saved_objects_management/find.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,39 @@ export default function ({ getService }: FtrProviderContext) {
});
});
});

describe('`sortField` and `sortOrder` parameters', () => {
it('sort objects by "type" in "asc" order', async () => {
await supertest
.get('/api/kibana/management/saved_objects/_find')
.query({
type: ['visualization', 'dashboard'],
sortField: 'type',
sortOrder: 'asc',
})
.expect(200)
.then((resp) => {
const objects = resp.body.saved_objects;
expect(objects.length).be.greaterThan(1); // Need more than 1 result for our test
expect(objects[0].type).to.be('dashboard');
});
});

it('sort objects by "type" in "desc" order', async () => {
await supertest
.get('/api/kibana/management/saved_objects/_find')
.query({
type: ['visualization', 'dashboard'],
sortField: 'type',
sortOrder: 'desc',
})
.expect(200)
.then((resp) => {
const objects = resp.body.saved_objects;
expect(objects[0].type).to.be('visualization');
});
});
});
});

describe('meta attributes injected properly', () => {
Expand Down

0 comments on commit 8c19c36

Please sign in to comment.