Unverified Commit e73307aa authored by Marcos Iglesias's avatar Marcos Iglesias Committed by GitHub

feat: Adds ability to use custom component on table (#645)

* Adds component wrapper capabilities to columns
Adds storybook and updates caption font
Signed-off-by: 's avatarMarcos Iglesias <miglesiasvalle@lyft.com>

* Improving typing, still needs more work
Signed-off-by: 's avatarMarcos Iglesias <miglesiasvalle@lyft.com>
parent ee5e873b
...@@ -99,8 +99,8 @@ exports[`strict null compilation`] = { ...@@ -99,8 +99,8 @@ 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"], [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"] [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:1963290118": [ "js/components/common/Table/index.tsx:2876532157": [
[121, 18, 7, "Type \'unknown\' is not assignable to type \'ReactNode\'.\\n Type \'unknown\' is not assignable to type \'ReactPortal\'.", "3446393192"] [127, 18, 13, "Type \'unknown\' is not assignable to type \'ReactNode\'.\\n Type \'unknown\' is not assignable to type \'ReactPortal\'.", "971959308"]
], ],
"js/components/common/Tags/TagInput/index.tsx:3754832290": [ "js/components/common/Tags/TagInput/index.tsx:3754832290": [
[63, 22, 6, "Type \'undefined\' is not assignable to type \'GetAllTagsRequest\'.", "1979467425"], [63, 22, 6, "Type \'undefined\' is not assignable to type \'GetAllTagsRequest\'.", "1979467425"],
......
...@@ -288,6 +288,52 @@ describe('Table', () => { ...@@ -288,6 +288,52 @@ describe('Table', () => {
}); });
}); });
}); });
describe('when components are passed', () => {
describe('when one component', () => {
const {
columns,
data,
} = dataBuilder.withOneComponentColumn().build();
describe('table body', () => {
it('renders the first column as a component wrapped value', () => {
const { wrapper } = setup({
data,
columns,
});
const expected = data.length;
const actual = wrapper.find(
'.ams-table-body .ams-table-cell strong'
).length;
expect(actual).toEqual(expected);
});
});
});
describe('when multiple components per cell', () => {
const {
columns,
data,
} = dataBuilder.withMultipleComponentsColumn().build();
describe('table body', () => {
it('renders the first column as a component wrapped value', () => {
const { wrapper } = setup({
data,
columns,
});
const expected = 6;
const actual = wrapper.find(
'.ams-table-body .ams-table-cell strong'
).length;
expect(actual).toEqual(expected);
});
});
});
});
}); });
describe('options', () => { describe('options', () => {
......
...@@ -13,6 +13,7 @@ export interface TableColumn { ...@@ -13,6 +13,7 @@ export interface TableColumn {
title: string; title: string;
field: string; field: string;
horAlign?: TextAlignmentValues; horAlign?: TextAlignmentValues;
component?: (value: any) => React.ReactNode;
// className?: string; // className?: string;
// width?: number; // width?: number;
// sortable?: bool (false) // sortable?: bool (false)
...@@ -112,6 +113,11 @@ const Table: React.FC<TableProps> = ({ ...@@ -112,6 +113,11 @@ const Table: React.FC<TableProps> = ({
const cellStyle = { const cellStyle = {
textAlign: `${horAlign}` as TextAlignmentValues, textAlign: `${horAlign}` as TextAlignmentValues,
}; };
// TODO: Improve the typing of this
let cellContent: React.ReactNode | typeof value = value;
if (columnInfo && columnInfo.component) {
cellContent = columnInfo.component(value);
}
return ( return (
<td <td
...@@ -119,7 +125,7 @@ const Table: React.FC<TableProps> = ({ ...@@ -119,7 +125,7 @@ const Table: React.FC<TableProps> = ({
key={`index:${index}`} key={`index:${index}`}
style={cellStyle} style={cellStyle}
> >
{value} {cellContent}
</td> </td>
); );
})} })}
......
...@@ -5,8 +5,6 @@ ...@@ -5,8 +5,6 @@
@import 'typography'; @import 'typography';
@import 'animations'; @import 'animations';
$table-header-font-size: 12px;
$table-header-line-height: 16px;
$table-header-height: 33px; $table-header-height: 33px;
$table-header-border-width: 2px; $table-header-border-width: 2px;
...@@ -21,8 +19,8 @@ $shimmer-block-width: 40%; ...@@ -21,8 +19,8 @@ $shimmer-block-width: 40%;
} }
.ams-table-header { .ams-table-header {
font-size: $table-header-font-size; @extend %text-caption-w2;
line-height: $table-header-line-height;
color: $text-secondary; color: $text-secondary;
border-bottom: $table-header-border-width solid $gray15; border-bottom: $table-header-border-width solid $gray15;
} }
......
...@@ -14,6 +14,14 @@ const { ...@@ -14,6 +14,14 @@ const {
columns: alignedColumns, columns: alignedColumns,
data: alignedData, data: alignedData,
} = dataBuilder.withAlignedColumns().build(); } = dataBuilder.withAlignedColumns().build();
const {
columns: customColumns,
data: customColumnsData,
} = dataBuilder.withOneComponentColumn().build();
const {
columns: multipleCustomColumns,
data: multipleCustomComlumnsData,
} = dataBuilder.withMultipleComponentsColumn().build();
const stories = storiesOf('Components/Table', module); const stories = storiesOf('Components/Table', module);
...@@ -34,5 +42,19 @@ stories.add('Table', () => ( ...@@ -34,5 +42,19 @@ stories.add('Table', () => (
<StorySection title="Table with 50px row height"> <StorySection title="Table with 50px row height">
<Table columns={columns} data={data} options={{ rowHeight: 50 }} /> <Table columns={columns} data={data} options={{ rowHeight: 50 }} />
</StorySection> </StorySection>
<StorySection title="Table with custom column components">
<Table
columns={customColumns}
data={customColumnsData}
options={{ rowHeight: 40 }}
/>
</StorySection>
<StorySection title="Table with multiple custom column components">
<Table
columns={multipleCustomColumns}
data={multipleCustomComlumnsData}
options={{ rowHeight: 40 }}
/>
</StorySection>
</> </>
)); ));
// Copyright Contributors to the Amundsen project.
// SPDX-License-Identifier: Apache-2.0
import * as React from 'react';
const defaultData = [ const defaultData = [
{ name: 'rowName', type: 'rowType', value: 1 }, { name: 'rowName', type: 'rowType', value: 1 },
{ name: 'rowName2', type: 'rowType2', value: 2 }, { name: 'rowName2', type: 'rowType2', value: 2 },
...@@ -50,6 +55,57 @@ function TestDataBuilder(config = {}) { ...@@ -50,6 +55,57 @@ function TestDataBuilder(config = {}) {
return new this.Klass(attr); return new this.Klass(attr);
}; };
this.withOneComponentColumn = () => {
const attr = {
data: [...this.config.data],
columns: [
{
title: 'Name',
field: 'name',
component: (name) => <strong>{name}</strong>,
},
{
title: 'Type',
field: 'type',
},
{
title: 'Value',
field: 'value',
},
],
};
return new this.Klass(attr);
};
this.withMultipleComponentsColumn = () => {
const attr = {
data: [
{ name: 'rowName', type: 'rowType', value: [1] },
{ name: 'rowName2', type: 'rowType2', value: [2, 3] },
{ name: 'rowName3', type: 'rowType3', value: [4, 5, 6] },
],
columns: [
{
title: 'Name',
field: 'name',
},
{
title: 'Type',
field: 'type',
},
{
title: 'Value',
field: 'value',
component: (values) =>
values.map((val, i) => <strong key={`key:${val}`}>{val}</strong>),
},
],
};
return new this.Klass(attr);
};
this.withAlignedColumns = () => { this.withAlignedColumns = () => {
const attr = { const attr = {
data: [...this.config.data], data: [...this.config.data],
......
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