From 8781d75d10c21f2926a0491649f4dee10be3233d Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Fri, 9 Mar 2018 16:48:29 -0800 Subject: [PATCH] Remove EuiTableOfRecords. (#490) --- CHANGELOG.md | 8 +- src-docs/src/routes.js | 4 - .../table_of_records/column_data_types.js | 56 - .../views/table_of_records/full_featured.js | 334 --- .../implicit_record_action.js | 166 -- .../src/views/table_of_records/props_info.js | 369 ---- .../table_of_records_example.js | 183 -- src/components/index.js | 4 - .../collapsed_record_actions.test.js.snap | 40 - .../custom_record_action.test.js.snap | 11 - .../default_record_action.test.js.snap | 42 - .../expanded_record_actions.test.js.snap | 72 - .../__snapshots__/pagination_bar.test.js.snap | 45 - .../table_of_records.test.js.snap | 1879 ----------------- src/components/table_of_records/_index.scss | 1 - .../table_of_records/_table_of_records.scss | 3 - .../collapsed_record_actions.js | 108 - .../collapsed_record_actions.test.js | 51 - .../table_of_records/custom_record_action.js | 54 - .../custom_record_action.test.js | 40 - .../table_of_records/default_record_action.js | 111 - .../default_record_action.test.js | 79 - .../expanded_record_actions.js | 44 - .../expanded_record_actions.test.js | 50 - src/components/table_of_records/index.js | 3 - .../table_of_records/pagination_bar.js | 37 - .../table_of_records/pagination_bar.test.js | 90 - .../table_of_records.behavior.test.js | 67 - .../table_of_records/table_of_records.js | 579 ----- .../table_of_records/table_of_records.test.js | 548 ----- 30 files changed, 6 insertions(+), 5072 deletions(-) delete mode 100644 src-docs/src/views/table_of_records/column_data_types.js delete mode 100644 src-docs/src/views/table_of_records/full_featured.js delete mode 100644 src-docs/src/views/table_of_records/implicit_record_action.js delete mode 100644 src-docs/src/views/table_of_records/props_info.js delete mode 100644 src-docs/src/views/table_of_records/table_of_records_example.js delete mode 100644 src/components/table_of_records/__snapshots__/collapsed_record_actions.test.js.snap delete mode 100644 src/components/table_of_records/__snapshots__/custom_record_action.test.js.snap delete mode 100644 src/components/table_of_records/__snapshots__/default_record_action.test.js.snap delete mode 100644 src/components/table_of_records/__snapshots__/expanded_record_actions.test.js.snap delete mode 100644 src/components/table_of_records/__snapshots__/pagination_bar.test.js.snap delete mode 100644 src/components/table_of_records/__snapshots__/table_of_records.test.js.snap delete mode 100644 src/components/table_of_records/_index.scss delete mode 100644 src/components/table_of_records/_table_of_records.scss delete mode 100644 src/components/table_of_records/collapsed_record_actions.js delete mode 100644 src/components/table_of_records/collapsed_record_actions.test.js delete mode 100644 src/components/table_of_records/custom_record_action.js delete mode 100644 src/components/table_of_records/custom_record_action.test.js delete mode 100644 src/components/table_of_records/default_record_action.js delete mode 100644 src/components/table_of_records/default_record_action.test.js delete mode 100644 src/components/table_of_records/expanded_record_actions.js delete mode 100644 src/components/table_of_records/expanded_record_actions.test.js delete mode 100644 src/components/table_of_records/index.js delete mode 100644 src/components/table_of_records/pagination_bar.js delete mode 100644 src/components/table_of_records/pagination_bar.test.js delete mode 100644 src/components/table_of_records/table_of_records.behavior.test.js delete mode 100644 src/components/table_of_records/table_of_records.js delete mode 100644 src/components/table_of_records/table_of_records.test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 30c7bb3adee..657aa42ff65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ - `EuiBottomBar` now uses `EuiPortal` to avoid zindex conflicts ([#487](https://github.com/elastic/eui/pull/487)) - Upped dark theme contrast on disabled buttons ([#487](https://github.com/elastic/eui/pull/487)) +**Breaking changes** + +- Removed `EuiTableOfRecords` ([#490](https://github.com/elastic/eui/pull/490)) + # [`0.0.25`](https://github.com/elastic/eui/tree/v0.0.25) - `EuiSearchBar` accepts `toolsLeft` and `toolsRight` props ([#458](https://github.com/elastic/eui/pull/458)) @@ -95,7 +99,7 @@ **Bug fixes** -- **Note: This is deprecated in 0.0.21.** `EuiTableOfRecords` selection bugs ([#365](https://github.com/elastic/eui/pull/365)) +- **Note: This is deprecated in 0.0.21 and removed in 0.0.26.** `EuiTableOfRecords` selection bugs ([#365](https://github.com/elastic/eui/pull/365)) - Deleting selected items now resets the select all checkbox to an unchecked state - The select all checkbox only becomes checked when all selectable rows are checked, not just some of them @@ -119,7 +123,7 @@ - `EuiRadio` now supports the `input` tag's `name` attribute. `EuiRadioGroup` accepts a `name` prop that will propagate to its `EuiRadio`s. ([#348](https://github.com/elastic/eui/pull/348)) - Added Machine Learning create jobs icon set. ([#338](https://github.com/elastic/eui/pull/338)) -- **Note: This is deprecated in 0.0.21.** Added `EuiTableOfRecords`, a higher level table component to take away all your table listings frustrations. ([#250](https://github.com/elastic/eui/pull/250)) +- **Note: This is deprecated in 0.0.21 and removed in 0.0.26.** Added `EuiTableOfRecords`, a higher level table component to take away all your table listings frustrations. ([#250](https://github.com/elastic/eui/pull/250)) **Bug fixes** diff --git a/src-docs/src/routes.js b/src-docs/src/routes.js index 6821a96199e..5dfca92640b 100644 --- a/src-docs/src/routes.js +++ b/src-docs/src/routes.js @@ -164,9 +164,6 @@ import { StepsExample } import { TableExample } from './views/tables/tables_example'; -import { TableOfRecordsExample } - from './views/table_of_records/table_of_records_example'; - import { TabsExample } from './views/tabs/tabs_example'; @@ -281,7 +278,6 @@ const navigation = [{ LoadingExample, ProgressExample, TableExample, - TableOfRecordsExample, TextExample, TitleExample, ToastExample, diff --git a/src-docs/src/views/table_of_records/column_data_types.js b/src-docs/src/views/table_of_records/column_data_types.js deleted file mode 100644 index 7a4ae897779..00000000000 --- a/src-docs/src/views/table_of_records/column_data_types.js +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react'; -import { times } from 'lodash'; - -import { - Random -} from '../../../../src/services'; - -import { - EuiTableOfRecords, -} from '../../../../src/components'; - -const random = new Random(); - -const records = times(5, (index) => { - return { - id: index, - string: random.oneOf(['Martijn', 'Elissa', 'Clinton', 'Igor', 'Karl', 'Drew', 'Honza', 'Rashid', 'Jordan']), - number: random.integer({ min: 0, max: 2000000 }), - boolean: random.boolean(), - date: random.date({ min: new Date(1971, 0, 0), max: new Date(1990, 0, 0) }) - }; -}); - -const model = { - data: { records } -}; - -const config = { - recordId: 'id', - columns: [ - { - field: 'string', - name: 'string', - dataType: 'string', - }, - { - field: 'number', - name: 'number', - dataType: 'number' - }, - { - field: 'boolean', - name: 'boolean', - dataType: 'boolean' - }, - { - field: 'date', - name: 'date', - dataType: 'date' - }, - ], -}; - -export default () => { - return ; -}; diff --git a/src-docs/src/views/table_of_records/full_featured.js b/src-docs/src/views/table_of_records/full_featured.js deleted file mode 100644 index f9830daa9e2..00000000000 --- a/src-docs/src/views/table_of_records/full_featured.js +++ /dev/null @@ -1,334 +0,0 @@ -import React, { - Component, -} from 'react'; -import uuid from 'uuid/v1'; -import { times } from 'lodash'; - -import { - EuiButton, - EuiTableOfRecords, - EuiHealth, - EuiSwitch, - EuiFlexGroup, - EuiFlexItem, - EuiLink, - EuiSpacer, -} from '../../../../src/components'; - -import { - formatDate, - Random, - Comparators -} from '../../../../src/services'; - -const random = new Random(); - -const people = times(20, (index) => { - return { - id: index, - firstName: random.oneOf(['Martijn', 'Elissa', 'Clinton', 'Igor', 'Karl', 'Drew', 'Honza', 'Rashid', 'Jordan']), - lastName: random.oneOf(['van Groningen', 'Weve', 'Gormley', 'Motov', 'Minarik', 'Raines', 'Král', 'Khan', 'Sissel']), - nickname: random.oneOf(['martijnvg', 'elissaw', 'clintongormley', 'imotov', 'karmi', 'drewr', 'HonzaKral', 'rashidkpc', 'whack']), - dateOfBirth: random.date({ min: new Date(1971, 0, 0), max: new Date(1990, 0, 0) }), - country: random.oneOf(['us', 'nl', 'cz', 'za', 'au']), - online: random.boolean() - }; -}); - -function loadPage(pageIndex, pageSize, sort) { - let list = people; - if (sort) { - list = people.sort(Comparators.property(sort.field, Comparators.default(sort.direction))); - } - if (!pageIndex && !pageSize) { - return { - index: 0, - size: list.length, - items: list, - totalRecordCount: list.length - }; - } - const from = pageIndex * pageSize; - const items = list.slice(from, Math.min(from + pageSize, list.length)); - return { - index: pageIndex, - size: pageSize, - items, - totalRecordCount: list.length - }; -} - -export default class PeopleTable extends Component { - constructor(props) { - super(props); - - this.state = { - selectedIds: [], - features: { - pagination: true, - sorting: true, - selection: true, - multipleRecordActions: true - }, - ...this.computeTableState({ - page: { - index: 0, - size: 5, - }, - }) - }; - } - - computeTableState(criteria) { - const page = criteria.page ? - loadPage(criteria.page.index, criteria.page.size, criteria.sort) : - loadPage(undefined, undefined, criteria.sort); - return { - data: { - records: page.items, - totalRecordCount: page.totalRecordCount - }, - criteria: { - page: { - index: page.index, - size: page.size - }, - sort: criteria.sort - } - }; - } - - onSelectionChanged = selection => { - const selectedIds = selection.map(item => item.id); - this.setState({ - selectedIds, - }); - }; - - onDataCriteriaChange(criteria) { - this.setState(this.computeTableState(criteria)); - } - - deletePerson(personToDelete) { - const i = people.findIndex((person) => person.id === personToDelete.id); - if (i !== -1) { - people.splice(i, 1); - } - this.onDataCriteriaChange(this.state.criteria); - } - - deleteSelectedPeople = () => { - this.state.selectedIds.forEach(id => { - const i = people.findIndex((person) => person.id === id); - if (i !== -1) { - people.splice(i, 1); - } - }); - this.onDataCriteriaChange(this.state.criteria); - }; - - clonePerson(personToClone) { - const i = people.findIndex((person) => person.id === personToClone.id); - const clone = { ...personToClone, id: uuid() }; - people.splice(i, 0, clone); - this.onDataCriteriaChange(this.state.criteria); - } - - changePersonOnlineStatus(personToUpdate, online) { - const person = people.find((person) => person.id === personToUpdate.id); - if (person) { - person.online = online; - } - this.onDataCriteriaChange(this.state.criteria); - } - - toggleFeature(feature) { - this.setState(prevState => ({ - features: { - ...prevState.features, - [feature]: !prevState.features[feature] - } - })); - } - - render() { - const { features } = this.state; - - const config = { - recordId: 'id', - columns: [ - { - field: 'firstName', - name: 'First Name', - description: `Person's given name`, - dataType: 'string', - sortable: features.sorting, - }, - { - field: 'lastName', - name: 'Last Name', - description: `Person's family name`, - dataType: 'string' - }, - { - field: 'nickname', - name: 'Nickname', - description: `Person's nickname / online handle`, - render: value => ( - - {value} - - ) - }, - { - field: 'dateOfBirth', - name: 'Date of Birth', - description: `Person's date of birth`, - render: value => formatDate(value, 'D MMM YYYY'), - sortable: features.sorting, - dataType: 'date' - }, - { - field: 'online', - name: 'Online', - description: `Is this person currently online?`, - render: (value) => { - const color = value ? 'success' : 'danger'; - const content = value ? 'Online' : 'Offline'; - return {content}; - }, - sortable: features.sorting - }, - { - name: '', - actions: features.multipleRecordActions ? [ - { - name: 'Clone', - description: 'Clone this person', - icon: 'copy', - onClick: (person) => this.clonePerson(person) - }, - { - name: 'Delete', - description: 'Delete this person', - icon: 'trash', - color: 'danger', - onClick: (person) => this.deletePerson(person) - }, - // uncomment once context menu officially supports checkbox elements - // see https://github.com/elastic/eui/issues/336 - // { - // name: 'Online/Offline', - // description: 'toggles the online/offline state of the person', - // render: (person, model, enabled) => { - // const onChange = (event) => this.changePersonOnlineStatus(person, event.target.checked); - // return ( - // - // ); - // } - // } - ] : [ - { - name: 'Delete', - description: 'Delete this person', - icon: 'trash', - type: 'icon', - color: 'danger', - onClick: (person) => this.deletePerson(person) - } - ] - } - ], - - pagination: features.pagination ? { - pageSizeOptions: [3, 5, 8] - } : undefined, - - selection: features.selection ? { - selectable: (record) => record.online, - selectableMessage: person => !person.online ? `${person.firstName} is offline` : undefined, - onSelectionChanged: this.onSelectionChanged, - } : undefined, - - onDataCriteriaChange: (criteria) => this.onDataCriteriaChange(criteria) - }; - - const { - selectedIds, - data, - criteria: { - page, - sort, - }, - } = this.state; - - const model = { - data, - criteria: { - page: features.pagination ? page : undefined, - sort: features.sorting ? sort : undefined, - }, - }; - - let deleteButton; - - if (selectedIds.length) { - const label = selectedIds.length > 1 ? `Delete ${selectedIds.length} people` : `Delete 1 person`; - deleteButton = ( - - - {label} - - - ); - } - - return ( -
- - { deleteButton } - - - - - - - - - - - - - - - - - -
- ); - } -} diff --git a/src-docs/src/views/table_of_records/implicit_record_action.js b/src-docs/src/views/table_of_records/implicit_record_action.js deleted file mode 100644 index bc4d0fe1202..00000000000 --- a/src-docs/src/views/table_of_records/implicit_record_action.js +++ /dev/null @@ -1,166 +0,0 @@ -import React, { Component } from 'react'; -import { times } from 'lodash'; - -import { - EuiTableOfRecords, - EuiSwitch, - EuiIcon, - EuiLink, -} from '../../../../src/components'; - -import { - formatDate, - Random, - Comparators -} from '../../../../src/services'; - -const random = new Random(); - -const people = times(20, (index) => { - return { - id: index, - firstName: random.oneOf(['Martijn', 'Elissa', 'Clinton', 'Igor', 'Karl', 'Drew', 'Honza', 'Rashid', 'Jordan']), - lastName: random.oneOf(['van Groningen', 'Weve', 'Gormley', 'Motov', 'Minarik', 'Raines', 'Král', 'Khan', 'Sissel']), - nickname: random.oneOf(['martijnvg', 'elissaw', 'clintongormley', 'imotov', 'karmi', 'drewr', 'HonzaKral', 'rashidkpc', 'whack']), - dateOfBirth: random.date({ min: new Date(1971, 0, 0), max: new Date(1990, 0, 0) }), - country: random.oneOf(['us', 'nl', 'cz', 'za', 'au']), - online: random.boolean() - }; -}); - -function loadPage(pageIndex, pageSize, sort) { - let list = people; - if (sort) { - list = people.sort(Comparators.property(sort.field, Comparators.default(sort.direction))); - } - const from = pageIndex * pageSize; - const items = list.slice(from, Math.min(from + pageSize, list.length)); - return { - index: pageIndex, - size: pageSize, - items, - totalRecordCount: list.length - }; -} - -export default class PeopleTable extends Component { - - constructor(props) { - super(props); - this.state = this.computeState({ - page: { - index: 0, - size: 5 - } - }); - } - - computeState(criteria, selection = []) { - const page = loadPage(criteria.page.index, criteria.page.size, criteria.sort); - return { - data: { - records: page.items, - totalRecordCount: page.totalRecordCount - }, - criteria: { - page: { - index: page.index, - size: page.size - }, - sort: criteria.sort - }, - selection - }; - } - - onDataCriteriaChange(criteria) { - this.setState((prevState) => this.computeState(criteria, prevState.selection)); - } - - onPersonOnlineStatusChange(personId, online) { - const person = people.find(person => person.id === personId); - if (person) { - person.online = online; - } - this.onDataCriteriaChange(this.state.criteria); - } - - onSelectionChanged(selection) { - this.setState({ selection }); - } - - render() { - - const config = { - recordId: 'id', - columns: [ - { - width: '30px', - align: 'right', - render: (person) => { - const color = person.online ? 'success' : 'subdued'; - const title = person.online ? 'Online' : 'Offline'; - return ; - } - }, - { - field: 'firstName', - name: 'First Name', - description: `Person's given name`, - dataType: 'string', - sortable: true - }, - { - field: 'lastName', - name: 'Last Name', - description: `Person's family name`, - dataType: 'string' - }, - { - field: 'nickname', - name: 'Nickname', - description: `Person's nickname / online handle`, - render: value => ( - - {value} - - ) - }, - { - field: 'dateOfBirth', - name: 'Date of Birth', - description: `Person's date of birth`, - render: value => formatDate(value, 'D MMM YYYY'), - sortable: true - }, - { - field: 'online', - name: 'Online', - description: `Is this person is currently online?`, - render: (online, person) => { - const disabled = this.state.selection.length !== 0; - const onChange = (event) => { - this.onPersonOnlineStatusChange(person.id, event.target.checked); - }; - return ; - }, - sortable: true - } - ], - pagination: { - pageSizeOptions: [3, 5, 8] - }, - - selection: { - selectable: (record) => record.online, - selectableMessage: person => !person.online ? `${person.firstName} is offline` : undefined, - onSelectionChanged: (selection) => this.onSelectionChanged(selection) - }, - - onDataCriteriaChange: (criteria) => this.onDataCriteriaChange(criteria, this.state.selection) - - }; - - return ; - } -} diff --git a/src-docs/src/views/table_of_records/props_info.js b/src-docs/src/views/table_of_records/props_info.js deleted file mode 100644 index 86bae89994d..00000000000 --- a/src-docs/src/views/table_of_records/props_info.js +++ /dev/null @@ -1,369 +0,0 @@ -export const propsInfo = { - - EuiTableOfRecords: { - __docgenInfo: { - props: { - config: { - description: 'Configures the features and behaviour of the table', - required: true, - type: { name: '#Config' } - }, - model: { - description: 'Defines the data model of this table', - required: true, - type: { name: '#Model' } - } - } - } - }, - - Model: { - __docgenInfo: { - _euiObjectType: 'type', - props: { - data: { - description: 'Holds the data for the table', - required: true, - type: { name: '#ModelData' } - }, - criteria: { - description: 'Defines the criteria to which the data adheres', - required: false, - type: { name: '#ModelCriteria' } - } - } - } - }, - - - ModelData: { - __docgenInfo: { - _euiObjectType: 'type', - props: { - records: { - description: 'An array of the records to be displayed', - required: true, - type: { name: 'object[]' } - }, - totalRecordCount: { - description: 'The total number of records that match the criteria', - required: false, - type: { name: 'number' } - } - } - } - }, - - ModelCriteria: { - __docgenInfo: { - _euiObjectType: 'type', - props: { - page: { - description: 'If the data records represents a page into a bigger set, this describes this page', - required: false, - type: { name: '#ModelCriteriaPage' } - }, - sort: { - description: 'If the data records are sorted, this describes the sort criteria', - required: false, - type: { name: '#ModelCriteriaSort' } - } - } - } - }, - - ModelCriteriaPage: { - __docgenInfo: { - _euiObjectType: 'type', - props: { - size: { - description: 'The maximum number of records per page', - required: true, - type: { name: 'number' } - }, - index: { - description: 'The page (zero-based) index', - required: false, - type: { name: 'number' } - } - } - } - }, - - ModelCriteriaSort: { - __docgenInfo: { - _euiObjectType: 'type', - props: { - field: { - description: 'The field the data is sorted on', - required: true, - type: { name: 'string' } - }, - direction: { - description: 'The direction of the sort', - required: false, - type: { name: '"asc" | "desc"' } - } - } - } - }, - - Config: { - __docgenInfo: { - _euiObjectType: 'type', - props: { - columns: { - description: 'Defines the table columns', - required: true, - type: { name: '(#FieldDataColumn | #ComputedColumn | #ActionsColumn)[]' } - }, - onDataCriteriaChange: { - description: 'A callback to handle changes in the data criteria', - required: false, - type: { name: '(criteria: #ModelCriteria) => void' } - }, - selection: { - description: 'Configuring selection', - required: false, - type: { name: '#ConfigSelection' } - }, - pagination: { - description: 'Configuring pagination', - required: false, - type: { name: '#ConfigPagination' } - } - } - } - }, - - ConfigSelection: { - __docgenInfo: { - _euiObjectType: 'type', - props: { - onSelectionChanged: { - description: 'A callback that will be called whenever the record selection changes', - required: false, - type: { name: '(selectedRecords) => void' } - }, - selectable: { - description: 'A callback that is called per record to indicate whether it is selectable', - required: false, - type: { name: '(record, model) => void' } - } - } - } - }, - - ConfigPagination: { - __docgenInfo: { - _euiObjectType: 'type', - props: { - pageSizeOptions: { - description: 'Configures the page size dropdown options', - required: false, - defaultValue: { value: '[5, 10, 20]' }, - type: { name: 'number[]' } - } - } - } - }, - - FieldDataColumn: { - __docgenInfo: { - _euiObjectType: 'type', - description: `Describes a column that displays a value derived of one of the Record's fields`, - props: { - field: { - description: 'A field of the record (may be a nested field)', - required: true, - type: { name: 'string' } - }, - name: { - description: 'The display name of the column', - required: true, - type: { name: 'string' } - }, - description: { - description: 'A description of the column (will be presented as a title over the column header', - required: false, - type: { name: 'string' } - }, - dataType: { - description: 'Describes the data types of the displayed value (serves as a rendering hint for the table)', - required: false, - defaultValue: { value: '"auto"' }, - type: { name: '"auto" | string" | "number" | "date" | "boolean"' } - }, - width: { - description: 'A CSS width property. Hints for the required width of the column', - required: false, - type: { name: 'string (e.g. "30%", "100px", etc..)' } - }, - sortable: { - description: 'Defines whether the user can sort on this column', - required: false, - defaultValue: { value: 'false' }, - type: { name: 'boolean' } - }, - align: { - description: 'Defines the horizontal alignment of the column', - required: false, - defaultValue: { value: '"right"', comment: 'May change when "dataType" is defined' }, - type: { name: '"left" | "right"' } - }, - truncateText: { - description: `Indicates whether this column should truncate its content when it doesn't fit`, - required: false, - defaultValue: { value: 'false' }, - type: { name: 'boolean' } - }, - render: { - description: `Describe a custom renderer function for the content`, - required: false, - type: { name: '(value, record) => PropTypes.node' } - } - } - } - }, - - ComputedColumn: { - __docgenInfo: { - _euiObjectType: 'type', - description: `Describes a column for computed values`, - props: { - render: { - description: `A function that computes the value for each record and renders it`, - required: true, - type: { name: '(record, model) => PropTypes.node' } - }, - name: { - description: 'The display name of the column', - required: false, - type: { name: 'string' } - }, - description: { - description: 'A description of the column (will be presented as a title over the column header', - required: false, - type: { name: 'string' } - }, - width: { - description: 'A CSS width property. Hints for the required width of the column', - required: false, - type: { name: 'string (e.g. "30%", "100px", etc..)' } - }, - truncateText: { - description: `Indicates whether this column should truncate its content when it doesn't fit`, - required: false, - defaultValue: { value: 'false' }, - type: { name: 'boolean' } - } - } - } - }, - - ActionsColumn: { - __docgenInfo: { - _euiObjectType: 'type', - description: `Describes a column that holds action controls (e.g. Buttons)`, - props: { - actions: { - description: `An array of actions to associate per record`, - required: true, - type: { name: '(#DefaultRecordAction | #CustomRecordAction)[]' } - }, - name: { - description: 'The display name of the column', - required: false, - type: { name: 'string' } - }, - description: { - description: 'A description of the column (will be presented as a title over the column header', - required: false, - type: { name: 'string' } - }, - width: { - description: 'A CSS width property. Hints for the required width of the column', - required: false, - type: { name: 'string (e.g. "30%", "100px", etc..)' } - } - } - } - }, - - DefaultRecordAction: { - __docgenInfo: { - _euiObjectType: 'type', - description: `Describes an action that is displayed as a button`, - props: { - name: { - description: 'The display name of the action (will be the button caption', - required: true, - type: { name: 'string' } - }, - description: { - description: 'Describes the action (will be the button title)', - required: true, - type: { name: 'string' } - }, - onClick: { - description: 'A handler function to execute the action', - required: true, - type: { name: '(record, model) => void' } - }, - type: { - description: 'The type of action', - required: false, - defaultValue: { value: '"button"' }, - type: { name: '"button" | "icon"' } - }, - available: { - description: 'A callback function that determines whether the action is available', - required: false, - defaultValue: { value: '() => true' }, - type: { name: '(record, model) => boolean' } - }, - enabled: { - description: 'A callback function that determines whether the action is enabled', - required: false, - defaultValue: { value: '() => true' }, - type: { name: '(record, model) => boolean' } - }, - icon: { - description: 'Associates an icon with the button', - required: false, - type: { name: 'string (must be one of the supported icon types)' } - }, - color: { - description: 'Defines the color of the button', - required: false, - type: { name: 'string (must be one of the supported button colors)' } - } - } - } - }, - - CustomRecordAction: { - __docgenInfo: { - _euiObjectType: 'type', - description: `Describes a custom action`, - props: { - render: { - description: 'The function that renders the action. Note that the returned node is ' + - 'expected to have`onFocus` and `onBlur` functions', - required: true, - type: { name: '(record, model, enabled) => PropTypes.node' } - }, - available: { - description: 'A callback that defines whether the action is available', - required: false, - type: { name: '(record, model) => boolean' } - }, - enabled: { - description: 'A callback that defines whether the action is enabled', - required: false, - type: { name: '(record, model) => boolean' } - } - } - } - }, -}; diff --git a/src-docs/src/views/table_of_records/table_of_records_example.js b/src-docs/src/views/table_of_records/table_of_records_example.js deleted file mode 100644 index c9b2abbd4a1..00000000000 --- a/src-docs/src/views/table_of_records/table_of_records_example.js +++ /dev/null @@ -1,183 +0,0 @@ -import React from 'react'; -import { Link } from 'react-router'; - -import { renderToHtml } from '../../services'; - -import { - GuideSectionTypes, -} from '../../components'; - -import { - EuiCode, EuiText, EuiTitle, EuiCallOut, EuiSpacer -} from '../../../../src/components'; - -import FullFeatured from './full_featured'; -const fullFeaturedSource = require('!!raw-loader!./full_featured'); -const fullFeaturedHtml = renderToHtml(FullFeatured); - -import ImplicitRecordActionsTable from './implicit_record_action'; -const implicitRecordActionSource = require('!!raw-loader!./implicit_record_action'); -const implicitRecordActionHtml = renderToHtml(ImplicitRecordActionsTable); - -import ColumnDataTypes from './column_data_types'; -import { propsInfo } from './props_info'; -const columnRenderersSource = require('!!raw-loader!./column_data_types'); -const columnRenderersHtml = renderToHtml(ColumnDataTypes); - -export const TableOfRecordsExample = { - title: 'Table Of Records', - intro: ( - - - EuiTableOfRecords should no longer be used. Instead, use - the EuiBasicTable as documented here. We plan - to remove this component from EUI fairly soon. - - -

TableOfRecords

-
-

- EuiTableOfRecords is a high level component that aims to simplify and unifiy the way - one creates a table of... (wait for it....) records!!! -

- - The goal of a high level components is to make the consumer not think about design or UX/UI behaviour. - Instead, the consumer only need to define the functional requirements - features of the component (in - this case, table), the data, and the type of interaction the user should have with it. Through high level - components, Eui can promote best/common UI practices and patterns. - - High level components are as stateless as they can possibly be. Meaning, all the management of the data - (e.g. where is it coming from, how is it loaded, how is it filtered, etc...) is expected to be done - externally to this component. Typically one would use a container component to wrap around this component - that will either manage this state internally, or use other state stores (e.g. such as Redux). - - - - Think of a record in a data store - typically it represents an entity with a very clear - schema and is something that can be presented in a tabular form. - - -

- The EuiTableOfRecords accepts two required properties: -

-
    -
  • - config - This is the configuration of the table. It provides all information the - table needs to render its records. -
  • -
  • - model - This object provides the table two things - the data (the records that - should be shown), and the criteria of the data. The criteria effectively describes what data is - show and how it was collected. -
  • -
- -
- ), - sections: [ - { - title: 'Full Featured Example', - source: [ - { - type: GuideSectionTypes.JS, - code: fullFeaturedSource, - }, - { - type: GuideSectionTypes.HTML, - code: fullFeaturedHtml, - } - ], - text: ( -
-

- The following example shows ToR in its full glory: -

-
    -
  • - Pagination - enabled when the provided model specifies the pagination criteria (i.e. - model.criteria.page.index and model.criteria.page.size) -
  • -
  • - Sorting - enabled when any of the columns is configured to be sortable: true -
  • -
  • - Selection - enabled when the selection is configured on the config (i.e. - config.selection.onSelectionChanged?, selectable? and - config.selection.selectableMessage?) -
  • -
  • - Custom Column Rendering - You can customize how the data is displayed in each column by - specifying a renderer for that column. You can also specify the data type for that column (this will serve - as a rendering hint for the table, such that it'll choose the most suitable rendering defaults for the - data type). -
  • -
  • - Record Level Actions - Actions that are associated with each records. A single action - will be rendered at the last column of each row and will appear when hovering over the row. Multiple - actions will "folded" into a menu popup. -
  • -
-
- ), - props: propsInfo, - demo: - }, - { - title: 'Computed Columns and "Implicit" Record Actions', - source: [ - { - type: GuideSectionTypes.JS, - code: implicitRecordActionSource, - }, - { - type: GuideSectionTypes.HTML, - code: implicitRecordActionHtml, - } - ], - text: ( -
-

- Event though the table tries to dictate our common design patterns rules, at times these rules - need to be broken for good reaosns. For example, there can be a valid use case for having muliple - controls visible all the time (that is, not collapsed into a popover). -

-

- You can achieve this by using custom columnRenderers. The following example, enables switching the online/offline - status of a person. Also note how listening to selection state changes enables us to follow the design - guidelines and disable these switches when selection is on. -

-

- As a bonus, we show how you can define a computed column that is not associated with any - specific record key and simply renders content that is computed/derived out of the record itself (here we - added a small little icon column that shows the user icon that is colored based on the person's - online status). -

-
- ), - demo: - }, - { - title: 'Column data types', - source: [ - { - type: GuideSectionTypes.JS, - code: columnRenderersSource, - }, - { - type: GuideSectionTypes.HTML, - code: columnRenderersHtml, - } - ], - text: ( -
-

- You can specify a dataType property in your column configuration - which will be used as the default format for rendering the data for each cell in - that column. -

-
- ), - demo: - } - ] -}; diff --git a/src/components/index.js b/src/components/index.js index 6d33e33c80c..250853169ea 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -239,10 +239,6 @@ export { EuiTableRowCellCheckbox, } from './table'; -export { - EuiTableOfRecords -} from './table_of_records'; - export { EuiBasicTable, EuiInMemoryTable diff --git a/src/components/table_of_records/__snapshots__/collapsed_record_actions.test.js.snap b/src/components/table_of_records/__snapshots__/collapsed_record_actions.test.js.snap deleted file mode 100644 index 191c044c053..00000000000 --- a/src/components/table_of_records/__snapshots__/collapsed_record_actions.test.js.snap +++ /dev/null @@ -1,40 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`CollapsedRecordActions render 1`] = ` - - } - closePopover={[Function]} - id="id-actions" - isOpen={false} - ownFocus={false} - panelPaddingSize="none" - popoverRef={[Function]} -> - - default1 - , - , - ] - } - /> - -`; diff --git a/src/components/table_of_records/__snapshots__/custom_record_action.test.js.snap b/src/components/table_of_records/__snapshots__/custom_record_action.test.js.snap deleted file mode 100644 index e0a9b03ae1e..00000000000 --- a/src/components/table_of_records/__snapshots__/custom_record_action.test.js.snap +++ /dev/null @@ -1,11 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`CustomRecordAction render 1`] = ` -
-`; diff --git a/src/components/table_of_records/__snapshots__/default_record_action.test.js.snap b/src/components/table_of_records/__snapshots__/default_record_action.test.js.snap deleted file mode 100644 index ee11eed574c..00000000000 --- a/src/components/table_of_records/__snapshots__/default_record_action.test.js.snap +++ /dev/null @@ -1,42 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`DefaultRecordAction render - button 1`] = ` - - action1 - -`; - -exports[`DefaultRecordAction render - icon 1`] = ` - -`; diff --git a/src/components/table_of_records/__snapshots__/expanded_record_actions.test.js.snap b/src/components/table_of_records/__snapshots__/expanded_record_actions.test.js.snap deleted file mode 100644 index c21085714b0..00000000000 --- a/src/components/table_of_records/__snapshots__/expanded_record_actions.test.js.snap +++ /dev/null @@ -1,72 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ExpandedRecordActions render 1`] = ` -Array [ - , - , -] -`; diff --git a/src/components/table_of_records/__snapshots__/pagination_bar.test.js.snap b/src/components/table_of_records/__snapshots__/pagination_bar.test.js.snap deleted file mode 100644 index 7a8e8d39904..00000000000 --- a/src/components/table_of_records/__snapshots__/pagination_bar.test.js.snap +++ /dev/null @@ -1,45 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`PaginationBar render - custom page size options 1`] = ` -
- - -
-`; - -exports[`PaginationBar render 1`] = ` -
- - -
-`; diff --git a/src/components/table_of_records/__snapshots__/table_of_records.test.js.snap b/src/components/table_of_records/__snapshots__/table_of_records.test.js.snap deleted file mode 100644 index 9ffe7a91914..00000000000 --- a/src/components/table_of_records/__snapshots__/table_of_records.test.js.snap +++ /dev/null @@ -1,1879 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EuiTableOfRecords basic - empty 1`] = ` -
- - - - Name - - - - -
-`; - -exports[`EuiTableOfRecords basic - with records 1`] = ` -
- - - - Name - - - - - - name1 - - - - - name2 - - - - - name3 - - - - -
-`; - -exports[`EuiTableOfRecords with pagination - 2nd page 1`] = ` -
- - - - Name - - - - - - name1 - - - - - name2 - - - - - -
-`; - -exports[`EuiTableOfRecords with pagination 1`] = ` -
- - - - Name - - - - - - name1 - - - - - name2 - - - - - name3 - - - - - -
-`; - -exports[`EuiTableOfRecords with pagination and selection 1`] = ` -
- - - - - - - Name - - - - - - - - - name1 - - - - - - - - name2 - - - - - - - - name3 - - - - - -
-`; - -exports[`EuiTableOfRecords with pagination, selection and sorting 1`] = ` -
- - - - - - - Name - - - - - - - - - name1 - - - - - - - - name2 - - - - - - - - name3 - - - - - -
-`; - -exports[`EuiTableOfRecords with pagination, selection, sorting and a single record action 1`] = ` -
- - - - - - - Name - - - - - - - - - - name1 - - - - - - - - - - - name2 - - - - - - - - - - - name3 - - - - - - - - -
-`; - -exports[`EuiTableOfRecords with pagination, selection, sorting and column dataType 1`] = ` -
- - - - - - - Count - - - - - - - - - 1 - - - - - - - - 2 - - - - - - - - 3 - - - - - -
-`; - -exports[`EuiTableOfRecords with pagination, selection, sorting and column renderer 1`] = ` -
- - - - - - - Name - - - - - - - - - NAME1 - - - - - - - - NAME2 - - - - - - - - NAME3 - - - - - -
-`; - -exports[`EuiTableOfRecords with pagination, selection, sorting and multiple record actions 1`] = ` -
- - - - - - - Name - - - - - - - - - - name1 - - - - - - - - - - - name2 - - - - - - - - - - - name3 - - - - - - - - -
-`; - -exports[`EuiTableOfRecords with pagination, selection, sorting, column renderer and column dataType 1`] = ` -
- - - - - - - Count - - - - - - - - - x - - - - - - - - xx - - - - - - - - xxx - - - - - -
-`; - -exports[`EuiTableOfRecords with sorting 1`] = ` -
- - - - Name - - - - - - name1 - - - - - name2 - - - - - name3 - - - - -
-`; diff --git a/src/components/table_of_records/_index.scss b/src/components/table_of_records/_index.scss deleted file mode 100644 index 0bf270dde0f..00000000000 --- a/src/components/table_of_records/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'table_of_records'; diff --git a/src/components/table_of_records/_table_of_records.scss b/src/components/table_of_records/_table_of_records.scss deleted file mode 100644 index 589d61068cf..00000000000 --- a/src/components/table_of_records/_table_of_records.scss +++ /dev/null @@ -1,3 +0,0 @@ -.euiTableOfRecords { - -} diff --git a/src/components/table_of_records/collapsed_record_actions.js b/src/components/table_of_records/collapsed_record_actions.js deleted file mode 100644 index dd637e91e02..00000000000 --- a/src/components/table_of_records/collapsed_record_actions.js +++ /dev/null @@ -1,108 +0,0 @@ -import React, { Component } from 'react'; -import { EuiContextMenuItem, EuiContextMenuPanel } from '../context_menu'; -import { EuiPopover } from '../popover'; -import { EuiButtonIcon } from '../button'; - -export class CollapsedRecordActions extends Component { - - constructor(props) { - super(props); - this.state = { popoverOpen: false }; - } - - togglePopover = () => { - this.setState(prevState => ({ popoverOpen: !prevState.popoverOpen })); - }; - - closePopover = () => { - this.setState({ popoverOpen: false }); - }; - - onPopoverBlur = () => { - // you must be asking... WTF? I know... but this timeout is - // required to make sure we process the onBlur events after the initial - // event cycle. Reference: - // https://medium.com/@jessebeach/dealing-with-focus-and-blur-in-a-composite-widget-in-react-90d3c3b49a9b - window.requestAnimationFrame(() => { - if (!this.popoverDiv.contains(document.activeElement)) { - this.props.onBlur(); - } - }); - }; - - registerPopoverDiv = (popoverDiv) => { - if (!this.popoverDiv) { - this.popoverDiv = popoverDiv; - this.popoverDiv.addEventListener('focusout', this.onPopoverBlur); - } - }; - - componentWillUnmount() { - if (this.popoverDiv) { - this.popoverDiv.removeEventListener('focusout', this.onPopoverBlur); - } - } - - render() { - - const { actions, recordId, record, model, actionEnabled, onFocus } = this.props; - - const isOpen = this.state.popoverOpen; - - let allDisabled = true; - const items = actions.reduce((items, action, index) => { - const key = `action_${recordId}_${index}`; - const available = action.available ? action.available(record, model) : true; - if (!available) { - return items; - } - const enabled = actionEnabled(action); - allDisabled = allDisabled && !enabled; - if (action.render) { - const item = action.render(record, model, enabled); - items.push( - - {item} - - ); - } else { - items.push( - - {action.name} - - ); - } - return items; - }, []); - - const popoverButton = ( - - ); - - return ( - - - - ); - } -} diff --git a/src/components/table_of_records/collapsed_record_actions.test.js b/src/components/table_of_records/collapsed_record_actions.test.js deleted file mode 100644 index 5d424cb536b..00000000000 --- a/src/components/table_of_records/collapsed_record_actions.test.js +++ /dev/null @@ -1,51 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; -import { CollapsedRecordActions } from './collapsed_record_actions'; - -describe('CollapsedRecordActions', () => { - - test('render', () => { - - const props = { - actions: [ - { - name: 'default1', - description: 'default 1', - onClick: () => { - } - }, - { - name: 'custom1', - description: 'custom 1', - render: () => { - } - } - ], - visible: true, - recordId: 'id', - record: { id: 'xyz' }, - model: { - data: { - records: [], - totalRecordCount: 0 - }, - criteria: { - page: { - size: 5, - index: 0 - } - } - }, - actionEnabled: () => true, - onFocus: () => {} - }; - - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); - - }); - -}); diff --git a/src/components/table_of_records/custom_record_action.js b/src/components/table_of_records/custom_record_action.js deleted file mode 100644 index b218a2a40cb..00000000000 --- a/src/components/table_of_records/custom_record_action.js +++ /dev/null @@ -1,54 +0,0 @@ -import React, { Component, cloneElement } from 'react'; - -export class CustomRecordAction extends Component { - - constructor(props) { - super(props); - this.state = { hasFocus: false }; - - // while generally considered an anti-pattern, here we require - // to do that as the onFocus/onBlur events of the action controls - // may trigger while this component is unmounted. An alternative - // (at least the workarounds suggested by react is to unregister - // the onFocus/onBlur listeners from the action controls... this - // unfortunately will lead to unecessarily complex code... so we'll - // stick to this approach for now) - this.mounted = false; - } - - componentWillMount() { - this.mounted = true; - } - - componentWillUnmount() { - this.mounted = false; - } - - onFocus = () => { - if (this.mounted) { - this.setState({ hasFocus: true }); - } - }; - - onBlur = () => { - if (this.mounted) { - this.setState({ hasFocus: false }); - } - }; - - hasFocus = () => { - return this.state.hasFocus; - }; - - render() { - const { action, enabled, visible, record, model } = this.props; - const tool = action.render(record, model, enabled); - const clonedTool = cloneElement(tool, { onFocus: this.onFocus, onBlur: this.onBlur }); - const style = this.hasFocus() || visible ? { opacity: 1 } : { opacity: 0 }; - return ( -
- {clonedTool} -
- ); - } -} diff --git a/src/components/table_of_records/custom_record_action.test.js b/src/components/table_of_records/custom_record_action.test.js deleted file mode 100644 index bf64729cc6c..00000000000 --- a/src/components/table_of_records/custom_record_action.test.js +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; -import { CustomRecordAction } from './custom_record_action'; - -describe('CustomRecordAction', () => { - - test('render', () => { - - const props = { - action: { - name: 'custom1', - description: 'custom 1', - render: () => 'test' - }, - enabled: true, - visible: true, - record: { id: 'xyz' }, - model: { - data: { - records: [], - totalRecordCount: 0 - }, - criteria: { - page: { - size: 5, - index: 0 - } - } - } - }; - - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); - - }); - -}); diff --git a/src/components/table_of_records/default_record_action.js b/src/components/table_of_records/default_record_action.js deleted file mode 100644 index 1e748acc107..00000000000 --- a/src/components/table_of_records/default_record_action.js +++ /dev/null @@ -1,111 +0,0 @@ -import React, { Component } from 'react'; -import { isString } from '../../services/predicate'; -import { EuiButton, EuiButtonIcon } from '../button'; - -const defaults = { - color: 'primary' -}; - -export class DefaultRecordAction extends Component { - - constructor(props) { - super(props); - this.state = { hasFocus: false }; - - // while generally considered an anti-pattern, here we require - // to do that as the onFocus/onBlur events of the action controls - // may trigger while this component is unmounted. An alternative - // (at least the workarounds suggested by react is to unregister - // the onFocus/onBlur listeners from the action controls... this - // unfortunately will lead to unecessarily complex code... so we'll - // stick to this approach for now) - this.mounted = false; - } - - componentWillMount() { - this.mounted = true; - } - - componentWillUnmount() { - this.mounted = false; - } - - onFocus = () => { - if (this.mounted) { - this.setState({ hasFocus: true }); - } - }; - - onBlur = () => { - if (this.mounted) { - this.setState({ hasFocus: false }); - } - }; - - hasFocus = () => { - return this.state.hasFocus; - }; - - render() { - const { action, enabled, visible, record, model } = this.props; - if (!action.onClick) { - throw new Error(`Cannot render record action [${action.name}]. Missing required 'onClick' callback. If you want - to provide a custom action control, make sure to define the 'render' callback`); - } - const onClick = () => action.onClick(record, model); - const color = this.resolveActionColor(); - const icon = this.resolveActionIcon(); - const style = this.hasFocus() || visible ? { opacity: 1 } : { opacity: 0 }; - if (action.type === 'icon') { - if (!icon) { - throw new Error(`Cannot render record action [${action.name}]. It is configured to render as an icon but no - icon is provided. Make sure to set the 'icon' property of the action`); - } - return ( - - ); - } - - return ( - - {action.name} - - ); - } - - resolveActionIcon() { - const { action, record, model } = this.props; - if (action.icon) { - return isString(action.icon) ? action.icon : action.icon(record, model); - } - } - - resolveActionColor() { - const { action, record, model } = this.props; - if (action.color) { - return isString(action.color) ? action.color : action.color(record, model); - } - return defaults.color; - } -} diff --git a/src/components/table_of_records/default_record_action.test.js b/src/components/table_of_records/default_record_action.test.js deleted file mode 100644 index ec625d643dd..00000000000 --- a/src/components/table_of_records/default_record_action.test.js +++ /dev/null @@ -1,79 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; -import { DefaultRecordAction } from './default_record_action'; -import { Random } from '../../services/random'; - -const random = new Random(); - -describe('DefaultRecordAction', () => { - - test('render - button', () => { - - const props = { - action: { - name: 'action1', - description: 'action 1', - type: random.oneOf([undefined, 'button', 'foobar']), - onClick: () => {} - }, - enabled: true, - visible: true, - record: { id: 'xyz' }, - model: { - data: { - records: [], - totalRecordCount: 0 - }, - criteria: { - page: { - size: 5, - index: 0 - } - } - } - }; - - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); - - }); - - test('render - icon', () => { - - const props = { - action: { - name: 'action1', - description: 'action 1', - type: 'icon', - icon: 'trash', - onClick: () => {} - }, - enabled: true, - visible: true, - record: { id: 'xyz' }, - model: { - data: { - records: [], - totalRecordCount: 0 - }, - criteria: { - page: { - size: 5, - index: 0 - } - } - } - }; - - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); - - }); - -}); diff --git a/src/components/table_of_records/expanded_record_actions.js b/src/components/table_of_records/expanded_record_actions.js deleted file mode 100644 index 8429e80daea..00000000000 --- a/src/components/table_of_records/expanded_record_actions.js +++ /dev/null @@ -1,44 +0,0 @@ -import React from 'react'; -import { DefaultRecordAction } from './default_record_action'; -import { CustomRecordAction } from './custom_record_action'; - -export const ExpandedRecordActions = ({ actions, visible, recordId, record, model, actionEnabled }) => { - - return actions.reduce((tools, action, index) => { - const available = action.available ? action.available(record, model) : true; - if (!available) { - return tools; - } - const enabled = actionEnabled(action); - const key = `record_action_${recordId}_${index}`; - if (action.render) { - // custom action has a render function - tools.push( - - ); - } else { - tools.push( - - ); - } - return tools; - }, []); -}; diff --git a/src/components/table_of_records/expanded_record_actions.test.js b/src/components/table_of_records/expanded_record_actions.test.js deleted file mode 100644 index d3e6af9a653..00000000000 --- a/src/components/table_of_records/expanded_record_actions.test.js +++ /dev/null @@ -1,50 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; -import { ExpandedRecordActions } from './expanded_record_actions'; - -describe('ExpandedRecordActions', () => { - - test('render', () => { - - const props = { - actions: [ - { - name: 'default1', - description: 'default 1', - onClick: () => { - } - }, - { - name: 'custom1', - description: 'custom 1', - render: () => { - } - } - ], - visible: true, - recordId: 'id', - record: { id: 'xyz' }, - model: { - data: { - records: [], - totalRecordCount: 0 - }, - criteria: { - page: { - size: 5, - index: 0 - } - } - }, - actionEnabled: () => true - }; - - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); - - }); - -}); diff --git a/src/components/table_of_records/index.js b/src/components/table_of_records/index.js deleted file mode 100644 index 0da08b7f8d0..00000000000 --- a/src/components/table_of_records/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export { - EuiTableOfRecords -} from './table_of_records'; diff --git a/src/components/table_of_records/pagination_bar.js b/src/components/table_of_records/pagination_bar.js deleted file mode 100644 index 7ae0adcafc0..00000000000 --- a/src/components/table_of_records/pagination_bar.js +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react'; -import { EuiSpacer } from '../spacer'; -import { EuiTablePagination } from '../table'; - -const defaults = { - pageSizeOptions: [5, 10, 20] -}; - -export const PaginationBar = ({ config, model, onPageSizeChange, onPageChange }) => { - if (!model.criteria || !model.criteria.page) { - throw new Error(`The table of records is configured to show pagination but the provided - model is missing page criteria. Make sure the page criteria (index and size) is specified - under model.criteria.page`); - } - if (!config.onDataCriteriaChange) { - throw new Error(`The table of records is provided with a paginated model but [onDataCriteriaChange] is - not configured. This callback must be implemented to handle pagination changes`); - } - const pageSizeOptions = config.pagination.pageSizeOptions ? - config.pagination.pageSizeOptions : - defaults.pageSizeOptions; - const totalRecordCount = model.data.totalRecordCount || model.data.records.length; - const pageCount = Math.ceil(totalRecordCount / model.criteria.page.size); - return ( -
- - -
- ); -}; diff --git a/src/components/table_of_records/pagination_bar.test.js b/src/components/table_of_records/pagination_bar.test.js deleted file mode 100644 index 004d00587cf..00000000000 --- a/src/components/table_of_records/pagination_bar.test.js +++ /dev/null @@ -1,90 +0,0 @@ -import React from 'react'; -import { requiredProps } from '../../test'; -import { shallow } from 'enzyme'; -import { PaginationBar } from './pagination_bar'; - -describe('PaginationBar', () => { - - test('render', () => { - - const props = { - ...requiredProps, - config: { - recordId: 'id', - columns: [ - { - field: 'name', - name: 'Name', - description: 'description' - } - ], - pagination: {}, - onDataCriteriaChange: () => {} - }, - model: { - data: { - records: [], - totalRecordCount: 0 - }, - criteria: { - page: { - size: 5, - index: 0 - } - } - }, - onPageSizeChange: () => {}, - onPageChange: () => {} - }; - - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); - - }); - - test('render - custom page size options', () => { - - const props = { - ...requiredProps, - config: { - recordId: 'id', - columns: [ - { - field: 'name', - name: 'Name', - description: 'description' - } - ], - pagination: { - pageSizeOptions: [1, 2, 3] - }, - onDataCriteriaChange: () => {} - }, - model: { - data: { - records: [], - totalRecordCount: 0 - }, - criteria: { - page: { - size: 5, - index: 0 - } - } - }, - onPageSizeChange: () => {}, - onPageChange: () => {} - }; - - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); - - }); - -}); diff --git a/src/components/table_of_records/table_of_records.behavior.test.js b/src/components/table_of_records/table_of_records.behavior.test.js deleted file mode 100644 index 21676712515..00000000000 --- a/src/components/table_of_records/table_of_records.behavior.test.js +++ /dev/null @@ -1,67 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; -import { findTestSubject } from '../../test'; - -import { EuiTableOfRecords } from './table_of_records'; - -describe('EuiTableOfRecords', () => { - describe('behavior', () => { - describe('selected items', () => { - let props; - let component; - - beforeEach(() => { - props = { - config: { - recordId: 'id', - columns: [ - { - field: 'name', - name: 'Name', - description: 'description' - } - ], - selection: { - onSelectionChanged: () => {} - }, - onDataCriteriaChange: () => {} - }, - model: { - data: { - records: [ - { id: '1', name: 'name1' }, - { id: '2', name: 'name2' } - ], - }, - } - }; - - component = mount(); - }); - - test('check the select all checkbox when all are selected', () => { - findTestSubject(component, 'checkboxSelectRow-1').simulate('change', { target: { checked: true } }); - findTestSubject(component, 'checkboxSelectRow-2').simulate('change', { target: { checked: true } }); - expect(findTestSubject(component, 'checkboxSelectAll').prop('checked')).toBe(true); - }); - - test('uncheck the select all checkbox when some are selected', () => { - findTestSubject(component, 'checkboxSelectRow-1').simulate('change', { target: { checked: true } }); - expect(findTestSubject(component, 'checkboxSelectAll').prop('checked')).toBe(false); - }); - - test('are all selected when the select all checkbox is checked', () => { - findTestSubject(component, 'checkboxSelectAll').simulate('change', { target: { checked: true } }); - expect(findTestSubject(component, 'checkboxSelectRow-1').prop('checked')).toBe(true); - expect(findTestSubject(component, 'checkboxSelectRow-2').prop('checked')).toBe(true); - }); - - test('select all checkbox becomes unchecked when selected items are deleted', () => { - findTestSubject(component, 'checkboxSelectAll').simulate('change', { target: { checked: true } }); - props.model.data.records = []; - component.setProps(...props); - expect(findTestSubject(component, 'checkboxSelectAll').prop('checked')).toBe(false); - }); - }); - }); -}); diff --git a/src/components/table_of_records/table_of_records.js b/src/components/table_of_records/table_of_records.js deleted file mode 100644 index 90ed801da96..00000000000 --- a/src/components/table_of_records/table_of_records.js +++ /dev/null @@ -1,579 +0,0 @@ -import React, { Component } from 'react'; -import _ from 'lodash'; -import { isString } from '../../services/predicate'; -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import { - EuiTable, EuiTableBody, EuiTableHeader, EuiTableHeaderCell, EuiTableHeaderCellCheckbox, - EuiTableRow, EuiTableRowCell, EuiTableRowCellCheckbox -} from '../table'; -import { EuiCheckbox } from '../form/checkbox'; -import { ICON_TYPES } from '../icon'; -import { COLORS as BUTTON_ICON_COLORS } from '../button/button_icon/button_icon'; -import { - formatAuto, - formatBoolean, - formatDate, - formatNumber, - formatText, - LEFT_ALIGNMENT, RIGHT_ALIGNMENT, - SortDirection, PropertySortType -} from '../../services'; -import { PaginationBar } from './pagination_bar'; -import { CollapsedRecordActions } from './collapsed_record_actions'; -import { ExpandedRecordActions } from './expanded_record_actions'; - -const dataTypesProfiles = { - auto: { - align: LEFT_ALIGNMENT, - render: value => formatAuto(value) - }, - string: { - align: LEFT_ALIGNMENT, - render: value => formatText(value) - }, - number: { - align: RIGHT_ALIGNMENT, - render: value => formatNumber(value), - }, - boolean: { - align: LEFT_ALIGNMENT, - render: value => formatBoolean(value), - }, - date: { - align: LEFT_ALIGNMENT, - render: value => formatDate(value), - } -}; - -const DATA_TYPES = Object.keys(dataTypesProfiles); - -const DefaultRecordActionType = PropTypes.shape({ - type: PropTypes.oneOf([ 'icon', 'button' ]), // default is 'button' - name: PropTypes.string.isRequired, - description: PropTypes.string.isRequired, - onClick: PropTypes.func.isRequired, // (record, model) => void, - available: PropTypes.func, // (record, model) => boolean; - enabled: PropTypes.func, // (record, model) => boolean; - icon: PropTypes.oneOfType([ // required when type is 'icon' - PropTypes.oneOf(ICON_TYPES), - PropTypes.func // (record, model) => oneOf(ICON_TYPES) - ]), - color: PropTypes.oneOfType([ - PropTypes.oneOf(BUTTON_ICON_COLORS), - PropTypes.func // (record, model) => oneOf(ICON_BUTTON_COLORS) - ]) -}); - -const CustomRecordActionType = PropTypes.shape({ - render: PropTypes.func.isRequired, // (record, model, enabled) => PropTypes.node; - available: PropTypes.func, // (record, model) => boolean; - enabled: PropTypes.func // (record, model) => boolean; -}); - -const SupportedRecordActionType = PropTypes.oneOfType([ - DefaultRecordActionType, - CustomRecordActionType -]); - -const FieldDataColumnType = PropTypes.shape({ - field: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - description: PropTypes.string, - dataType: PropTypes.oneOf(DATA_TYPES), - width: PropTypes.string, - sortable: PropTypes.bool, - align: PropTypes.oneOf([LEFT_ALIGNMENT, RIGHT_ALIGNMENT]), - truncateText: PropTypes.bool, - render: PropTypes.func // ((value, record) => PropTypes.node (also see [services/value_renderer] for basic implementations) -}); - -const ComputedColumnType = PropTypes.shape({ - render: PropTypes.func.isRequired, // (record) => PropTypes.node - name: PropTypes.string, - description: PropTypes.string, - width: PropTypes.string, - truncateText: PropTypes.bool -}); - -const ActionsColumnType = PropTypes.shape({ - actions: PropTypes.arrayOf(SupportedRecordActionType).isRequired, - name: PropTypes.string, - description: PropTypes.string, - width: PropTypes.string -}); - -const ColumnType = PropTypes.oneOfType([FieldDataColumnType, ComputedColumnType, ActionsColumnType]); - -const PaginationType = PropTypes.shape({ - pageSizeOptions: PropTypes.arrayOf(PropTypes.number) -}); - -const SelectionType = PropTypes.shape({ - onSelectionChanged: PropTypes.func, // (selection: Record[]) => void;, - selectable: PropTypes.func // (record, model) => boolean; -}); - -const RecordIdType = PropTypes.oneOfType([ - PropTypes.string, // the name of the record id property - PropTypes.func // (record) => string -]); - -const ConfigType = PropTypes.shape({ - // when string, it's treated as the id property name - // when function it needs to have the following signature: (record) => string - recordId: RecordIdType.isRequired, - columns: PropTypes.arrayOf(ColumnType).isRequired, - onDataCriteriaChange: PropTypes.func, - selection: SelectionType, - pagination: PaginationType -}); - -const ModelType = PropTypes.shape({ - data: PropTypes.shape({ - records: PropTypes.array.isRequired, - totalRecordCount: PropTypes.number - }).isRequired, - criteria: PropTypes.shape({ - page: PropTypes.shape({ - index: PropTypes.number.isRequired, - size: PropTypes.number.isRequired - }), - sort: PropertySortType - }) -}); - -const EuiTableOfRecordsPropTypes = { - config: ConfigType.isRequired, - model: ModelType.isRequired, - className: PropTypes.string -}; - -export class EuiTableOfRecords extends Component { - - static propTypes = EuiTableOfRecordsPropTypes; - - constructor(props) { - super(props); - this.state = { - hoverRecordId: null, - selection: [] - }; - } - - recordId(record) { - const id = this.props.config.recordId; - return isString(id) ? record[id] : id(record); - } - - changeSelection(selection) { - if (!this.props.config.selection) { - return; - } - this.setState({ selection }); - if (this.props.config.selection.onSelectionChanged) { - this.props.config.selection.onSelectionChanged(selection); - } - } - - clearSelection() { - this.changeSelection([]); - } - - onPageSizeChange(size) { - this.clearSelection(); - const criteria = { - ...this.props.model.criteria, - page: { - ...this.props.model.criteria.page, - index: 0, // when page size changes, we take the user back to the first page - size - } - }; - this.props.config.onDataCriteriaChange(criteria); - } - - onPageChange(index) { - this.clearSelection(); - const criteria = { - ...this.props.model.criteria, - page: { - ...this.props.model.criteria.page, - index - } - }; - this.props.config.onDataCriteriaChange(criteria); - } - - onColumnSortChange(column) { - this.clearSelection(); - const currentCriteria = this.props.model.criteria; - let direction = SortDirection.ASC; - if (currentCriteria && currentCriteria.sort && currentCriteria.sort.field === column.field) { - direction = SortDirection.reverse(currentCriteria.sort.direction); - } - const criteria = { - ...currentCriteria, - // resetting the page if the criteria has one - page: !currentCriteria.page ? undefined : { - index: 0, - size: currentCriteria.page.size - }, - sort: { - field: column.field, - direction - } - }; - this.props.config.onDataCriteriaChange(criteria); - } - - onRecordHover(recordId) { - this.setState({ hoverRecordId: recordId }); - } - - clearRecordHover() { - this.setState({ hoverRecordId: null }); - } - - componentWillReceiveProps(nextProps) { - // Don't call changeSelection here or else we can get into an infinite loop: - // changeSelection calls props.onSelectionChanged on owner -> - // owner sets its state -> we receive new props, calling componentWillReceiveProps -> ad infinitum - if (!this.props.config.selection) { - return; - } - - this.setState(prevState => { - // Remove any records which don't exist any more. - const newSelection = prevState.selection.filter(selectedRecord => ( - nextProps.model.data.records.findIndex(record => record.id === selectedRecord.id) !== -1 - )); - - return { - selection: newSelection, - }; - }); - } - - render() { - const { className, config, model, ...rest } = this.props; - - const classes = classNames( - 'euiRecordsTable', - className - ); - - const table = this.renderTable(config, model); - const paginationBar = this.renderPaginationBar(config, model); - - return ( -
- {table} - {paginationBar} -
- ); - } - - renderTable(config, model) { - const head = this.renderTableHead(config, model); - const body = this.renderTableBody(config, model); - return {head}{body}; - } - - renderTableHead(config, model) { - const headers = []; - - if (config.selection) { - const selectableRecords = model.data.records.filter((record) => - !config.selection.selectable || config.selection.selectable(record, model)); - - const checked = - this.state.selection - && (selectableRecords.length !== 0) - && (this.state.selection.length === selectableRecords.length); - - const onChange = (event) => { - if (event.target.checked) { - this.changeSelection(selectableRecords); - } else { - this.changeSelection([]); - } - }; - - headers.push( - - - - ); - } - - config.columns.forEach((column, index) => { - // actions column - if (column.actions) { - headers.push( - - {column.name} - - ); - return; - } - - const align = this.resolveColumnAlign(column); - - // computed column - if (!column.field) { - headers.push( - - {column.name} - - ); - return; - } - - // field data column - const sortDirection = this.resolveColumnSortDirection(column, config, model); - const onSort = this.resolveColumnOnSort(column, config); - const isSorted = !!sortDirection; - const isSortAscending = SortDirection.isAsc(sortDirection); - headers.push( - - {column.name} - - ); - }); - - return {headers}; - } - - resolveColumnAlign(column) { - if (column.align) { - return column.align; - } - const dataType = column.dataType || 'auto'; - const profile = dataTypesProfiles[dataType]; - if (!profile) { - throw new Error(`Unknown dataType [${dataType}]. The supported data types are [${DATA_TYPES.join(', ')}]`); - } - return profile.align; - } - - resolveColumnSortDirection(column, config, model) { - const modelCriteriaSort = model.criteria ? model.criteria.sort : undefined; - if (column.sortable && modelCriteriaSort && modelCriteriaSort.field === column.field) { - return modelCriteriaSort.direction; - } - } - - resolveColumnOnSort(column, config) { - if (column.sortable) { - if (!config.onDataCriteriaChange) { - throw new Error(`The table of records is configured to be sortable on column [${column.field}] but - [onDataCriteriaChange] is not configured. This callback must be implemented to handle to handle the - sort requests`); - } - return () => this.onColumnSortChange(column); - } - } - - renderTableBody(config, model) { - const rows = model.data.records.map((record, index) => { - return this.renderTableRecordRow(record, config, model, index); - }); - return {rows}; - } - - renderTableRecordRow(record, config, model, rowIndex) { - const recordId = this.recordId(record); - const selected = this.state.selection && !!this.state.selection.find(selectedRecord => { - return this.recordId(selectedRecord) === recordId; - }); - - const cells = []; - - if (config.selection) { - cells.push(this.renderTableRecordSelectionCell(recordId, record, config, model, selected)); - } - - config.columns.forEach((column, columnIndex) => { - if (column.actions) { - cells.push(this.renderTableRecordActionsCell(recordId, record, column.actions, config, model, columnIndex)); - } else if (column.field) { - cells.push(this.renderTableRecordFieldDataCell(recordId, record, column, columnIndex)); - } else { - cells.push(this.renderTableRecordComputedCell(recordId, record, column, model, columnIndex)); - } - }); - - const onMouseOver = () => this.onRecordHover(recordId); - const onMouseOut = () => this.clearRecordHover(); - return ( - - {cells} - - ); - } - - renderTableRecordFieldDataCell(recordId, record, column, index) { - const key = `_data_column_${column.field}_${recordId}_${index}`; - const align = this.resolveColumnAlign(column); - const textOnly = !column.render; - const value = _.get(record, column.field); - const contentRenderer = this.resolveContentRenderer(column); - const content = contentRenderer(value, record); - return ( - - {content} - - ); - } - - renderTableRecordComputedCell(recordId, record, column, model, index) { - const key = `_computed_column_${recordId}_${index}`; - const align = this.resolveColumnAlign(column); - const contentRenderer = this.resolveContentRenderer(column); - const content = contentRenderer(record, model); - return ( - - {content} - - ); - } - - resolveContentRenderer(column) { - if (column.render) { - return column.render; - } - const dataType = column.dataType || 'auto'; - const profile = dataTypesProfiles[dataType]; - if (!profile) { - throw new Error(`Unknown dataType [${dataType}]. The supported data types are [${DATA_TYPES.join(', ')}]`); - } - return profile.render; - } - - renderTableRecordSelectionCell(recordId, record, config, model, selected) { - const key = `_selection_column_${recordId}`; - const checked = selected; - const disabled = config.selection.selectable && !config.selection.selectable(record); - const title = config.selection.selectableMessage && config.selection.selectableMessage(record); - const onChange = (event) => { - if (event.target.checked) { - this.changeSelection([...this.state.selection, record]); - } else { - this.changeSelection(this.state.selection.reduce((selection, selectedRecord) => { - if (this.recordId(selectedRecord) !== recordId) { - selection.push(selectedRecord); - } - return selection; - }, [])); - } - }; - - return ( - - - - ); - } - - renderTableRecordActionsCell(recordId, record, actions, config, model, columnIndex) { - const visible = this.state.hoverRecordId === recordId; - - const actionEnabled = (action) => - this.state.selection.length === 0 && (!action.enabled || action.enabled(record, model)); - - let actualActions = actions; - if (actions.length > 1) { - - // if we have more than 1 action, we don't show them all in the cell, instead we - // put them all in a popover tool. This effectively means we can only have a maximum - // of one tool per row (it's either and normal action, or it's a popover that shows multiple actions) - // - // here we create a single custom action that triggers the popover with all the configured actions - - actualActions = [ - { - name: 'Actions', - render: (record, model) => { - return ( - - ); - } - } - ]; - } - - const tools = ( - - ); - - const key = `record_actions_${recordId}_${columnIndex}`; - return ( - - {tools} - - ); - } - - renderPaginationBar(config, model) { - if (config.pagination) { - return ( - - ); - } - } - -} diff --git a/src/components/table_of_records/table_of_records.test.js b/src/components/table_of_records/table_of_records.test.js deleted file mode 100644 index 5cd988c4645..00000000000 --- a/src/components/table_of_records/table_of_records.test.js +++ /dev/null @@ -1,548 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; -import { requiredProps } from '../../test'; - -import { EuiTableOfRecords } from './table_of_records'; - -describe('EuiTableOfRecords', () => { - - test('basic - empty', () => { - - const props = { - ...requiredProps, - config: { - recordId: 'id', - columns: [ - { - field: 'name', - name: 'Name', - description: 'description' - } - ] - }, - model: { - data: { - records: [], - totalRecordCount: 0 - } - } - }; - - - const component = shallow( - - ); - - expect(component) - .toMatchSnapshot(); - }); - - test('basic - with records', () => { - - const props = { - ...requiredProps, - config: { - recordId: 'id', - columns: [ - { - field: 'name', - name: 'Name', - description: 'description' - } - ] - }, - model: { - data: { - records: [ - { id: '1', name: 'name1' }, - { id: '2', name: 'name2' }, - { id: '3', name: 'name3' } - ], - totalRecordCount: 3 - } - } - }; - - - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); - }); - - test('with pagination', () => { - - const props = { - ...requiredProps, - config: { - recordId: 'id', - columns: [ - { - field: 'name', - name: 'Name', - description: 'description' - } - ], - pagination: {}, - onDataCriteriaChange: () => undefined - }, - model: { - data: { - records: [ - { id: '1', name: 'name1' }, - { id: '2', name: 'name2' }, - { id: '3', name: 'name3' } - ], - totalRecordCount: 5 - }, - criteria: { - page: { - index: 0, - size: 3 - } - } - } - }; - - - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); - }); - - test('with pagination - 2nd page', () => { - - const props = { - ...requiredProps, - config: { - recordId: 'id', - columns: [ - { - field: 'name', - name: 'Name', - description: 'description' - } - ], - pagination: {}, - onDataCriteriaChange: () => undefined - }, - model: { - data: { - records: [ - { id: '1', name: 'name1' }, - { id: '2', name: 'name2' } - ], - totalRecordCount: 5 - }, - criteria: { - page: { - index: 1, - size: 3 - } - } - } - }; - - - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); - }); - - test('with sorting', () => { - - const props = { - ...requiredProps, - config: { - recordId: 'id', - columns: [ - { - field: 'name', - name: 'Name', - description: 'description', - sortable: true - } - ], - onDataCriteriaChange: () => undefined - }, - model: { - data: { - records: [ - { id: '1', name: 'name1' }, - { id: '2', name: 'name2' }, - { id: '3', name: 'name3' } - ], - totalRecordCount: 3 - }, - criteria: { - sort: { field: 'name', direction: 'asc' } - } - } - }; - - - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); - }); - - test('with pagination and selection', () => { - - const props = { - ...requiredProps, - config: { - recordId: 'id', - columns: [ - { - field: 'name', - name: 'Name', - description: 'description' - } - ], - pagination: {}, - selection: { - onSelectionChanged: () => undefined - }, - onDataCriteriaChange: () => undefined - }, - model: { - data: { - records: [ - { id: '1', name: 'name1' }, - { id: '2', name: 'name2' }, - { id: '3', name: 'name3' } - ], - totalRecordCount: 5 - }, - criteria: { - page: { - index: 0, - size: 3 - } - } - } - }; - - - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); - }); - - test('with pagination, selection and sorting', () => { - - const props = { - ...requiredProps, - config: { - recordId: 'id', - columns: [ - { - field: 'name', - name: 'Name', - description: 'description', - sortable: true - } - ], - pagination: {}, - selection: { - onSelectionChanged: () => undefined - }, - onDataCriteriaChange: () => undefined - }, - model: { - data: { - records: [ - { id: '1', name: 'name1' }, - { id: '2', name: 'name2' }, - { id: '3', name: 'name3' } - ], - totalRecordCount: 5 - }, - criteria: { - page: { - index: 0, - size: 3 - } - } - } - }; - - - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); - }); - - test('with pagination, selection, sorting and column renderer', () => { - - const props = { - ...requiredProps, - config: { - recordId: 'id', - columns: [ - { - field: 'name', - name: 'Name', - description: 'description', - sortable: true, - render: (name) => name.toUpperCase() - } - ], - pagination: {}, - selection: { - onSelectionChanged: () => undefined - }, - onDataCriteriaChange: () => undefined - }, - model: { - data: { - records: [ - { id: '1', name: 'name1' }, - { id: '2', name: 'name2' }, - { id: '3', name: 'name3' } - ], - totalRecordCount: 5 - }, - criteria: { - page: { - index: 0, - size: 3 - } - } - } - }; - - - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); - }); - - test('with pagination, selection, sorting and column dataType', () => { - - const props = { - ...requiredProps, - config: { - recordId: 'id', - columns: [ - { - field: 'count', - name: 'Count', - description: 'description', - sortable: true, - dataType: 'number' - } - ], - pagination: {}, - selection: { - onSelectionChanged: () => undefined - }, - onDataCriteriaChange: () => undefined - }, - model: { - data: { - records: [ - { id: '1', count: 1 }, - { id: '2', count: 2 }, - { id: '3', count: 3 } - ], - totalRecordCount: 5 - }, - criteria: { - page: { - index: 0, - size: 3 - } - } - } - }; - - - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); - }); - - // here we want to verify that the column renderer takes precedence over the column data type - test('with pagination, selection, sorting, column renderer and column dataType', () => { - - const props = { - ...requiredProps, - config: { - recordId: 'id', - columns: [ - { - field: 'count', - name: 'Count', - description: 'description', - sortable: true, - dataType: 'number', - render: (count) => 'x'.repeat(count) - } - ], - pagination: {}, - selection: { - onSelectionChanged: () => undefined - }, - onDataCriteriaChange: () => undefined - }, - model: { - data: { - records: [ - { id: '1', count: 1 }, - { id: '2', count: 2 }, - { id: '3', count: 3 } - ], - totalRecordCount: 5 - }, - criteria: { - page: { - index: 0, - size: 3 - } - } - } - }; - - - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); - }); - - test('with pagination, selection, sorting and a single record action', () => { - - const props = { - ...requiredProps, - config: { - recordId: 'id', - columns: [ - { - field: 'name', - name: 'Name', - description: 'description', - sortable: true - }, - { - actions: [ - { - type: 'button', - name: 'Edit', - description: 'edit', - onClick: () => undefined - } - ] - } - ], - pagination: {}, - selection: { - onSelectionChanged: () => undefined - }, - onDataCriteriaChange: () => undefined - }, - model: { - data: { - records: [ - { id: '1', name: 'name1' }, - { id: '2', name: 'name2' }, - { id: '3', name: 'name3' } - ], - totalRecordCount: 5 - }, - criteria: { - page: { - index: 0, - size: 3 - } - } - } - }; - - - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); - }); - - test('with pagination, selection, sorting and multiple record actions', () => { - - const props = { - ...requiredProps, - config: { - recordId: 'id', - columns: [ - { - field: 'name', - name: 'Name', - description: 'description', - sortable: true - }, - { - actions: [ - { - type: 'button', - name: 'Edit', - description: 'edit', - onClick: () => undefined - }, - { - type: 'button', - name: 'Delete', - description: 'delete', - onClick: () => undefined - } - ] - } - ], - pagination: {}, - selection: { - onSelectionChanged: () => undefined - }, - onDataCriteriaChange: () => undefined - }, - model: { - data: { - records: [ - { id: '1', name: 'name1' }, - { id: '2', name: 'name2' }, - { id: '3', name: 'name3' } - ], - totalRecordCount: 5 - }, - criteria: { - page: { - index: 0, - size: 3 - } - } - } - }; - - - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); - }); - -});