SuccessTable.tsx 6.64 KB
Newer Older
Lijiao's avatar
Lijiao committed
1
import * as React from 'react';
Lijiaoa's avatar
Lijiaoa committed
2
3
4
5
6
7
8
9
10
11
12
import {
    DetailsList,
    IDetailsListProps,
    IColumn,
    IRenderFunction,
    IDetailsHeaderProps,
    Sticky,
    StickyPositionType,
    ScrollablePane,
    ScrollbarVisibility
} from '@fluentui/react';
13
import DefaultMetric from '../../public-child/DefaultMetric';
14
import Details from './Details';
15
16
17
18
19
20
import { convertDuration } from '../../../static/function';
import { TRIALS } from '../../../static/datamodel';
import { DETAILTABS } from '../../stateless-component/NNItabs';
import '../../../static/style/succTable.scss';
import '../../../static/style/tableStatus.css';
import '../../../static/style/openRow.scss';
Lijiao's avatar
Lijiao committed
21
22

interface SuccessTableProps {
23
    trialIds: string[];
Lijiao's avatar
Lijiao committed
24
25
}

26
27
28
interface SuccessTableState {
    columns: IColumn[];
    source: Array<any>;
29
    innerWidth: number;
30
}
Lijiao's avatar
Lijiao committed
31

32
class SuccessTable extends React.Component<SuccessTableProps, SuccessTableState> {
Lijiao's avatar
Lijiao committed
33
34
    constructor(props: SuccessTableProps) {
        super(props);
35
36
37
38
39
        this.state = {
            columns: this.columns,
            source: TRIALS.table(this.props.trialIds),
            innerWidth: window.innerWidth
        };
Lijiao's avatar
Lijiao committed
40
41
    }

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
    private onRenderRow: IDetailsListProps['onRenderRow'] = props => {
        if (props) {
            return <Details detailsProps={props} />;
        }
        return null;
    };

    onColumnClick = (ev: React.MouseEvent<HTMLElement>, getColumn: IColumn): void => {
        const { columns, source } = this.state;
        const newColumns: IColumn[] = columns.slice();
        const currColumn: IColumn = newColumns.filter(item => getColumn.key === item.key)[0];
        newColumns.forEach((newCol: IColumn) => {
            if (newCol === currColumn) {
                currColumn.isSortedDescending = !currColumn.isSortedDescending;
                currColumn.isSorted = true;
            } else {
                newCol.isSorted = false;
                newCol.isSortedDescending = true;
Lijiao's avatar
Lijiao committed
60
            }
61
62
63
64
65
66
67
68
69
70
71
72
73
74
        });
        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
        const newItems = this.copyAndSort(source, currColumn.fieldName!, currColumn.isSortedDescending);
        this.setState({
            columns: newColumns,
            source: newItems
        });
    };

    private copyAndSort<T>(items: T[], columnKey: string, isSortedDescending?: boolean): T[] {
        const key = columnKey as keyof T;
        return items.slice(0).sort((a: T, b: T) => ((isSortedDescending ? a[key] < b[key] : a[key] > b[key]) ? 1 : -1));
    }

75
    tooltipStr = (
76
77
78
79
        <React.Fragment>
            The experiment is running, please wait for the final metric patiently. You could also find status of trial
            job with <span>{DETAILTABS}</span> button.
        </React.Fragment>
80
    );
81

82
83
84
85
86
    columns = [
        {
            name: 'Trial No.',
            key: 'sequenceId',
            fieldName: 'sequenceId', // required!
Lijiaoa's avatar
Lijiaoa committed
87
88
            minWidth: 65,
            maxWidth: 119,
89
            isResizable: true,
90
            data: 'number',
91
92
            onColumnClick: this.onColumnClick,
            onRender: (item: any): React.ReactNode => <div className='succeed-padding'>{item.sequenceId}</div>
93
94
        },
        {
95
96
97
            name: 'ID',
            key: 'id',
            fieldName: 'id',
Lijiaoa's avatar
Lijiaoa committed
98
99
            minWidth: 65,
            maxWidth: 119,
100
            isResizable: true,
101
102
            className: 'tableHead leftTitle',
            data: 'string',
103
104
            onColumnClick: this.onColumnClick,
            onRender: (item: any): React.ReactNode => <div className='succeed-padding'>{item.id}</div>
105
106
        },
        {
107
108
            name: 'Duration',
            key: 'duration',
Lijiaoa's avatar
Lijiaoa committed
109
110
            minWidth: 90,
            maxWidth: 166,
111
            isResizable: true,
112
113
114
            fieldName: 'duration',
            data: 'number',
            onColumnClick: this.onColumnClick,
115
            onRender: (item: any): React.ReactNode => (
116
                <div className='durationsty succeed-padding'>
117
118
119
120
121
                    <div>{convertDuration(item.duration)}</div>
                </div>
            )
        },
        {
122
123
            name: 'Status',
            key: 'status',
Lijiaoa's avatar
Lijiaoa committed
124
125
            minWidth: 108,
            maxWidth: 160,
126
            isResizable: true,
127
            fieldName: 'status',
128
129
130
            onRender: (item: any): React.ReactNode => (
                <div className={`${item.status} commonStyle succeed-padding`}>{item.status}</div>
            )
131
132
        },
        {
133
134
135
            name: 'Default metric',
            key: 'accuracy',
            fieldName: 'accuracy',
Lijiaoa's avatar
Lijiaoa committed
136
137
            minWidth: 108,
            maxWidth: 166,
138
            isResizable: true,
139
140
            data: 'number',
            onColumnClick: this.onColumnClick,
141
            onRender: (item: any): React.ReactNode => <DefaultMetric trialId={item.id} />
142
143
144
        }
    ];

Lijiaoa's avatar
Lijiaoa committed
145
146
147
148
149
150
151
152
153
154
155
156
157
158
    onRenderDetailsHeader: IRenderFunction<IDetailsHeaderProps> = (props, defaultRender) => {
        if (!props) {
            return null;
        }
        return (
            <Sticky stickyPosition={StickyPositionType.Header} isScrollSynced>
                {// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
                defaultRender!({
                    ...props
                })}
            </Sticky>
        );
    };

159
160
161
162
163
164
165
166
167
168
169
    setInnerWidth = (): void => {
        this.setState(() => ({ innerWidth: window.innerWidth }));
    };

    componentDidMount(): void {
        window.addEventListener('resize', this.setInnerWidth);
    }
    componentWillUnmount(): void {
        window.removeEventListener('resize', this.setInnerWidth);
    }

170
    componentDidUpdate(prevProps: SuccessTableProps): void {
171
        if (this.props.trialIds !== prevProps.trialIds) {
172
173
174
            const { trialIds } = this.props;
            this.setState(() => ({ source: TRIALS.table(trialIds) }));
        }
Lijiaoa's avatar
Lijiaoa committed
175
176
    }

177
178
    render(): React.ReactNode {
        const { columns, source } = this.state;
179
        const isNoneData = source.length === 0 ? true : false;
180

Lijiao's avatar
Lijiao committed
181
        return (
182
            <div id='succTable'>
Lijiaoa's avatar
Lijiaoa committed
183
184
185
186
187
188
189
190
191
192
193
194
                <ScrollablePane className='scrollPanel' scrollbarVisibility={ScrollbarVisibility.auto}>
                    <DetailsList
                        columns={columns}
                        items={source}
                        setKey='set'
                        compact={true}
                        onRenderRow={this.onRenderRow}
                        onRenderDetailsHeader={this.onRenderDetailsHeader}
                        selectionMode={0} // close selector function
                        className='succTable'
                    />
                </ScrollablePane>
195
                {isNoneData && <div className='succTable-tooltip'>{this.tooltipStr}</div>}
196
            </div>
Lijiao's avatar
Lijiao committed
197
198
199
        );
    }
}
200
201

export default SuccessTable;