• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sangupta / bedrock / 4360887097

08 Mar 2023 03:34AM CUT coverage: 80.687% (+14.5%) from 66.224%
4360887097

push

github

Sandeep Gupta
export all prop interfaces

121 of 129 branches covered (93.8%)

Branch coverage included in aggregate %.

5185 of 6447 relevant lines covered (80.43%)

1.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

50.0
/src/components/data/DataTable.tsx
1
/**
1✔
2
 * bedrock - UI Component Library
1✔
3
 * https://github.com/sangupta/bedrock
1✔
4
 *
1✔
5
 * MIT License.
1✔
6
 * Copyright (c) 2022, Sandeep Gupta.
1✔
7
 *
1✔
8
 * Use of this source code is governed by a MIT style license
1✔
9
 * that can be found in LICENSE file in the code repository.
1✔
10
 */
1✔
11

1✔
12
import React from 'react';
1✔
13
import TimeAgo from '../content/TimeAgo';
1✔
14
import ByteSize from '../content/ByteSize';
1✔
15
import DateTime from '../content/DateTime';
1✔
16
import { BaseProps } from '../../types';
1✔
17
import { DataColumnFormat, DataColumnType, ValueType } from './Data';
1✔
18

1✔
19
/**
1✔
20
 * PROP attributes for DataTable component.
1✔
21
 */
1✔
22
export interface DataTableProps {
1✔
23
    /**
1✔
24
     * The columns to be displayed in the data table.
1✔
25
     */
1✔
26
    columns: Array<DataColumnFormat>;
1✔
27

1✔
28
    /**
1✔
29
     * The attribute in one object of the `data` array that will
1✔
30
     * be used as the primary key when rendering.
1✔
31
     */
1✔
32
    rowKeyAttribute: string;
1✔
33

1✔
34
    /**
1✔
35
     * The data to be displayed in the table
1✔
36
     */
1✔
37
    data: Array<any>;
1✔
38

1✔
39
    /**
1✔
40
     * Do we need to display the header row?
1✔
41
     */
1✔
42
    hideHeaderRow?: boolean;
1✔
43

1✔
44
    /**
1✔
45
     * When a row is clicked
1✔
46
     */
1✔
47
    onRowClick?: (item: any) => void;
1✔
48

1✔
49
    /**
1✔
50
     * When a row is double clicked
1✔
51
     */
1✔
52
    onRowDoubleClick?: (item: any) => void;
1✔
53

1✔
54
    /**
1✔
55
     * Return the icon for one item/one row
1✔
56
     */
1✔
57
    getIconForItem?: (item: any) => React.ReactNode;
1✔
58

1✔
59
    /**
1✔
60
     * Currently selected item
1✔
61
     */
1✔
62
    selectedRow?: any;
1✔
63
}
1✔
64

1✔
65
/**
1✔
66
 * STATE attributes for DataTable component.
1✔
67
 */
1✔
68
interface DataTableState {
1✔
69

1✔
70
}
1✔
71

1✔
72
/**
1✔
73
 * Component to render a generic data table. Consider this as
1✔
74
 * a replacement to the `table` HTML tag. The data table uses
1✔
75
 * `grid` layout and supports the following features:
1✔
76
 * 
1✔
77
 * * capture click/double-click on data row
1✔
78
 * * can render icons based on attributes
1✔
79
 * * support for data formatting
1✔
80
 * 
1✔
81
 * @author sangupta
1✔
82
 */
1✔
83
export default class DataTable extends React.Component<DataTableProps, DataTableState> {
1✔
84

1✔
85
    /**
1✔
86
     * Render only the heading.
1✔
87
     * 
1✔
88
     * @param columns 
1✔
89
     * @returns 
1✔
90
     */
1✔
91
    renderHeading(columns: Array<DataColumnFormat>) {
1✔
92
        if (!!this.props.hideHeaderRow) {
×
93
            return null;
×
94
        }
×
95

×
96
        const result: any = [];
×
97

×
98
        (columns || []).forEach((item, index) => {
×
99
            result.push(
×
100
                <div key={item.title} className='data-table-col' style={{ gridColumnStart: index + 1 }}>{item.title}</div>
×
101
            );
×
102
        });
×
103

×
104
        return <div className='data-table-row-header'>{result}</div>
×
105
    }
×
106

1✔
107
    /**
1✔
108
     * Render all data rows.
1✔
109
     * 
1✔
110
     * @param format 
1✔
111
     * @param data 
1✔
112
     * @param rowKeyAttribute 
1✔
113
     * @returns 
1✔
114
     */
1✔
115
    renderData = (format: Array<DataColumnFormat>, data: Array<any>, rowKeyAttribute: string) => {
1✔
116
        const result: any = [];
×
117

×
118
        data.forEach((item, index) => {
×
119
            const itemID = item[rowKeyAttribute];
×
120

×
121
            result.push(
×
122
                <DataTableRow
×
123
                    className={this.props.selectedRow === item ? 'selected' : ''}
×
124
                    key={itemID || index}
×
125
                    rowKey={itemID || index}
×
126
                    dataRow={item}
×
127
                    onRowClick={this.props.onRowClick}
×
128
                    onRowDoubleClick={this.props.onRowDoubleClick} >
×
129
                    {this.renderDataRow(item, format)}
×
130
                </DataTableRow>
×
131
            );
×
132
        })
×
133

×
134
        return result;
×
135
    }
×
136

×
137
    /**
×
138
     * Render a single data row.
×
139
     * 
×
140
     * @param row 
×
141
     * @param formats 
×
142
     * @returns 
×
143
     */
×
144
    renderDataRow(row: any, formats: Array<DataColumnFormat>) {
×
145
        const columns: any = [];
×
146

×
147
        if (!formats || formats.length === 0) {
×
148
            return columns;
×
149
        }
×
150

×
151
        formats.forEach((format, index) => {
×
152
            let columnValue = format.attributeName
×
153
                ? row[format.attributeName]
×
154
                : format.getValue ? format.getValue(row) : row;
×
155

×
156
            // choose formatter based on field type
×
157
            if (format.formatAs) {
×
158
                columnValue = this.formatValue(format.formatAs, format.valueType || '', columnValue);
×
159
            }
×
160

×
161
            const addOnClass = format.className ? ' ' + format.className : '';
×
162
            columns.push(
×
163
                <div key={format.title || ('col-' + index)} className={'data-table-col' + addOnClass} style={{ gridColumnStart: (index + 1) }}>
×
164
                    {columnValue}
×
165
                </div>
×
166
            )
×
167
        });
×
168

×
169
        return columns;
×
170
    }
×
171

×
172
    /**
×
173
     * Format the column value based on its format and value type.
×
174
     * 
×
175
     * @param formatAs 
×
176
     * @param valueType 
×
177
     * @param value 
×
178
     * @returns 
×
179
     */
×
180
    formatValue = (formatAs: DataColumnType, valueType: ValueType, value: any) => {
×
181
        if (!formatAs) {
×
182
            return value;
×
183
        }
×
184

×
185
        switch (formatAs) {
×
186
            case 'string':
×
187
                return '' + value;
×
188

×
189
            case 'bytes':
×
190
                return <ByteSize bytes={value} />
×
191

×
192
            case 'date':
×
193
            case 'date-time':
×
194
            case 'time':
×
195
                return <DateTime value={value} type={formatAs} valueType={valueType} />
×
196

×
197
            case 'time-ago':
×
198
                if ((valueType || '').toLowerCase() === 'seconds') {
×
199
                    value = value * 1000;
×
200
                }
×
201
                return <TimeAgo millis={value} />
×
202

×
203
            case 'icon':
×
204
                return this.props.getIconForItem ? this.props.getIconForItem(value) : ''
×
205

×
206
            default:
×
207
                return value;
×
208
        }
×
209
    }
×
210

1✔
211
    /**
1✔
212
     * Render the data table.
1✔
213
     *
1✔
214
     * @returns 
1✔
215
     */
1✔
216
    render(): React.ReactNode {
1✔
217
        const { data, columns, rowKeyAttribute } = this.props;
×
218
        if (!data || data.length == 0) {
×
219
            return null;
×
220
        }
×
221

×
222
        return <div className='data-table' role='grid'>
×
223
            {this.renderHeading(columns)}
×
224
            {this.renderData(columns, data, rowKeyAttribute)}
×
225
        </div>
×
226
    }
×
227

1✔
228
}
1✔
229

1✔
230
/**
1✔
231
 * Prop attributes for DataTableRow component.
1✔
232
 */
1✔
233
interface DataTableRowProps extends BaseProps {
1✔
234
    rowKey: string;
1✔
235
    dataRow: any;
1✔
236
    className?: string;
1✔
237
    onRowClick?: (dataRow: any) => void;
1✔
238
    onRowDoubleClick?: (dataRow: any) => void;
1✔
239
}
1✔
240

1✔
241
/**
1✔
242
 * Represents a row in the data table.
1✔
243
 */
1✔
244
class DataTableRow extends React.Component<DataTableRowProps> {
1✔
245

1✔
246
    handleRowClick = () => {
1✔
247
        if (this.props.onRowClick) {
×
248
            this.props.onRowClick(this.props.dataRow);
×
249
        }
×
250
    }
×
251

×
252
    handleRowDoubleClick = () => {
×
253
        if (this.props.onRowDoubleClick) {
×
254
            this.props.onRowDoubleClick(this.props.dataRow);
×
255
        }
×
256
    }
×
257

1✔
258
    render(): React.ReactNode {
1✔
259
        return <div data-rowid={this.props.rowKey} className={'data-table-row ' + (this.props.className || '')} onClick={this.handleRowClick} onDoubleClick={this.handleRowDoubleClick}>
×
260
            {this.props.children}
×
261
        </div>
×
262
    }
×
263

1✔
264
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc