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

Introducing EuiBasicTable #377

Merged
merged 1 commit into from
Feb 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 5 additions & 5 deletions src-docs/src/components/guide_section/guide_section.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ export class GuideSection extends Component {

function markup(text) {
const regex = /(#[a-zA-Z]+)|(`[^`]+`)/g;
return text.split(regex).map(token => {
return text.split(regex).map((token, index) => {
if (!token) {
return '';
}
Expand All @@ -181,11 +181,11 @@ export class GuideSection extends Component {
const onClick = () => {
document.getElementById(id).scrollIntoView();
};
return <EuiLink onClick={onClick}>{id}</EuiLink>;
return <EuiLink key={`markup-${index}`} onClick={onClick}>{id}</EuiLink>;
}
if (token.startsWith('`')) {
const code = token.substring(1, token.length - 1);
return <EuiCode>{code}</EuiCode>;
return <EuiCode key={`markup-${index}`}>{code}</EuiCode>;
}
return token;

Expand All @@ -196,7 +196,7 @@ export class GuideSection extends Component {
const descriptionMarkup = markup(propDescription);
let defaultValueMarkup = '';
if (defaultValue) {
defaultValueMarkup = [ <EuiCode>{defaultValue.value}</EuiCode> ];
defaultValueMarkup = [ <EuiCode key={`defaultValue-${propName}`}>{defaultValue.value}</EuiCode> ];
if (defaultValue.comment) {
defaultValueMarkup.push(`(${defaultValue.comment})`);
}
Expand Down Expand Up @@ -236,7 +236,7 @@ export class GuideSection extends Component {

if (description) {
descriptionElement = (
<div key="description">
<div key={`description-${componentName}`}>
<EuiText>
<p>{description}</p>
</EuiText>
Expand Down
4 changes: 4 additions & 0 deletions src-docs/src/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ import { StepsExample }
import { TableExample }
from './views/table/table_example';

import { BasicTableExample }
from './views/basic_table/basic_table_example';

import { TableOfRecordsExample }
from './views/table_of_records/table_of_records_example';

Expand Down Expand Up @@ -242,6 +245,7 @@ const components = [
StepsExample,
TableExample,
TableOfRecordsExample,
BasicTableExample,
TabsExample,
TextExample,
TitleExample,
Expand Down
207 changes: 207 additions & 0 deletions src-docs/src/views/basic_table/actions/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
import React, { Component } from 'react';
import { formatDate } from '../../../../../src/services/format';
import { createDataStore } from '../data_store';
import { EuiBasicTable } from '../../../../../src/components/basic_table';
import { EuiLink } from '../../../../../src/components/link/link';
import { EuiHealth } from '../../../../../src/components/health';
import { EuiButton } from '../../../../../src/components/button/button';
import { EuiFlexGroup } from '../../../../../src/components/flex/flex_group';
import { EuiFlexItem } from '../../../../../src/components/flex/flex_item';
import { EuiSwitch } from '../../../../../src/components/form/switch/switch';
import { EuiSpacer } from '../../../../../src/components/spacer/spacer';

/*
Example user object:

{
id: '1',
firstName: 'john',
lastName: 'doe',
github: 'johndoe',
dateOfBirth: Date.now(),
nationality: 'NL',
online: true
}

Example country object:

{
code: 'NL',
name: 'Netherlands',
flag: '🇳🇱'
}
*/

const store = createDataStore();

export class Table extends Component {

constructor(props) {
super(props);
this.state = {
...this.buildTableState({ page: { index: 0, size: 5 } }),
selection: [],
multiAction: false
};
}

buildTableState(criteria) {
const { page } = criteria;
return {
criteria,
data: store.findUsers(page.index, page.size, criteria.sort)
};
}

reloadData(selection) {
this.setState(prevState => ({
...this.buildTableState(prevState.criteria),
selection
}));
}

renderDeleteButton() {
const selection = this.state.selection;
if (selection.length === 0) {
return;
}
const onClick = () => {
store.deleteUsers(...selection.map(user => user.id));
this.reloadData([]);
};
return (
<EuiButton
color="danger"
iconType="trash"
onClick={onClick}
>
Delete {selection.length} Users
</EuiButton>
);
}

toggleMultiAction() {
this.setState(prevState => ({ multiAction: !prevState.multiAction }));
}

deleteUser(user) {
store.deleteUsers(user.id);
this.reloadData([]);
}

cloneUser(user) {
store.cloneUser(user.id);
this.reloadData([]);
}

render() {
const { page, sort } = this.state.criteria;
const data = this.state.data;
const deleteButton = this.renderDeleteButton();
return (
<div>
<div>
<EuiFlexGroup alignItems="center">
{deleteButton}
<EuiFlexItem grow={false}>
<EuiSwitch
label="Multiple Actions"
checked={this.state.multiAction}
onChange={this.toggleMultiAction.bind(this)}
/>
</EuiFlexItem>
</EuiFlexGroup>
</div>
<EuiSpacer size="l" />
<EuiBasicTable
items={data.items}
columns={[
{
field: 'firstName',
name: 'First Name',
sortable: true
},
{
field: 'lastName',
name: 'Last Name'
},
{
field: 'github',
name: 'Github',
render: (username) => (
<EuiLink href={`https://github.com/${username}`} target="_blank">{username}</EuiLink>
)
},
{
field: 'dateOfBirth',
name: 'Date of Birth',
dataType: 'date',
render: (date) => formatDate(date, 'dobLong'),
sortable: true
},
{
field: 'nationality',
name: 'Nationality',
render: (countryCode) => {
const country = store.getCountry(countryCode);
return `${country.flag} ${country.name}`;
}
},
{
field: 'online',
name: 'Online',
dataType: 'boolean',
render: (online) => {
const color = online ? 'success' : 'danger';
const label = online ? 'Online' : 'Offline';
return <EuiHealth color={color}>{label}</EuiHealth>;
},
sortable: true
},
{
name: 'Actions',
actions: this.state.multiAction ? [
{
name: 'Clone',
description: 'Clone this person',
icon: 'copy',
onClick: (user) => this.cloneUser(user)
},
{
name: 'Delete',
description: 'Delete this person',
icon: 'trash',
color: 'danger',
onClick: (user) => this.deleteUser(user)
}
] : [
{
name: 'Delete',
type: 'icon',
description: 'Delete this person',
icon: 'trash',
color: 'danger',
onClick: (person) => this.deleteUser(person)
}
]
}
]}
pagination={{
pageIndex: page.index,
pageSize: page.size,
totalItemCount: data.totalCount,
pageSizeOptions: [3, 5, 8]
}}
sorting={{ sort }}
selection={{
itemId: 'id',
selectable: (user) => user.online,
selectableMessage: (selectable) => !selectable ? 'User is currently offline' : undefined,
onSelectionChange: (selection) => this.setState({ selection })
}}
onChange={(criteria) => this.setState(this.buildTableState(criteria))}
/>
</div>
);
}
}
46 changes: 46 additions & 0 deletions src-docs/src/views/basic_table/actions/actions_section.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react';
import { EuiBasicTable } from '../../../../../src/components';
import { GuideSectionTypes } from '../../../components';
import { renderToHtml } from '../../../services';

import { Table } from './actions';
import { EuiCode } from '../../../../../src/components/code';
const source = require('!!raw-loader!./actions');
const html = renderToHtml(Table);

export const section = {
title: 'Actions',
source: [
{
type: GuideSectionTypes.JS,
code: source,
}, {
type: GuideSectionTypes.HTML,
code: html,
}
],
text: (
<div>
<p>
The following example demonstrates &quot;actions&quot; columns. This is a special column
where you can define item level actions on. The most basic action you can define is a button
(maybe be of type <EuiCode>`button`</EuiCode> or <EuiCode>`icon`</EuiCode>) and it is also
possible to define a custom action.
</p>
<p>
The implementation enforces some of the UI/UX guidelines:
</p>
<ul>
<li>
There can only be a single action tool visible per row. When more than one action is defined,
they will all be collapsed under a single popover &quot;gear&quot; button.
</li>
<li>
The actions are only visible when the user hovers over the row with the mouse.
</li>
</ul>
</div>
),
components: { EuiBasicTable },
demo: <Table/>,
};
1 change: 1 addition & 0 deletions src-docs/src/views/basic_table/actions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { section } from './actions_section';
77 changes: 77 additions & 0 deletions src-docs/src/views/basic_table/basic/basic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React from 'react';
import { formatDate } from '../../../../../src/services/format';
import { createDataStore } from '../data_store';
import { EuiBasicTable } from '../../../../../src/components/basic_table';
import { EuiHealth } from '../../../../../src/components/health';
import { EuiLink } from '../../../../../src/components/link/link';

/*
Example user object:

{
id: '1',
firstName: 'john',
lastName: 'doe',
github: 'johndoe',
dateOfBirth: Date.now(),
nationality: 'NL',
online: true
}

Example country object:

{
code: 'NL',
name: 'Netherlands',
flag: '🇳🇱'
}
*/

const store = createDataStore();

export const Table = () => (
<EuiBasicTable
items={store.users.filter((user, index) => index < 10)}
columns={[
{
field: 'firstName',
name: 'First Name'
},
{
field: 'lastName',
name: 'Last Name'
},
{
field: 'github',
name: 'Github',
render: (username) => (
<EuiLink href={`https://github.com/${username}`} target="_blank">{username}</EuiLink>
)
},
{
field: 'dateOfBirth',
name: 'Date of Birth',
dataType: 'date',
render: (date) => formatDate(date, 'dobLong')
},
{
field: 'nationality',
name: 'Nationality',
render: (countryCode) => {
const country = store.getCountry(countryCode);
return `${country.flag} ${country.name}`;
}
},
{
field: 'online',
name: 'Online',
dataType: 'boolean',
render: (online) => {
const color = online ? 'success' : 'danger';
const label = online ? 'Online' : 'Offline';
return <EuiHealth color={color}>{label}</EuiHealth>;
}
}
]}
/>
);
Loading