Skip to content

Commit 362e024

Browse files
committed
refactor: select table into list
1 parent d450bfd commit 362e024

File tree

6 files changed

+96
-119
lines changed

6 files changed

+96
-119
lines changed

packages/compass-components/src/components/select-table.spec.tsx

Lines changed: 13 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
import { expect } from 'chai';
88
import React from 'react';
99
import sinon from 'sinon';
10-
import { SelectTable } from './select-table';
10+
import { SelectList } from './select-table';
1111
import { cloneDeep } from 'lodash';
1212

1313
type TestItem = {
@@ -17,25 +17,17 @@ type TestItem = {
1717
col2: string;
1818
};
1919

20-
describe('SelectTable', function () {
20+
describe('SelectList', function () {
2121
let items: TestItem[];
22-
let columns: [key: keyof TestItem, label: string | JSX.Element][];
22+
let label: [key: keyof TestItem, label: string | JSX.Element];
2323
let onChange: sinon.SinonStub;
2424

2525
beforeEach(function () {
2626
items = [
2727
{ id: 'id1', selected: true, col1: '1x1', col2: '1x2' },
2828
{ id: 'id2', selected: true, col1: '2x1', col2: '2x2' },
2929
];
30-
columns = [
31-
['col1', 'Column1'],
32-
[
33-
'col2',
34-
<span key="" data-testid="column2-span">
35-
Column2
36-
</span>,
37-
],
38-
];
30+
label = ['col1', 'Column1'];
3931
onChange = sinon.stub();
4032
});
4133

@@ -45,19 +37,13 @@ describe('SelectTable', function () {
4537

4638
describe('render', function () {
4739
it('allows listing multiple selectable items in a table', function () {
48-
render(
49-
<SelectTable items={items} columns={columns} onChange={onChange} />
50-
);
40+
render(<SelectList items={items} label={label} onChange={onChange} />);
5141

52-
expect(screen.getByTestId('column2-span')).to.be.visible;
53-
expect(screen.getByTestId('item-id1-col1')).to.have.text('1x1');
54-
expect(screen.getByTestId('item-id1-col2')).to.have.text('1x2');
42+
expect(screen.getByLabelText('1x1')).to.be.visible;
5543
});
5644

5745
it('renders checkboxes as expected when all items are selected', function () {
58-
render(
59-
<SelectTable items={items} columns={columns} onChange={onChange} />
60-
);
46+
render(<SelectList items={items} label={label} onChange={onChange} />);
6147

6248
expect(
6349
screen.getByTestId('select-table-all-checkbox').closest('input')
@@ -80,9 +66,7 @@ describe('SelectTable', function () {
8066
it('renders checkboxes as expected when no items are selected', function () {
8167
items[0].selected = false;
8268
items[1].selected = false;
83-
render(
84-
<SelectTable items={items} columns={columns} onChange={onChange} />
85-
);
69+
render(<SelectList items={items} label={label} onChange={onChange} />);
8670

8771
expect(
8872
screen.getByTestId('select-table-all-checkbox').closest('input')
@@ -104,9 +88,7 @@ describe('SelectTable', function () {
10488

10589
it('renders checkboxes as expected when some items are selected', function () {
10690
items[0].selected = false;
107-
render(
108-
<SelectTable items={items} columns={columns} onChange={onChange} />
109-
);
91+
render(<SelectList items={items} label={label} onChange={onChange} />);
11092

11193
expect(
11294
screen.getByTestId('select-table-all-checkbox').closest('input')
@@ -131,9 +113,7 @@ describe('SelectTable', function () {
131113
it('calls onChange when a single item is selected', function () {
132114
const originalItems = cloneDeep(items);
133115
items[0].selected = false;
134-
render(
135-
<SelectTable items={items} columns={columns} onChange={onChange} />
136-
);
116+
render(<SelectList items={items} label={label} onChange={onChange} />);
137117

138118
fireEvent.click(screen.getByTestId('select-id1'));
139119
expect(onChange).to.have.been.calledWith(originalItems);
@@ -142,9 +122,7 @@ describe('SelectTable', function () {
142122
it('calls onChange when a single item is deselected', function () {
143123
const expectedItems = cloneDeep(items);
144124
items[0].selected = false;
145-
render(
146-
<SelectTable items={items} columns={columns} onChange={onChange} />
147-
);
125+
render(<SelectList items={items} label={label} onChange={onChange} />);
148126

149127
fireEvent.click(screen.getByTestId('select-id1'));
150128
expect(onChange).to.have.been.calledWith(expectedItems);
@@ -154,9 +132,7 @@ describe('SelectTable', function () {
154132
const originalItems = cloneDeep(items);
155133
items[0].selected = false;
156134
items[1].selected = false;
157-
render(
158-
<SelectTable items={items} columns={columns} onChange={onChange} />
159-
);
135+
render(<SelectList items={items} label={label} onChange={onChange} />);
160136

161137
fireEvent.click(screen.getByTestId('select-table-all-checkbox'));
162138
expect(onChange).to.have.been.calledWith(originalItems);
@@ -166,9 +142,7 @@ describe('SelectTable', function () {
166142
const expectedItems = cloneDeep(items);
167143
items[0].selected = false;
168144
items[1].selected = false;
169-
render(
170-
<SelectTable items={items} columns={columns} onChange={onChange} />
171-
);
145+
render(<SelectList items={items} label={label} onChange={onChange} />);
172146

173147
fireEvent.click(screen.getByTestId('select-table-all-checkbox'));
174148
expect(onChange).to.have.been.calledWith(expectedItems);
Lines changed: 68 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,56 @@
11
import React, { useCallback } from 'react';
2-
import {
3-
Cell,
4-
Checkbox,
5-
HeaderCell,
6-
HeaderRow,
7-
Row,
8-
Table,
9-
TableBody,
10-
TableHead,
11-
} from './leafygreen';
2+
import { Checkbox } from './leafygreen';
123
import { spacing } from '@leafygreen-ui/tokens';
13-
import { css } from '@leafygreen-ui/emotion';
4+
import { css, cx } from '@leafygreen-ui/emotion';
5+
import { palette } from '@leafygreen-ui/palette';
6+
import { useDarkMode } from '../hooks/use-theme';
147

158
const checkboxStyles = css({
169
padding: spacing[100],
1710
});
1811

12+
const containerStyles = css({
13+
display: 'flex',
14+
flexDirection: 'column',
15+
});
16+
17+
const listHeaderStyles = css({
18+
display: 'flex',
19+
alignItems: 'center',
20+
fontWeight: 600,
21+
borderBottom: `${spacing[100]}px solid ${palette.gray.light2}`,
22+
flexShrink: 0,
23+
padding: `${spacing[100]}px 0px`,
24+
});
25+
const listBodyStyles = css({
26+
overflow: 'auto',
27+
});
28+
const listItemStyles = css({
29+
padding: `${spacing[100]}px 0px`,
30+
});
31+
1932
type SelectItem = {
2033
id: string;
2134
selected: boolean;
2235
};
2336

24-
type SelectTableProps<T extends SelectItem> = {
37+
type SelectListProps<T extends SelectItem> = {
2538
items: T[];
26-
columns: ReadonlyArray<
27-
readonly [key: string & keyof T, label: string | JSX.Element]
28-
>;
39+
label: readonly [key: string & keyof T, label: string | JSX.Element];
2940
onChange: (newList: T[]) => void;
3041
disabled?: boolean;
3142
className?: string;
3243
};
3344

34-
export function SelectTable<T extends SelectItem>(
35-
props: SelectTableProps<T>
45+
export function SelectList<T extends SelectItem>(
46+
props: SelectListProps<T>
3647
): React.ReactElement {
37-
const { items, columns, disabled, onChange } = props;
48+
const { items, label, disabled, onChange } = props;
49+
50+
const isDarkMode = useDarkMode();
51+
const evenRowStyles = isDarkMode
52+
? css({ backgroundColor: palette.gray.dark3 })
53+
: css({ backgroundColor: palette.gray.light3 });
3854

3955
const selectAll = items.every((item) => item.selected);
4056
const selectNone = items.every((item) => !item.selected);
@@ -61,53 +77,40 @@ export function SelectTable<T extends SelectItem>(
6177
);
6278

6379
return (
64-
<div className={props.className}>
65-
<Table shouldAlternateRowColor>
66-
<TableHead>
67-
<HeaderRow>
68-
<HeaderCell key="select-table-all-checkbox">
69-
<Checkbox
70-
className={checkboxStyles}
71-
data-testid="select-table-all-checkbox"
72-
aria-label="Select all"
73-
onChange={handleSelectAllChange}
74-
checked={selectAll}
75-
indeterminate={!selectAll && !selectNone}
76-
disabled={disabled}
77-
/>
78-
</HeaderCell>
79-
{columns.map((col) => (
80-
<HeaderCell key={`col-${col[0]}`}>{col[1]}</HeaderCell>
81-
))}
82-
</HeaderRow>
83-
</TableHead>
84-
<TableBody>
85-
{items.map((item) => (
86-
<Row key={item.id}>
87-
<Cell>
88-
<Checkbox
89-
className={checkboxStyles}
90-
key={`select-${item.id}`}
91-
name={`select-${item.id}`}
92-
data-testid={`select-${item.id}`}
93-
aria-label="Select item in row"
94-
onChange={handleSelectItemChange}
95-
checked={item.selected}
96-
disabled={disabled}
97-
/>
98-
</Cell>
99-
{columns.map(([name]) => (
100-
<Cell
101-
key={`item-${name}`}
102-
data-testid={`item-${item.id}-${name}`}
103-
>
104-
{item[name]}
105-
</Cell>
106-
))}
107-
</Row>
108-
))}
109-
</TableBody>
110-
</Table>
80+
<div className={cx(props.className, containerStyles)}>
81+
<div className={listHeaderStyles}>
82+
<Checkbox
83+
className={cx(checkboxStyles, css({ paddingRight: 0 }))}
84+
data-testid="select-table-all-checkbox"
85+
aria-label="Select all"
86+
onChange={handleSelectAllChange}
87+
checked={selectAll}
88+
indeterminate={!selectAll && !selectNone}
89+
disabled={disabled}
90+
/>
91+
<div className={css({ lineHeight: '16px' })}>{label[1]}</div>
92+
</div>
93+
<div className={listBodyStyles}>
94+
{items.map((item, index) => (
95+
<div
96+
className={cx(listItemStyles, index % 2 === 0 && evenRowStyles)}
97+
key={`select-table-item-${item.id}`}
98+
data-testid={`select-table-item-${item.id}`}
99+
>
100+
<Checkbox
101+
className={checkboxStyles}
102+
key={`select-${item.id}`}
103+
name={`select-${item.id}`}
104+
data-testid={`select-${item.id}`}
105+
label={item[label[0]]}
106+
aria-label={`Select ${item[label[0]]}`}
107+
onChange={handleSelectItemChange}
108+
checked={item.selected}
109+
disabled={disabled}
110+
/>
111+
</div>
112+
))}
113+
</div>
111114
</div>
112115
);
113116
}

packages/compass-components/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,4 +210,4 @@ export {
210210
type VirtualListProps,
211211
type ItemRenderer as VirtualListItemRenderer,
212212
} from './components/virtual-list';
213-
export { SelectTable } from './components/select-table';
213+
export { SelectList } from './components/select-table';

packages/compass-connection-import-export/src/components/export-modal.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
FormFieldContainer,
77
FormModal,
88
openToast,
9-
SelectTable,
9+
SelectList,
1010
} from '@mongodb-js/compass-components';
1111
import { FileInput } from './file-input';
1212
import { Passphrase } from './passphrase';
@@ -21,7 +21,7 @@ const tableStyles = css({
2121
overflow: 'auto',
2222
});
2323

24-
const selectTableColumns = [['name', 'Connection Name']] as const;
24+
const SelectListLabel = ['name', 'Connection Name'] as const;
2525

2626
export function ExportConnectionsModal({
2727
open,
@@ -97,10 +97,10 @@ export function ExportConnectionsModal({
9797
}
9898
data-testid="connection-export-modal"
9999
>
100-
<SelectTable
100+
<SelectList
101101
className={tableStyles}
102102
items={connectionList}
103-
columns={selectTableColumns}
103+
label={SelectListLabel}
104104
disabled={inProgress}
105105
onChange={onChangeConnectionList}
106106
/>

packages/compass-connection-import-export/src/components/import-modal.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
FormModal,
88
spacing,
99
openToast,
10-
SelectTable,
10+
SelectList,
1111
} from '@mongodb-js/compass-components';
1212
import { FileInput } from './file-input';
1313
import { Passphrase } from './passphrase';
@@ -26,7 +26,7 @@ const existingFavoriteBadgeStyles = css({
2626
marginLeft: spacing[200],
2727
});
2828

29-
const selectTableColumns = [['displayName', 'Connection Name']] as const;
29+
const SelectListLabel = ['displayName', 'Connection Name'] as const;
3030

3131
export function ImportConnectionsModal({
3232
open,
@@ -136,10 +136,10 @@ export function ImportConnectionsModal({
136136
/>
137137
</FormFieldContainer>
138138
{connectionList.length > 0 && (
139-
<SelectTable
139+
<SelectList
140140
className={tableStyles}
141141
items={displayConnectionList}
142-
columns={selectTableColumns}
142+
label={SelectListLabel}
143143
disabled={inProgress}
144144
onChange={onChangeConnectionList}
145145
/>

0 commit comments

Comments
 (0)