in ts/webui/src/components/trial-detail/TableList.tsx [207:402]
private _buildColumnsFromTableItems(tableItems: any[]): IColumn[] {
const columns: IColumn[] = [
// select trial function
{
name: '',
key: '_selected',
fieldName: 'selected',
minWidth: 20,
maxWidth: 20,
isResizable: true,
className: 'detail-table',
onRender: (record): React.ReactNode => (
<Checkbox
label={undefined}
checked={record._checked}
className='detail-check'
onChange={this.selectedTrialOnChangeEvent.bind(this, record.id)}
/>
)
},
// extra column, for a icon to expand the trial details panel
{
key: '_expand',
name: '',
onRender: (item): any => {
return (
<Icon
aria-hidden={true}
iconName='ChevronRight'
className='cursor'
styles={{
root: {
transition: 'all 0.2s',
transform: `rotate(${item._expandDetails ? 90 : 0}deg)`
}
}}
onClick={(event): void => {
event.stopPropagation();
const newItem: any = { ...item, _expandDetails: !item._expandDetails };
if (newItem._expandDetails) {
// preserve to be restored when refreshed
this._expandedTrialIds.add(newItem.id);
} else {
this._expandedTrialIds.delete(newItem.id);
}
const newItems = this.state.displayedItems.map(item =>
item.id === newItem.id ? newItem : item
);
this.setState({
displayedItems: newItems
});
}}
onMouseDown={(e): void => {
e.stopPropagation();
}}
onMouseUp={(e): void => {
e.stopPropagation();
}}
/>
);
},
fieldName: 'expand',
isResizable: false,
minWidth: 20,
maxWidth: 20
}
];
// looking at the first row only for now
for (const k of Object.keys(tableItems[0])) {
if (k === 'metric/default') {
// FIXME: default metric is hacked as latestAccuracy currently
continue;
}
const columnTitle = _inferColumnTitle(k);
// TODO: add blacklist
// 0.85: tableWidth / screen
const widths = window.innerWidth * 0.85;
columns.push({
name: columnTitle,
key: k,
fieldName: k,
minWidth: widths * 0.12,
maxWidth: widths * 0.19,
isResizable: true,
onColumnClick: this._onColumnClick.bind(this),
...(k === 'status' && {
// color status
onRender: (record): React.ReactNode => (
<span className={`${record.status} commonStyle`}>{record.status}</span>
)
}),
...(k === 'message' && {
onRender: (record): React.ReactNode =>
record.message.length > 15 ? (
<TooltipHost
content={record.message}
directionalHint={DirectionalHint.bottomCenter}
tooltipProps={{
calloutProps: {
styles: {
beak: { background: TOOLTIP_BACKGROUND_COLOR },
beakCurtain: { background: TOOLTIP_BACKGROUND_COLOR },
calloutMain: { background: TOOLTIP_BACKGROUND_COLOR }
}
}
}}
>
<div>{record.message}</div>
</TooltipHost>
) : (
<div>{record.message}</div>
)
}),
...((k.startsWith('metric/') || k.startsWith('space/')) && {
// show tooltip
onRender: (record): React.ReactNode => (
<TooltipHost
content={record[k]}
directionalHint={DirectionalHint.bottomCenter}
tooltipProps={{
calloutProps: {
styles: {
beak: { background: TOOLTIP_BACKGROUND_COLOR },
beakCurtain: { background: TOOLTIP_BACKGROUND_COLOR },
calloutMain: { background: TOOLTIP_BACKGROUND_COLOR }
}
}
}}
>
<div className='ellipsis'>{record[k]}</div>
</TooltipHost>
)
}),
...(k === 'latestAccuracy' && {
// FIXME: this is ad-hoc
onRender: (record): React.ReactNode => (
<TooltipHost
content={record._formattedLatestAccuracy}
directionalHint={DirectionalHint.bottomCenter}
tooltipProps={{
calloutProps: {
styles: {
beak: { background: TOOLTIP_BACKGROUND_COLOR },
beakCurtain: { background: TOOLTIP_BACKGROUND_COLOR },
calloutMain: { background: TOOLTIP_BACKGROUND_COLOR }
}
}
}}
>
<div className='ellipsis'>{record._formattedLatestAccuracy}</div>
</TooltipHost>
)
}),
...(['startTime', 'endTime'].includes(k) && {
onRender: (record): React.ReactNode => <span>{formatTimestamp(record[k], '--')}</span>
}),
...(k === 'duration' && {
onRender: (record): React.ReactNode => (
<span className='durationsty'>{convertDuration(record[k])}</span>
)
}),
...(k === 'id' && {
onRender: (record): React.ReactNode => (
<Stack horizontal className='idCopy'>
<div>{record.id}</div>
<CopyButton value={record.id} />
</Stack>
)
})
});
}
// operations column
columns.push({
name: 'Operation',
key: '_operation',
fieldName: 'operation',
minWidth: 150,
maxWidth: 160,
isResizable: true,
className: 'detail-table',
onRender: this._renderOperationColumn.bind(this)
});
const { sortInfo } = this.state;
for (const column of columns) {
if (column.key === sortInfo.field) {
column.isSorted = true;
column.isSortedDescending = sortInfo.isDescend;
} else {
column.isSorted = false;
column.isSortedDescending = true;
}
}
return columns;
}