@patternfly/react-table 4.44.11 → 4.44.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/dist/esm/components/Table/Table.d.ts +2 -1
- package/dist/esm/components/Table/Table.d.ts.map +1 -1
- package/dist/esm/components/Table/Table.js.map +1 -1
- package/dist/esm/components/Table/TableTypes.d.ts +2 -1
- package/dist/esm/components/Table/TableTypes.d.ts.map +1 -1
- package/dist/esm/components/Table/TableTypes.js.map +1 -1
- package/dist/esm/components/Table/base/provider.d.ts +2 -2
- package/dist/esm/components/Table/base/types.d.ts +2 -2
- package/dist/esm/components/TableComposable/TableComposable.d.ts +1 -1
- package/dist/esm/components/TableComposable/Td.d.ts +1 -1
- package/dist/js/components/Table/Table.d.ts +2 -1
- package/dist/js/components/Table/Table.d.ts.map +1 -1
- package/dist/js/components/Table/Table.js.map +1 -1
- package/dist/js/components/Table/TableTypes.d.ts +2 -1
- package/dist/js/components/Table/TableTypes.d.ts.map +1 -1
- package/dist/js/components/Table/TableTypes.js.map +1 -1
- package/dist/js/components/Table/base/provider.d.ts +2 -2
- package/dist/js/components/Table/base/types.d.ts +2 -2
- package/dist/js/components/TableComposable/TableComposable.d.ts +1 -1
- package/dist/js/components/TableComposable/Td.d.ts +1 -1
- package/package.json +6 -6
- package/src/components/Table/Table.tsx +2 -1
- package/src/components/Table/TableTypes.tsx +2 -1
- package/src/components/Table/examples/LegacyTableActions.tsx +218 -0
- package/src/components/Table/examples/LegacyTableBasic.tsx +90 -0
- package/src/components/Table/examples/LegacyTableCellWidth.tsx +66 -0
- package/src/components/Table/examples/LegacyTableCompoundExpandable.tsx +175 -0
- package/src/components/Table/examples/LegacyTableControllingText.tsx +51 -0
- package/src/components/Table/examples/LegacyTableEmptyState.tsx +48 -0
- package/src/components/Table/examples/LegacyTableExpandable.tsx +172 -0
- package/src/components/Table/examples/LegacyTableFavoritable.tsx +157 -0
- package/src/components/Table/examples/LegacyTableHoverable.tsx +125 -0
- package/src/components/Table/examples/LegacyTableMisc.tsx +56 -0
- package/src/components/Table/examples/LegacyTableSelectable.tsx +124 -0
- package/src/components/Table/examples/LegacyTableSelectableRadio.tsx +54 -0
- package/src/components/Table/examples/LegacyTableSortable.tsx +120 -0
- package/src/components/Table/examples/LegacyTableSortableCustom.tsx +189 -0
- package/src/components/Table/examples/LegacyTableTextModifiers.tsx +31 -0
- package/src/components/Table/examples/LegacyTableTree.tsx +213 -0
- package/src/components/Table/examples/Table.md +83 -1848
- package/src/components/TableComposable/examples/ComposableTable.md +31 -2805
- package/src/components/TableComposable/examples/ComposableTableActions.tsx +163 -0
- package/src/components/TableComposable/examples/ComposableTableBasic.tsx +89 -0
- package/src/components/TableComposable/examples/ComposableTableCellWidth.tsx +56 -0
- package/src/components/TableComposable/examples/ComposableTableCompoundExpandable.tsx +103 -0
- package/src/components/TableComposable/examples/ComposableTableControllingText.tsx +51 -0
- package/src/components/TableComposable/examples/ComposableTableDraggable.tsx +170 -0
- package/src/components/TableComposable/examples/ComposableTableEmptyState.tsx +45 -0
- package/src/components/TableComposable/examples/ComposableTableExpandable.tsx +195 -0
- package/src/components/TableComposable/examples/ComposableTableFavoritable.tsx +118 -0
- package/src/components/TableComposable/examples/ComposableTableHoverable.tsx +67 -0
- package/src/components/TableComposable/examples/ComposableTableMisc.tsx +92 -0
- package/src/components/TableComposable/examples/ComposableTableMultipleStickyColumns.tsx +153 -0
- package/src/components/TableComposable/examples/ComposableTableNestedExpandable.tsx +127 -0
- package/src/components/TableComposable/examples/ComposableTableNestedHeaders.tsx +202 -0
- package/src/components/TableComposable/examples/ComposableTableSelectable.tsx +125 -0
- package/src/components/TableComposable/examples/ComposableTableSelectableRadio.tsx +68 -0
- package/src/components/TableComposable/examples/ComposableTableSortable.tsx +107 -0
- package/src/components/TableComposable/examples/ComposableTableSortableCustom.tsx +175 -0
- package/src/components/TableComposable/examples/ComposableTableStickyColumn.tsx +144 -0
- package/src/components/TableComposable/examples/ComposableTableStickyColumnsAndHeader.tsx +167 -0
- package/src/components/TableComposable/examples/ComposableTableTextModifiers.tsx +33 -0
- package/src/components/TableComposable/examples/ComposableTableTree.tsx +201 -0
- package/src/demos/Table.md +7 -6
- package/src/components/Table/examples/DemoSortableTable.js +0 -65
- package/src/components/TableComposable/examples/DemoSortableTable.js +0 -65
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import {
|
|
4
|
+
ButtonVariant,
|
|
5
|
+
DropdownToggle,
|
|
6
|
+
ToggleGroup,
|
|
7
|
+
ToggleGroupItem,
|
|
8
|
+
ToggleGroupItemProps
|
|
9
|
+
} from '@patternfly/react-core';
|
|
10
|
+
import {
|
|
11
|
+
TableComposable,
|
|
12
|
+
Thead,
|
|
13
|
+
Tr,
|
|
14
|
+
Th,
|
|
15
|
+
Tbody,
|
|
16
|
+
Td,
|
|
17
|
+
CustomActionsToggleProps,
|
|
18
|
+
ActionsColumn,
|
|
19
|
+
IAction
|
|
20
|
+
} from '@patternfly/react-table';
|
|
21
|
+
|
|
22
|
+
interface Repository {
|
|
23
|
+
name: string;
|
|
24
|
+
branches: string;
|
|
25
|
+
prs: string;
|
|
26
|
+
workspaces: string;
|
|
27
|
+
lastCommit: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type ExampleType = 'defaultToggle' | 'customToggle';
|
|
31
|
+
|
|
32
|
+
export const ComposableTableActions: React.FunctionComponent = () => {
|
|
33
|
+
// In real usage, this data would come from some external source like an API via props.
|
|
34
|
+
const repositories: Repository[] = [
|
|
35
|
+
{ name: 'one', branches: 'two', prs: 'a', workspaces: 'four', lastCommit: 'five' },
|
|
36
|
+
{ name: 'a', branches: 'two', prs: 'k', workspaces: 'four', lastCommit: 'five' },
|
|
37
|
+
{ name: 'p', branches: 'two', prs: 'b', workspaces: 'four', lastCommit: 'five' },
|
|
38
|
+
{ name: '4', branches: '2', prs: 'b', workspaces: 'four', lastCommit: 'five' },
|
|
39
|
+
{ name: '5', branches: '2', prs: 'b', workspaces: 'four', lastCommit: 'five' }
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
const columnNames = {
|
|
43
|
+
name: 'Repositories',
|
|
44
|
+
branches: 'Branches',
|
|
45
|
+
prs: 'Pull requests',
|
|
46
|
+
workspaces: 'Workspaces',
|
|
47
|
+
lastCommit: 'Last commit'
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// This state is just for the ToggleGroup in this example and isn't necessary for TableComposable usage.
|
|
51
|
+
const [exampleChoice, setExampleChoice] = React.useState<ExampleType>('defaultToggle');
|
|
52
|
+
const onExampleTypeChange: ToggleGroupItemProps['onChange'] = (_isSelected, event) => {
|
|
53
|
+
const id = event.currentTarget.id;
|
|
54
|
+
setExampleChoice(id as ExampleType);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const customActionsToggle = (props: CustomActionsToggleProps) => (
|
|
58
|
+
<DropdownToggle onToggle={props.onToggle} isDisabled={props.isDisabled}>
|
|
59
|
+
Actions
|
|
60
|
+
</DropdownToggle>
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const defaultActions = (repo: Repository): IAction[] => [
|
|
64
|
+
{
|
|
65
|
+
title: 'Some action',
|
|
66
|
+
onClick: () => console.log(`clicked on Some action, on row ${repo.name}`)
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
title: <a href="https://www.patternfly.org">Link action</a>
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
isSeparator: true
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
title: 'Third action',
|
|
76
|
+
onClick: () => console.log(`clicked on Third action, on row ${repo.name}`)
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
title: 'Start',
|
|
80
|
+
variant: ButtonVariant.secondary,
|
|
81
|
+
onClick: () => console.log(`clicked on extra action, on row ${repo.name}`),
|
|
82
|
+
isOutsideDropdown: true
|
|
83
|
+
}
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
const lastRowActions = (repo: Repository): IAction[] => [
|
|
87
|
+
{
|
|
88
|
+
title: 'Some action',
|
|
89
|
+
onClick: () => console.log(`clicked on Some action, on row ${repo.name}`)
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
title: <div>Another action</div>,
|
|
93
|
+
onClick: () => console.log(`clicked on Another action, on row ${repo.name}`)
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
isSeparator: true
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
title: 'Third action',
|
|
100
|
+
onClick: () => console.log(`clicked on Third action, on row ${repo.name}`)
|
|
101
|
+
}
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<React.Fragment>
|
|
106
|
+
<ToggleGroup aria-label="Default uses kebab toggle">
|
|
107
|
+
<ToggleGroupItem
|
|
108
|
+
text="Default actions toggle"
|
|
109
|
+
buttonId="defaultToggle"
|
|
110
|
+
isSelected={exampleChoice === 'defaultToggle'}
|
|
111
|
+
onChange={onExampleTypeChange}
|
|
112
|
+
/>
|
|
113
|
+
<ToggleGroupItem
|
|
114
|
+
text="Custom actions toggle"
|
|
115
|
+
buttonId="customToggle"
|
|
116
|
+
isSelected={exampleChoice === 'customToggle'}
|
|
117
|
+
onChange={onExampleTypeChange}
|
|
118
|
+
/>
|
|
119
|
+
</ToggleGroup>
|
|
120
|
+
<TableComposable aria-label="Actions table">
|
|
121
|
+
<Thead>
|
|
122
|
+
<Tr>
|
|
123
|
+
<Th>{columnNames.name}</Th>
|
|
124
|
+
<Th>{columnNames.branches}</Th>
|
|
125
|
+
<Th>{columnNames.prs}</Th>
|
|
126
|
+
<Th>{columnNames.workspaces}</Th>
|
|
127
|
+
<Th>{columnNames.lastCommit}</Th>
|
|
128
|
+
</Tr>
|
|
129
|
+
</Thead>
|
|
130
|
+
<Tbody>
|
|
131
|
+
{repositories.map(repo => {
|
|
132
|
+
// Arbitrary logic to determine which rows get which actions in this example
|
|
133
|
+
let rowActions: IAction[] | null = defaultActions(repo);
|
|
134
|
+
if (repo.name === 'a') {
|
|
135
|
+
rowActions = null;
|
|
136
|
+
}
|
|
137
|
+
if (repo.name === '5') {
|
|
138
|
+
rowActions = lastRowActions(repo);
|
|
139
|
+
}
|
|
140
|
+
return (
|
|
141
|
+
<Tr key={repo.name}>
|
|
142
|
+
<Td dataLabel={columnNames.name}>{repo.name}</Td>
|
|
143
|
+
<Td dataLabel={columnNames.branches}>{repo.branches}</Td>
|
|
144
|
+
<Td dataLabel={columnNames.prs}>{repo.prs}</Td>
|
|
145
|
+
<Td dataLabel={columnNames.workspaces}>{repo.workspaces}</Td>
|
|
146
|
+
<Td dataLabel={columnNames.lastCommit}>{repo.lastCommit}</Td>
|
|
147
|
+
<Td>
|
|
148
|
+
{rowActions ? (
|
|
149
|
+
<ActionsColumn
|
|
150
|
+
items={rowActions}
|
|
151
|
+
isDisabled={repo.name === '4'} // Also arbitrary for the example
|
|
152
|
+
actionsToggle={exampleChoice === 'customToggle' ? customActionsToggle : undefined}
|
|
153
|
+
/>
|
|
154
|
+
) : null}
|
|
155
|
+
</Td>
|
|
156
|
+
</Tr>
|
|
157
|
+
);
|
|
158
|
+
})}
|
|
159
|
+
</Tbody>
|
|
160
|
+
</TableComposable>
|
|
161
|
+
</React.Fragment>
|
|
162
|
+
);
|
|
163
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ToggleGroup, ToggleGroupItem, ToggleGroupItemProps } from '@patternfly/react-core';
|
|
3
|
+
import { TableComposable, Caption, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
|
|
4
|
+
|
|
5
|
+
interface Repository {
|
|
6
|
+
name: string;
|
|
7
|
+
branches: string | null;
|
|
8
|
+
prs: string | null;
|
|
9
|
+
workspaces: string;
|
|
10
|
+
lastCommit: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type ExampleType = 'default' | 'compact' | 'compactBorderless';
|
|
14
|
+
|
|
15
|
+
export const ComposableTableBasic: React.FunctionComponent = () => {
|
|
16
|
+
// In real usage, this data would come from some external source like an API via props.
|
|
17
|
+
const repositories: Repository[] = [
|
|
18
|
+
{ name: 'one', branches: 'two', prs: 'three', workspaces: 'four', lastCommit: 'five' },
|
|
19
|
+
{ name: 'one - 2', branches: null, prs: null, workspaces: 'four - 2', lastCommit: 'five - 2' },
|
|
20
|
+
{ name: 'one - 3', branches: 'two - 3', prs: 'three - 3', workspaces: 'four - 3', lastCommit: 'five - 3' }
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const columnNames = {
|
|
24
|
+
name: 'Repositories',
|
|
25
|
+
branches: 'Branches',
|
|
26
|
+
prs: 'Pull requests',
|
|
27
|
+
workspaces: 'Workspaces',
|
|
28
|
+
lastCommit: 'Last commit'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// This state is just for the ToggleGroup in this example and isn't necessary for TableComposable usage.
|
|
32
|
+
const [exampleChoice, setExampleChoice] = React.useState<ExampleType>('default');
|
|
33
|
+
const onExampleTypeChange: ToggleGroupItemProps['onChange'] = (_isSelected, event) => {
|
|
34
|
+
const id = event.currentTarget.id;
|
|
35
|
+
setExampleChoice(id as ExampleType);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<React.Fragment>
|
|
40
|
+
<ToggleGroup aria-label="Default with single selectable">
|
|
41
|
+
<ToggleGroupItem
|
|
42
|
+
text="Default"
|
|
43
|
+
buttonId="default"
|
|
44
|
+
isSelected={exampleChoice === 'default'}
|
|
45
|
+
onChange={onExampleTypeChange}
|
|
46
|
+
/>
|
|
47
|
+
<ToggleGroupItem
|
|
48
|
+
text="Compact"
|
|
49
|
+
buttonId="compact"
|
|
50
|
+
isSelected={exampleChoice === 'compact'}
|
|
51
|
+
onChange={onExampleTypeChange}
|
|
52
|
+
/>
|
|
53
|
+
<ToggleGroupItem
|
|
54
|
+
text="Compact borderless"
|
|
55
|
+
buttonId="compactBorderless"
|
|
56
|
+
isSelected={exampleChoice === 'compactBorderless'}
|
|
57
|
+
onChange={onExampleTypeChange}
|
|
58
|
+
/>
|
|
59
|
+
</ToggleGroup>
|
|
60
|
+
<TableComposable
|
|
61
|
+
aria-label="Simple table"
|
|
62
|
+
variant={exampleChoice !== 'default' ? 'compact' : undefined}
|
|
63
|
+
borders={exampleChoice !== 'compactBorderless'}
|
|
64
|
+
>
|
|
65
|
+
<Caption>Simple table using composable components</Caption>
|
|
66
|
+
<Thead>
|
|
67
|
+
<Tr>
|
|
68
|
+
<Th>{columnNames.name}</Th>
|
|
69
|
+
<Th>{columnNames.branches}</Th>
|
|
70
|
+
<Th>{columnNames.prs}</Th>
|
|
71
|
+
<Th>{columnNames.workspaces}</Th>
|
|
72
|
+
<Th>{columnNames.lastCommit}</Th>
|
|
73
|
+
</Tr>
|
|
74
|
+
</Thead>
|
|
75
|
+
<Tbody>
|
|
76
|
+
{repositories.map(repo => (
|
|
77
|
+
<Tr key={repo.name}>
|
|
78
|
+
<Td dataLabel={columnNames.name}>{repo.name}</Td>
|
|
79
|
+
<Td dataLabel={columnNames.branches}>{repo.branches}</Td>
|
|
80
|
+
<Td dataLabel={columnNames.prs}>{repo.prs}</Td>
|
|
81
|
+
<Td dataLabel={columnNames.workspaces}>{repo.workspaces}</Td>
|
|
82
|
+
<Td dataLabel={columnNames.lastCommit}>{repo.lastCommit}</Td>
|
|
83
|
+
</Tr>
|
|
84
|
+
))}
|
|
85
|
+
</Tbody>
|
|
86
|
+
</TableComposable>
|
|
87
|
+
</React.Fragment>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TableComposable, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
|
|
3
|
+
|
|
4
|
+
interface Repository {
|
|
5
|
+
name: string;
|
|
6
|
+
branches: string | null;
|
|
7
|
+
prs: string | null;
|
|
8
|
+
workspaces: string;
|
|
9
|
+
lastCommit: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const ComposableTableCellWidth: React.FunctionComponent = () => {
|
|
13
|
+
// In real usage, this data would come from some external source like an API via props.
|
|
14
|
+
const repositories: Repository[] = [
|
|
15
|
+
{ name: 'one', branches: 'two', prs: 'three', workspaces: 'four', lastCommit: 'five' },
|
|
16
|
+
{ name: 'one - 2', branches: null, prs: null, workspaces: 'four - 2', lastCommit: 'five - 2' },
|
|
17
|
+
{ name: 'one - 3', branches: 'two - 3', prs: 'three - 3', workspaces: 'four - 3', lastCommit: 'five - 3' }
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const columnNames = {
|
|
21
|
+
name: 'Repositories',
|
|
22
|
+
branches: 'Branches',
|
|
23
|
+
prs: 'Pull requests',
|
|
24
|
+
workspaces: 'Workspaces',
|
|
25
|
+
lastCommit: 'Last commit'
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<TableComposable aria-label="Cell widths">
|
|
30
|
+
<Thead>
|
|
31
|
+
<Tr>
|
|
32
|
+
<Th width={15}>{columnNames.name}</Th>
|
|
33
|
+
<Th width={15}>{columnNames.branches}</Th>
|
|
34
|
+
<Th width={40} visibility={['hiddenOnMd', 'visibleOnLg']}>
|
|
35
|
+
{columnNames.prs}
|
|
36
|
+
</Th>
|
|
37
|
+
<Th width={15}>{columnNames.workspaces}</Th>
|
|
38
|
+
<Th width={15}>{columnNames.lastCommit}</Th>
|
|
39
|
+
</Tr>
|
|
40
|
+
</Thead>
|
|
41
|
+
<Tbody>
|
|
42
|
+
{repositories.map(repo => (
|
|
43
|
+
<Tr key={repo.name}>
|
|
44
|
+
<Td dataLabel={columnNames.name}>{repo.name}</Td>
|
|
45
|
+
<Td dataLabel={columnNames.branches}>{repo.branches}</Td>
|
|
46
|
+
<Td dataLabel={columnNames.prs} visibility={['hiddenOnMd', 'visibleOnLg']}>
|
|
47
|
+
{repo.prs}
|
|
48
|
+
</Td>
|
|
49
|
+
<Td dataLabel={columnNames.workspaces}>{repo.workspaces}</Td>
|
|
50
|
+
<Td dataLabel={columnNames.lastCommit}>{repo.lastCommit}</Td>
|
|
51
|
+
</Tr>
|
|
52
|
+
))}
|
|
53
|
+
</Tbody>
|
|
54
|
+
</TableComposable>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TableComposable, Thead, Tr, Th, Tbody, Td, TdProps, ExpandableRowContent } from '@patternfly/react-table';
|
|
3
|
+
|
|
4
|
+
import CodeBranchIcon from '@patternfly/react-icons/dist/esm/icons/code-branch-icon';
|
|
5
|
+
import CodeIcon from '@patternfly/react-icons/dist/esm/icons/code-icon';
|
|
6
|
+
import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon';
|
|
7
|
+
|
|
8
|
+
interface Repository {
|
|
9
|
+
name: string;
|
|
10
|
+
branches: number;
|
|
11
|
+
prs: number;
|
|
12
|
+
workspaces: number;
|
|
13
|
+
lastCommit: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const ComposableTableCompoundExpandable: React.FunctionComponent = () => {
|
|
17
|
+
// In real usage, this data would come from some external source like an API via props.
|
|
18
|
+
const repositories: Repository[] = [
|
|
19
|
+
{ name: 'siemur/test-space', branches: 10, prs: 4, workspaces: 4, lastCommit: '20 minutes' },
|
|
20
|
+
{ name: 'siemur/test-space-2', branches: 3, prs: 4, workspaces: 4, lastCommit: '20 minutes' }
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const columnNames = {
|
|
24
|
+
name: 'Repositories',
|
|
25
|
+
branches: 'Branches',
|
|
26
|
+
prs: 'Pull requests',
|
|
27
|
+
workspaces: 'Workspaces',
|
|
28
|
+
lastCommit: 'Last commit'
|
|
29
|
+
};
|
|
30
|
+
type ColumnKey = keyof typeof columnNames;
|
|
31
|
+
|
|
32
|
+
// In this example, expanded cells are tracked by the repo and property names from each row. This could be any pair of unique identifiers.
|
|
33
|
+
// This is to prevent state from being based on row and column order index in case we later add sorting and rearranging columns.
|
|
34
|
+
// Note that this behavior is very similar to selection state.
|
|
35
|
+
const [expandedCells, setExpandedCells] = React.useState<Record<string, ColumnKey>>({
|
|
36
|
+
'siemur/test-space': 'branches' // Default to the first cell of the first row being expanded
|
|
37
|
+
});
|
|
38
|
+
const setCellExpanded = (repo: Repository, columnKey: ColumnKey, isExpanding = true) => {
|
|
39
|
+
const newExpandedCells = { ...expandedCells };
|
|
40
|
+
if (isExpanding) {
|
|
41
|
+
newExpandedCells[repo.name] = columnKey;
|
|
42
|
+
} else {
|
|
43
|
+
delete newExpandedCells[repo.name];
|
|
44
|
+
}
|
|
45
|
+
setExpandedCells(newExpandedCells);
|
|
46
|
+
};
|
|
47
|
+
const compoundExpandParams = (repo: Repository, columnKey: ColumnKey): TdProps['compoundExpand'] => ({
|
|
48
|
+
isExpanded: expandedCells[repo.name] === columnKey,
|
|
49
|
+
onToggle: () => setCellExpanded(repo, columnKey, expandedCells[repo.name] !== columnKey)
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<TableComposable aria-label="Compound expandable table">
|
|
54
|
+
<Thead>
|
|
55
|
+
<Tr>
|
|
56
|
+
<Th>{columnNames.name}</Th>
|
|
57
|
+
<Th>{columnNames.branches}</Th>
|
|
58
|
+
<Th>{columnNames.prs}</Th>
|
|
59
|
+
<Th>{columnNames.workspaces}</Th>
|
|
60
|
+
<Th>{columnNames.lastCommit}</Th>
|
|
61
|
+
<Th />
|
|
62
|
+
</Tr>
|
|
63
|
+
</Thead>
|
|
64
|
+
{repositories.map(repo => {
|
|
65
|
+
const expandedCellKey = expandedCells[repo.name];
|
|
66
|
+
const isRowExpanded = !!expandedCellKey;
|
|
67
|
+
return (
|
|
68
|
+
<Tbody key={repo.name} isExpanded={isRowExpanded}>
|
|
69
|
+
<Tr>
|
|
70
|
+
<Td dataLabel={columnNames.name} component="th">
|
|
71
|
+
<a href="#">{repo.name}</a>
|
|
72
|
+
</Td>
|
|
73
|
+
<Td dataLabel={columnNames.branches} compoundExpand={compoundExpandParams(repo, 'branches')}>
|
|
74
|
+
<CodeBranchIcon key="icon" /> {repo.branches}
|
|
75
|
+
</Td>
|
|
76
|
+
<Td dataLabel={columnNames.prs} compoundExpand={compoundExpandParams(repo, 'prs')}>
|
|
77
|
+
<CodeIcon key="icon" /> {repo.prs}
|
|
78
|
+
</Td>
|
|
79
|
+
<Td dataLabel={columnNames.workspaces} compoundExpand={compoundExpandParams(repo, 'workspaces')}>
|
|
80
|
+
<CubeIcon key="icon" /> {repo.workspaces}
|
|
81
|
+
</Td>
|
|
82
|
+
<Td dataLabel={columnNames.lastCommit}>{repo.lastCommit}</Td>
|
|
83
|
+
<Td>
|
|
84
|
+
<a href="#">Open in GitHub</a>
|
|
85
|
+
</Td>
|
|
86
|
+
</Tr>
|
|
87
|
+
{isRowExpanded ? (
|
|
88
|
+
<Tr isExpanded={isRowExpanded}>
|
|
89
|
+
<Td dataLabel={columnNames[expandedCellKey]} noPadding colSpan={6}>
|
|
90
|
+
<ExpandableRowContent>
|
|
91
|
+
<div className="pf-u-m-md">
|
|
92
|
+
Expanded content for {repo.name}: {expandedCellKey} goes here!
|
|
93
|
+
</div>
|
|
94
|
+
</ExpandableRowContent>
|
|
95
|
+
</Td>
|
|
96
|
+
</Tr>
|
|
97
|
+
) : null}
|
|
98
|
+
</Tbody>
|
|
99
|
+
);
|
|
100
|
+
})}
|
|
101
|
+
</TableComposable>
|
|
102
|
+
);
|
|
103
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TableComposable, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
|
|
3
|
+
|
|
4
|
+
// This example has been simplified to focus on the text modifier props. In real usage,
|
|
5
|
+
// you may want to derive your rows from typed underlying data and minimal state. See other examples.
|
|
6
|
+
|
|
7
|
+
const columnNames = {
|
|
8
|
+
truncate: 'Truncate (width 20%)',
|
|
9
|
+
break: 'Break word',
|
|
10
|
+
wrap: 'Wrapping table header text. This th text will wrap instead of truncate.',
|
|
11
|
+
fit: 'Fit content',
|
|
12
|
+
nowrap: 'No wrap'
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const ComposableTableControllingText: React.FunctionComponent = () => (
|
|
16
|
+
<TableComposable aria-label="Controlling text">
|
|
17
|
+
<Thead>
|
|
18
|
+
<Tr>
|
|
19
|
+
<Th width={20}>{columnNames.truncate}</Th>
|
|
20
|
+
<Th>{columnNames.break}</Th>
|
|
21
|
+
<Th modifier="wrap">{columnNames.wrap}</Th>
|
|
22
|
+
<Th modifier="fitContent">{columnNames.fit}</Th>
|
|
23
|
+
<Th>{columnNames.nowrap}</Th>
|
|
24
|
+
</Tr>
|
|
25
|
+
</Thead>
|
|
26
|
+
<Tbody>
|
|
27
|
+
<Tr>
|
|
28
|
+
<Td dataLabel={columnNames.truncate} modifier="truncate">
|
|
29
|
+
This text will truncate instead of wrap.
|
|
30
|
+
</Td>
|
|
31
|
+
<Td dataLabel={columnNames.break} modifier="breakWord">
|
|
32
|
+
<a>http://thisisaverylongurlthatneedstobreakusethebreakwordmodifier.org</a>
|
|
33
|
+
</Td>
|
|
34
|
+
<Td dataLabel={columnNames.wrap}>
|
|
35
|
+
<p>
|
|
36
|
+
By default,
|
|
37
|
+
<code>thead</code> cells will truncate and
|
|
38
|
+
<code>tbody</code> cells will wrap. Use
|
|
39
|
+
<code>.pf-m-wrap</code> on a<code>th</code> to change its behavior.
|
|
40
|
+
</p>
|
|
41
|
+
</Td>
|
|
42
|
+
<Td dataLabel={columnNames.fit}>
|
|
43
|
+
This cell's content will adjust itself to the parent th width. This modifier only affects table layouts.
|
|
44
|
+
</Td>
|
|
45
|
+
<Td dataLabel={columnNames.nowrap} modifier="nowrap">
|
|
46
|
+
<a href="#">No wrap</a>
|
|
47
|
+
</Td>
|
|
48
|
+
</Tr>
|
|
49
|
+
</Tbody>
|
|
50
|
+
</TableComposable>
|
|
51
|
+
);
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TableComposable, Thead, Tbody, Tr, Th, Td, TbodyProps, TrProps } from '@patternfly/react-table';
|
|
3
|
+
import styles from '@patternfly/react-styles/css/components/Table/table';
|
|
4
|
+
|
|
5
|
+
export const ComposableTableDraggable: React.FunctionComponent = () => {
|
|
6
|
+
const [draggedItemId, setDraggedItemId] = React.useState<string | null>(null);
|
|
7
|
+
const [draggingToItemIndex, setDraggingToItemIndex] = React.useState<number | null>(null);
|
|
8
|
+
const [isDragging, setIsDragging] = React.useState(false);
|
|
9
|
+
const [itemOrder, setItemOrder] = React.useState(['row1', 'row2', 'row3']);
|
|
10
|
+
const [tempItemOrder, setTempItemOrder] = React.useState<string[]>([]);
|
|
11
|
+
|
|
12
|
+
const bodyRef = React.useRef<HTMLTableSectionElement>();
|
|
13
|
+
|
|
14
|
+
const onDragStart: TrProps['onDragStart'] = evt => {
|
|
15
|
+
evt.dataTransfer.effectAllowed = 'move';
|
|
16
|
+
evt.dataTransfer.setData('text/plain', evt.currentTarget.id);
|
|
17
|
+
const draggedItemId = evt.currentTarget.id;
|
|
18
|
+
|
|
19
|
+
evt.currentTarget.classList.add(styles.modifiers.ghostRow);
|
|
20
|
+
evt.currentTarget.setAttribute('aria-pressed', 'true');
|
|
21
|
+
|
|
22
|
+
setDraggedItemId(draggedItemId);
|
|
23
|
+
setIsDragging(true);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const moveItem = (arr: string[], i1: string, toIndex: number) => {
|
|
27
|
+
const fromIndex = arr.indexOf(i1);
|
|
28
|
+
if (fromIndex === toIndex) {
|
|
29
|
+
return arr;
|
|
30
|
+
}
|
|
31
|
+
const temp = arr.splice(fromIndex, 1);
|
|
32
|
+
arr.splice(toIndex, 0, temp[0]);
|
|
33
|
+
|
|
34
|
+
return arr;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const move = (itemOrder: string[]) => {
|
|
38
|
+
const ulNode = bodyRef.current;
|
|
39
|
+
const nodes = Array.from(ulNode.children);
|
|
40
|
+
if (nodes.map(node => node.id).every((id, i) => id === itemOrder[i])) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
while (ulNode.firstChild) {
|
|
44
|
+
ulNode.removeChild(ulNode.lastChild);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
itemOrder.forEach(id => {
|
|
48
|
+
ulNode.appendChild(nodes.find(n => n.id === id));
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const onDragCancel = () => {
|
|
53
|
+
Array.from(bodyRef.current.children).forEach(el => {
|
|
54
|
+
el.classList.remove(styles.modifiers.ghostRow);
|
|
55
|
+
el.setAttribute('aria-pressed', 'false');
|
|
56
|
+
});
|
|
57
|
+
setDraggedItemId(null);
|
|
58
|
+
setDraggingToItemIndex(null);
|
|
59
|
+
setIsDragging(false);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const onDragLeave: TbodyProps['onDragLeave'] = evt => {
|
|
63
|
+
if (!isValidDrop(evt)) {
|
|
64
|
+
move(itemOrder);
|
|
65
|
+
setDraggingToItemIndex(null);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const isValidDrop = (evt: React.DragEvent<HTMLTableSectionElement | HTMLTableRowElement>) => {
|
|
70
|
+
const ulRect = bodyRef.current.getBoundingClientRect();
|
|
71
|
+
return (
|
|
72
|
+
evt.clientX > ulRect.x &&
|
|
73
|
+
evt.clientX < ulRect.x + ulRect.width &&
|
|
74
|
+
evt.clientY > ulRect.y &&
|
|
75
|
+
evt.clientY < ulRect.y + ulRect.height
|
|
76
|
+
);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const onDrop: TrProps['onDrop'] = evt => {
|
|
80
|
+
if (isValidDrop(evt)) {
|
|
81
|
+
setItemOrder(tempItemOrder);
|
|
82
|
+
} else {
|
|
83
|
+
onDragCancel();
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const onDragOver: TbodyProps['onDragOver'] = evt => {
|
|
88
|
+
evt.preventDefault();
|
|
89
|
+
|
|
90
|
+
const curListItem = (evt.target as HTMLTableSectionElement).closest('tr');
|
|
91
|
+
if (!curListItem || !bodyRef.current.contains(curListItem) || curListItem.id === draggedItemId) {
|
|
92
|
+
return null;
|
|
93
|
+
} else {
|
|
94
|
+
const dragId = curListItem.id;
|
|
95
|
+
const newDraggingToItemIndex = Array.from(bodyRef.current.children).findIndex(item => item.id === dragId);
|
|
96
|
+
if (newDraggingToItemIndex !== draggingToItemIndex) {
|
|
97
|
+
const tempItemOrder = moveItem([...itemOrder], draggedItemId, newDraggingToItemIndex);
|
|
98
|
+
move(tempItemOrder);
|
|
99
|
+
setDraggingToItemIndex(newDraggingToItemIndex);
|
|
100
|
+
setTempItemOrder(tempItemOrder);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const onDragEnd: TrProps['onDragEnd'] = evt => {
|
|
106
|
+
const target = evt.target as HTMLTableRowElement;
|
|
107
|
+
target.classList.remove(styles.modifiers.ghostRow);
|
|
108
|
+
target.setAttribute('aria-pressed', 'false');
|
|
109
|
+
setDraggedItemId(null);
|
|
110
|
+
setDraggingToItemIndex(null);
|
|
111
|
+
setIsDragging(false);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last commit'];
|
|
115
|
+
const rows = [
|
|
116
|
+
{
|
|
117
|
+
id: 'row1',
|
|
118
|
+
repository: 'one',
|
|
119
|
+
branch: 'two',
|
|
120
|
+
pullRequest: 'three',
|
|
121
|
+
workspace: 'four',
|
|
122
|
+
lastCommit: 'five'
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: 'row2',
|
|
126
|
+
repository: 'one -2',
|
|
127
|
+
branch: null,
|
|
128
|
+
pullRequest: null,
|
|
129
|
+
workspace: 'four -2',
|
|
130
|
+
lastCommit: 'five -2'
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
id: 'row3',
|
|
134
|
+
repository: 'one - 3',
|
|
135
|
+
branch: 'two - 3',
|
|
136
|
+
pullRequest: 'three - 3',
|
|
137
|
+
workspace: 'four - 3',
|
|
138
|
+
lastCommit: 'five - 3'
|
|
139
|
+
}
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<TableComposable aria-label="Draggable table" className={isDragging && styles.modifiers.dragOver}>
|
|
144
|
+
<Thead>
|
|
145
|
+
<Tr>
|
|
146
|
+
<Th />
|
|
147
|
+
{columns.map((column, columnIndex) => (
|
|
148
|
+
<Th key={columnIndex}>{column}</Th>
|
|
149
|
+
))}
|
|
150
|
+
</Tr>
|
|
151
|
+
</Thead>
|
|
152
|
+
<Tbody ref={bodyRef} onDragOver={onDragOver} onDrop={onDragOver} onDragLeave={onDragLeave}>
|
|
153
|
+
{rows.map((row, rowIndex) => (
|
|
154
|
+
<Tr key={rowIndex} id={row.id} draggable onDrop={onDrop} onDragEnd={onDragEnd} onDragStart={onDragStart}>
|
|
155
|
+
<Td
|
|
156
|
+
draggableRow={{
|
|
157
|
+
id: `draggable-row-${row.id}`
|
|
158
|
+
}}
|
|
159
|
+
/>
|
|
160
|
+
{Object.keys(row).map((key, keyIndex) => (
|
|
161
|
+
<Td key={`${rowIndex}_${keyIndex}`} dataLabel={columns[keyIndex]}>
|
|
162
|
+
{row[key]}
|
|
163
|
+
</Td>
|
|
164
|
+
))}
|
|
165
|
+
</Tr>
|
|
166
|
+
))}
|
|
167
|
+
</Tbody>
|
|
168
|
+
</TableComposable>
|
|
169
|
+
);
|
|
170
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TableComposable, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
|
|
3
|
+
import {
|
|
4
|
+
Bullseye,
|
|
5
|
+
EmptyState,
|
|
6
|
+
EmptyStateVariant,
|
|
7
|
+
EmptyStateIcon,
|
|
8
|
+
Title,
|
|
9
|
+
EmptyStateBody,
|
|
10
|
+
Button
|
|
11
|
+
} from '@patternfly/react-core';
|
|
12
|
+
import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
|
|
13
|
+
|
|
14
|
+
// This example has been simplified to focus on the empty state. In real usage,
|
|
15
|
+
// you may want to derive your rows from typed underlying data and minimal state. See other examples.
|
|
16
|
+
|
|
17
|
+
export const ComposableTableEmptyState: React.FunctionComponent = () => (
|
|
18
|
+
<TableComposable aria-label="Empty state table">
|
|
19
|
+
<Thead>
|
|
20
|
+
<Tr>
|
|
21
|
+
<Th>Repositories</Th>
|
|
22
|
+
<Th>Branches</Th>
|
|
23
|
+
<Th>Pull requests</Th>
|
|
24
|
+
<Th>Workspaces</Th>
|
|
25
|
+
<Th>Last commit</Th>
|
|
26
|
+
</Tr>
|
|
27
|
+
</Thead>
|
|
28
|
+
<Tbody>
|
|
29
|
+
<Tr>
|
|
30
|
+
<Td colSpan={8}>
|
|
31
|
+
<Bullseye>
|
|
32
|
+
<EmptyState variant={EmptyStateVariant.small}>
|
|
33
|
+
<EmptyStateIcon icon={SearchIcon} />
|
|
34
|
+
<Title headingLevel="h2" size="lg">
|
|
35
|
+
No results found
|
|
36
|
+
</Title>
|
|
37
|
+
<EmptyStateBody>Clear all filters and try again.</EmptyStateBody>
|
|
38
|
+
<Button variant="link">Clear all filters</Button>
|
|
39
|
+
</EmptyState>
|
|
40
|
+
</Bullseye>
|
|
41
|
+
</Td>
|
|
42
|
+
</Tr>
|
|
43
|
+
</Tbody>
|
|
44
|
+
</TableComposable>
|
|
45
|
+
);
|