Line data Source code
1 : import * as arrow from 'apache-arrow';
2 : import * as React from 'react';
3 : import * as styles from './data_table.module.css';
4 : import symbols from '@ankoh/dashql-svg-symbols';
5 :
6 : import { classNames } from '../../utils/classnames.js';
7 : import { ButtonSize, ButtonVariant, IconButton } from '../../ui/foundations/button.js';
8 : import { DataFrame } from '../../compute/data_frame.js';
9 : import { DataTableLayout } from './data_table_layout.js';
10 : import { arePropsEqualWithStyle } from './memo_props.js';
11 :
12 : /// ---------------------------------------------------------------------------
13 : /// Header Name Cell
14 : /// ---------------------------------------------------------------------------
15 :
16 : export interface HeaderNameCellProps {
17 : columnIndex: number;
18 : style: React.CSSProperties;
19 : table: arrow.Table;
20 : gridLayout: DataTableLayout;
21 : dataFrame: DataFrame | null;
22 : rightmostVisibleColumn: number;
23 : sortAscending: boolean | null;
24 : onOrderByColumn: (col: number) => void;
25 : onShowTable?: () => void;
26 : }
27 :
28 1 : function HeaderNameCellImpl(props: HeaderNameCellProps): React.ReactElement {
29 1 : if (props.columnIndex >= props.gridLayout.arrowFieldByColumnIndex.length) {
30 0 : return <div style={props.style} />;
31 : }
32 1 : const fieldId = props.gridLayout.arrowFieldByColumnIndex[props.columnIndex];
33 1 : const fieldName = props.table.schema.fields[fieldId].name;
34 1 : const isSorted = props.sortAscending != null;
35 1 : const sortState = props.sortAscending == null ? 'unsorted' : (props.sortAscending ? 'ascending' : 'descending');
36 1 : const sortLabel = `Sort ${fieldName}; currently ${sortState}`;
37 1 : const sortIcon = props.sortAscending === false ? 'sort_desc_16' : 'sort_asc_16';
38 1 : const sortButtonVariant = isSorted ? ButtonVariant.Default : ButtonVariant.Invisible;
39 :
40 1 : if (props.columnIndex == 0) {
41 : // Corner cell (top-left)
42 1 : return (
43 1 : <div className={classNames(styles.header_corner_cell, { [styles.header_cell_clickable]: props.onShowTable != null })} style={props.style} onClick={props.onShowTable}>
44 1 : <span className={styles.header_cell_actions}>
45 1 : <IconButton
46 1 : variant={sortButtonVariant}
47 1 : size={ButtonSize.Small}
48 1 : aria-label={sortLabel}
49 1 : onClick={(e) => { e.stopPropagation(); props.onOrderByColumn(fieldId); }}
50 1 : disabled={props.dataFrame == null}
51 : >
52 1 : <svg width="16px" height="16px">
53 1 : <use xlinkHref={`${symbols}#${sortIcon}`} />
54 1 : </svg>
55 1 : </IconButton>
56 1 : </span>
57 1 : </div>
58 : );
59 1 : } else {
60 : // Regular header cell
61 1 : const isRightmost = props.columnIndex === props.rightmostVisibleColumn;
62 1 : return (
63 1 : <div
64 1 : className={classNames(styles.header_cell, {
65 1 : [styles.header_metadata_cell]: props.gridLayout.isSystemColumn[props.columnIndex] == 1,
66 1 : [styles.header_cell_rightmost]: isRightmost,
67 1 : [styles.header_cell_clickable]: props.onShowTable != null,
68 1 : })}
69 1 : style={props.style}
70 1 : onClick={props.onShowTable}
71 : >
72 1 : <span className={styles.header_cell_name}>
73 1 : {fieldName}
74 1 : </span>
75 1 : <span className={styles.header_cell_actions}>
76 1 : <IconButton
77 1 : variant={sortButtonVariant}
78 1 : size={ButtonSize.Small}
79 1 : aria-label={sortLabel}
80 1 : onClick={(e) => { e.stopPropagation(); props.onOrderByColumn(fieldId); }}
81 1 : disabled={props.dataFrame == null}
82 : >
83 1 : <svg width="16px" height="16px">
84 1 : <use xlinkHref={`${symbols}#${sortIcon}`} />
85 1 : </svg>
86 1 : </IconButton>
87 1 : </span>
88 1 : </div>
89 : );
90 1 : }
91 1 : }
92 :
93 1 : export const HeaderNameCell = React.memo(HeaderNameCellImpl, arePropsEqualWithStyle);
|