Unverified Commit 58558c74 authored by Marcos Iglesias's avatar Marcos Iglesias Committed by GitHub

feat: Adds a basic Table to our component library (#636)

Signed-off-by: 's avatarMarcos Iglesias Valle <golodhros@gmail.com>
parent 6355e812
......@@ -99,6 +99,9 @@ exports[`strict null compilation`] = {
[255, 6, 11, "No overload matches this call.\\n The last overload gave the following error.\\n Type \'(() => SubmitSearchRequest) | null\' is not assignable to type \'ActionCreator<any>\'.\\n Type \'null\' is not assignable to type \'ActionCreator<any>\'.", "2296208050"],
[270, 4, 18, "No overload matches this call.\\n The last overload gave the following error.\\n Argument of type \'(dispatch: any, ownProps: any) => ActionCreator<unknown>\' is not assignable to parameter of type \'DispatchFromProps\'.\\n Type \'(dispatch: any, ownProps: any) => ActionCreator<unknown>\' is missing the following properties from type \'DispatchFromProps\': submitSearch, onInputChange, onSelectInlineResult", "2926224796"]
],
"js/components/common/Table/index.tsx:2224568087": [
[44, 20, 7, "Type \'unknown\' is not assignable to type \'ReactNode\'.\\n Type \'unknown\' is not assignable to type \'ReactPortal\'.", "3446393192"]
],
"js/components/common/Tags/TagInput/index.tsx:3754832290": [
[63, 22, 6, "Type \'undefined\' is not assignable to type \'GetAllTagsRequest\'.", "1979467425"],
[66, 4, 4, "Type \'undefined\' is not assignable to type \'Tag[]\'.", "2087952548"],
......
import * as React from 'react';
import { mount } from 'enzyme';
import Table, { TableProps } from '.';
import TestDataBuilder from './testDataBuilder';
const dataBuilder = new TestDataBuilder();
const setup = (propOverrides?: Partial<TableProps>) => {
const { data, columns } = dataBuilder.build();
const props = {
data,
columns,
...propOverrides,
};
const wrapper = mount<TableProps>(<Table {...props} />);
return { props, wrapper };
};
describe('Table', () => {
describe('render', () => {
it('renders without issues', () => {
expect(() => {
setup();
}).not.toThrow();
});
describe('when simple data is passed', () => {
it('renders a table', () => {
const { wrapper } = setup();
const expected = 1;
const actual = wrapper.find('.ams-table').length;
expect(actual).toEqual(expected);
});
describe('table header', () => {
it('renders a table header', () => {
const { wrapper } = setup();
const expected = 1;
const actual = wrapper.find('.ams-table-header').length;
expect(actual).toEqual(expected);
});
it('renders a three cells inside the header', () => {
const { wrapper } = setup();
const expected = 3;
const actual = wrapper.find(
'.ams-table-header .ams-table-heading-cell'
).length;
expect(actual).toEqual(expected);
});
});
describe('table body', () => {
it('renders a table body', () => {
const { wrapper } = setup();
const expected = 1;
const actual = wrapper.find('.ams-table-body').length;
expect(actual).toEqual(expected);
});
it('renders three rows', () => {
const { wrapper } = setup();
const expected = 3;
const actual = wrapper.find('.ams-table-row').length;
expect(actual).toEqual(expected);
});
it('renders nine cells', () => {
const { wrapper } = setup();
const expected = 9;
const actual = wrapper.find('.ams-table-row .ams-table-cell').length;
expect(actual).toEqual(expected);
});
});
});
describe('when more data than columns', () => {
const { columns, data } = dataBuilder.withMoreDataThanColumns().build();
describe('table header', () => {
it('renders a three cells inside the header', () => {
const { wrapper } = setup({ columns, data });
const expected = 3;
const actual = wrapper.find(
'.ams-table-header .ams-table-heading-cell'
).length;
expect(actual).toEqual(expected);
});
});
describe('table body', () => {
it('renders four rows', () => {
const { wrapper } = setup({ columns, data });
const expected = 4;
const actual = wrapper.find('.ams-table-row').length;
expect(actual).toEqual(expected);
});
it('renders twelve cells', () => {
const { wrapper } = setup({ columns, data });
const expected = 12;
const actual = wrapper.find('.ams-table-row .ams-table-cell').length;
expect(actual).toEqual(expected);
});
});
});
});
describe('lifetime', () => {});
});
import * as React from 'react';
import './styles.scss';
export interface TableColumn {
title: string;
field: string;
horAlign?: 'left' | 'right' | 'center';
// width?: number;
// className?: string;
// sortable?: bool (false)
// data?: () => React.ReactNode ((row,index) => <div>{index}</div>)
// actions?: Action[]
}
export interface TableProps {
columns: TableColumn[];
data: [];
}
const Table: React.FC<TableProps> = ({ data, columns }: TableProps) => {
const fields = columns.map(({ field }) => field);
return (
<table className="ams-table">
<thead className="ams-table-header">
<tr>
{columns.map(({ title }, index) => {
return (
<th className="ams-table-heading-cell" key={`index:${index}`}>
{title}
</th>
);
})}
</tr>
</thead>
<tbody className="ams-table-body">
{data.map((item, index) => {
return (
<tr className="ams-table-row" key={`index:${index}`}>
{Object.entries(item)
.filter(([key]) => fields.includes(key))
.map(([, value], index) => (
<td className="ams-table-cell" key={`index:${index}`}>
{value}
</td>
))}
</tr>
);
})}
</tbody>
</table>
);
};
export default Table;
@import 'variables';
@import 'typography';
$table-header-font-size: 12px;
$table-header-line-height: 16px;
$table-header-height: 33px;
$table-header-border-width: 2px;
.ams-table {
width: 100%;
max-width: 100%;
margin-bottom: $spacer-3;
box-sizing: border-box;
}
.ams-table-header {
font-size: $table-header-font-size;
line-height: $table-header-line-height;
color: $text-secondary;
border-bottom: $table-header-border-width solid $gray15;
}
.ams-table-heading-cell {
height: $table-header-height;
text-transform: uppercase;
}
import React from 'react';
import { storiesOf } from '@storybook/react';
import StorySection from '../StorySection';
import Table from '.';
import TestDataBuilder from './testDataBuilder';
const { columns, data } = new TestDataBuilder().build();
const stories = storiesOf('Components/Table', module);
stories.add('Table', () => (
<>
<StorySection title="Basic Table">
<Table columns={columns} data={data} />
</StorySection>
</>
));
const defaultData = [
{ name: 'rowName', type: 'rowType', value: 1 },
{ name: 'rowName2', type: 'rowType2', value: 2 },
{ name: 'rowName3', type: 'rowType3', value: 3 },
];
const defaultColumns = [
{
title: 'Name',
field: 'name',
},
{
title: 'Type',
field: 'type',
},
{
title: 'Value',
field: 'value',
},
];
const initalConfig = {
data: defaultData,
columns: defaultColumns,
};
/**
* Generates test data for the table data
* @example
* let testData = new TestDataBuilder()
* .withUsageRow()
* .build();
*/
function TestDataBuilder(config = {}) {
this.Klass = TestDataBuilder;
this.config = {
...initalConfig,
...config,
};
this.withUsageRow = () => {
const attr = {
data: [
...this.config.data,
{ name: 'usageRow', type: 'usageRowType', value: 4, usage: 44 },
],
columns: [...this.config.columns, { title: 'Usage', field: 'usage' }],
};
return new this.Klass(attr);
};
this.withMoreDataThanColumns = () => {
const attr = {
data: [
...this.config.data,
{
name: 'extraName',
type: 'extraRowType',
value: 4,
usage: 44,
extraValue: 3,
},
],
columns: [...this.config.columns],
};
return new this.Klass(attr);
};
this.build = () => this.config;
}
export default TestDataBuilder;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment