@teselagen/ui 0.10.4 → 0.10.6
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/DataTable/DisplayOptions.d.ts +2 -1
- package/DataTable/DraggableColumnOptions.d.ts +7 -0
- package/DataTable/SortableColumns.d.ts +2 -1
- package/DataTable/ThComponent.d.ts +2 -1
- package/DataTable/dragNoticeEl.d.ts +1 -0
- package/DataTable/viewColumn.d.ts +0 -2
- package/index.cjs.js +1879 -6768
- package/index.es.js +595 -5484
- package/package.json +1 -1
- package/src/DataTable/Columns.js +13 -5
- package/src/DataTable/DisplayOptions.js +33 -126
- package/src/DataTable/DraggableColumnOptions.js +176 -0
- package/src/DataTable/SortableColumns.js +38 -26
- package/src/DataTable/ThComponent.js +22 -9
- package/src/DataTable/dragNoticeEl.js +13 -0
- package/src/DataTable/index.js +66 -129
- package/src/DataTable/style.css +18 -13
- package/src/DataTable/utils/queryParams.js +6 -1
- package/src/DataTable/utils/tableQueryParamsToHasuraClauses.js +180 -142
- package/src/DataTable/utils/withTableParams.js +2 -3
- package/src/DataTable/viewColumn.js +0 -1
- package/src/TgSelect/index.js +2 -0
- package/ui.css +18 -13
package/package.json
CHANGED
package/src/DataTable/Columns.js
CHANGED
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
noop,
|
|
10
10
|
cloneDeep,
|
|
11
11
|
get,
|
|
12
|
-
padStart
|
|
12
|
+
padStart,
|
|
13
|
+
flatMap
|
|
13
14
|
} from "lodash-es";
|
|
14
15
|
import dayjs from "dayjs";
|
|
15
16
|
import localizedFormat from "dayjs/plugin/localizedFormat";
|
|
@@ -38,6 +39,7 @@ import { change as _change } from "redux-form";
|
|
|
38
39
|
import { RenderCell } from "./RenderCell";
|
|
39
40
|
import { getCCDisplayName } from "./utils/tableQueryParamsToHasuraClauses";
|
|
40
41
|
import { showContextMenu } from "../utils/menuUtils";
|
|
42
|
+
import { dragNoticeEl } from "./dragNoticeEl";
|
|
41
43
|
|
|
42
44
|
dayjs.extend(localizedFormat);
|
|
43
45
|
|
|
@@ -171,12 +173,13 @@ const RenderColumnHeader = ({
|
|
|
171
173
|
})}
|
|
172
174
|
onContextMenu={e => {
|
|
173
175
|
if (!withDisplayOptions) {
|
|
174
|
-
return
|
|
176
|
+
return;
|
|
175
177
|
}
|
|
176
178
|
e.preventDefault();
|
|
177
179
|
e.persist();
|
|
178
180
|
showContextMenu(
|
|
179
181
|
[
|
|
182
|
+
dragNoticeEl,
|
|
180
183
|
{
|
|
181
184
|
text: "Hide Column",
|
|
182
185
|
disabled: onlyOneVisibleColumn,
|
|
@@ -917,7 +920,10 @@ export const useColumns = ({
|
|
|
917
920
|
});
|
|
918
921
|
}
|
|
919
922
|
|
|
920
|
-
const tableColumns = columns
|
|
923
|
+
const tableColumns = flatMap(columns, column => {
|
|
924
|
+
if (column.isHidden) {
|
|
925
|
+
return [];
|
|
926
|
+
}
|
|
921
927
|
const tableColumn = {
|
|
922
928
|
...column,
|
|
923
929
|
Header: RenderColumnHeader({
|
|
@@ -950,8 +956,10 @@ export const useColumns = ({
|
|
|
950
956
|
getHeaderProps: () => ({
|
|
951
957
|
// needs to be a string because it is getting passed
|
|
952
958
|
// to the dom
|
|
953
|
-
immovable:
|
|
954
|
-
|
|
959
|
+
immovable:
|
|
960
|
+
column.type === "action" || column.immovable ? "true" : "false",
|
|
961
|
+
columnindex: column.columnIndex,
|
|
962
|
+
path: column.path
|
|
955
963
|
})
|
|
956
964
|
};
|
|
957
965
|
const noEllipsis = column.noEllipsis;
|
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
import React, { useState } from "react";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
Button,
|
|
5
|
-
Checkbox,
|
|
6
|
-
Menu,
|
|
7
|
-
MenuItem,
|
|
8
|
-
Classes,
|
|
9
|
-
InputGroup,
|
|
10
|
-
Popover,
|
|
11
|
-
Switch
|
|
12
|
-
} from "@blueprintjs/core";
|
|
13
|
-
import { getCCDisplayName } from "./utils/tableQueryParamsToHasuraClauses";
|
|
2
|
+
import { noop } from "lodash-es";
|
|
3
|
+
import { Button, Menu, Classes, Popover, Switch } from "@blueprintjs/core";
|
|
14
4
|
import InfoHelper from "../InfoHelper";
|
|
5
|
+
import DraggableColumnOptions from "./DraggableColumnOptions";
|
|
6
|
+
import { dragNoticeEl } from "./dragNoticeEl";
|
|
15
7
|
|
|
16
8
|
const DisplayOptions = ({
|
|
17
9
|
compact,
|
|
@@ -22,13 +14,13 @@ const DisplayOptions = ({
|
|
|
22
14
|
resetDefaultVisibility = noop,
|
|
23
15
|
updateColumnVisibility = noop,
|
|
24
16
|
updateTableDisplayDensity,
|
|
17
|
+
moveColumnPersist = noop,
|
|
25
18
|
showForcedHiddenColumns,
|
|
26
19
|
setShowForcedHidden,
|
|
27
20
|
hasOptionForForcedHidden,
|
|
28
21
|
schema
|
|
29
22
|
}) => {
|
|
30
23
|
const [isOpen, setIsOpen] = useState(false);
|
|
31
|
-
const [searchTerms, setSearchTerms] = useState({});
|
|
32
24
|
|
|
33
25
|
const changeTableDensity = e => {
|
|
34
26
|
updateTableDisplayDensity(e.target.value);
|
|
@@ -41,99 +33,13 @@ const DisplayOptions = ({
|
|
|
41
33
|
return null; //don't show antyhing!
|
|
42
34
|
}
|
|
43
35
|
const { fields } = schema;
|
|
44
|
-
const fieldGroups = {};
|
|
45
|
-
const mainFields = [];
|
|
46
|
-
|
|
47
|
-
fields.forEach(field => {
|
|
48
|
-
if (field.hideInMenu) return;
|
|
49
|
-
if (!field.fieldGroup) return mainFields.push(field);
|
|
50
|
-
if (!fieldGroups[field.fieldGroup]) fieldGroups[field.fieldGroup] = [];
|
|
51
|
-
fieldGroups[field.fieldGroup].push(field);
|
|
52
|
-
});
|
|
53
36
|
|
|
54
37
|
let numVisible = 0;
|
|
55
38
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
return (
|
|
61
|
-
<Checkbox
|
|
62
|
-
name={`${path}-${i}`}
|
|
63
|
-
key={path || i}
|
|
64
|
-
onChange={() => {
|
|
65
|
-
if (numVisible <= 1 && !isHidden) {
|
|
66
|
-
return window.toastr.warning(
|
|
67
|
-
"We have to display at least one column :)"
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
updateColumnVisibility({ shouldShow: isHidden, path });
|
|
71
|
-
}}
|
|
72
|
-
checked={!isHidden}
|
|
73
|
-
label={
|
|
74
|
-
<span style={{ display: "flex", marginTop: -17 }}>
|
|
75
|
-
{displayName}
|
|
76
|
-
{subFrag && (
|
|
77
|
-
<InfoHelper
|
|
78
|
-
icon="warning-sign"
|
|
79
|
-
intent="warning"
|
|
80
|
-
style={{ marginLeft: 5 }}
|
|
81
|
-
>
|
|
82
|
-
Viewing this column may cause the table to load slower
|
|
83
|
-
</InfoHelper>
|
|
84
|
-
)}
|
|
85
|
-
</span>
|
|
86
|
-
}
|
|
87
|
-
/>
|
|
88
|
-
);
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
let fieldGroupMenu;
|
|
92
|
-
if (!isEmpty(fieldGroups)) {
|
|
93
|
-
fieldGroupMenu = map(fieldGroups, (groupFields, groupName) => {
|
|
94
|
-
const searchTerm = searchTerms[groupName] || "";
|
|
95
|
-
const anyVisible = groupFields.some(
|
|
96
|
-
field => !field.isHidden && !field.isForcedHidden
|
|
97
|
-
);
|
|
98
|
-
const anyNotForcedHidden = groupFields.some(
|
|
99
|
-
field => !field.isForcedHidden
|
|
100
|
-
);
|
|
101
|
-
if (!anyNotForcedHidden) return;
|
|
102
|
-
return (
|
|
103
|
-
<MenuItem key={groupName} text={groupName}>
|
|
104
|
-
<InputGroup
|
|
105
|
-
leftIcon="search"
|
|
106
|
-
value={searchTerm}
|
|
107
|
-
onChange={e => {
|
|
108
|
-
setSearchTerms(prev => ({
|
|
109
|
-
...prev,
|
|
110
|
-
[groupName]: e.target.value
|
|
111
|
-
}));
|
|
112
|
-
}}
|
|
113
|
-
/>
|
|
114
|
-
<Button
|
|
115
|
-
className={Classes.MINIMAL}
|
|
116
|
-
text={(anyVisible ? "Hide" : "Show") + " All"}
|
|
117
|
-
style={{ margin: "10px 0" }}
|
|
118
|
-
onClick={() => {
|
|
119
|
-
updateColumnVisibility({
|
|
120
|
-
shouldShow: !anyVisible,
|
|
121
|
-
paths: groupFields.map(field => field.path)
|
|
122
|
-
});
|
|
123
|
-
}}
|
|
124
|
-
/>
|
|
125
|
-
{groupFields
|
|
126
|
-
.filter(
|
|
127
|
-
field =>
|
|
128
|
-
startCase(getCCDisplayName(field)) // We have to use startCase with the camelCase here because the displayName is not always a string
|
|
129
|
-
.toLowerCase()
|
|
130
|
-
.indexOf(searchTerm.toLowerCase()) > -1
|
|
131
|
-
)
|
|
132
|
-
.map(getFieldCheckbox)}
|
|
133
|
-
</MenuItem>
|
|
134
|
-
);
|
|
135
|
-
});
|
|
136
|
-
}
|
|
39
|
+
// Count number of visible fields
|
|
40
|
+
fields.forEach(field => {
|
|
41
|
+
if (!field.isHidden && field.type !== "action") numVisible++;
|
|
42
|
+
});
|
|
137
43
|
|
|
138
44
|
return (
|
|
139
45
|
<Popover
|
|
@@ -170,21 +76,29 @@ const DisplayOptions = ({
|
|
|
170
76
|
<h5
|
|
171
77
|
style={{
|
|
172
78
|
fontWeight: "bold",
|
|
173
|
-
marginBottom:
|
|
79
|
+
marginBottom: 0,
|
|
174
80
|
marginTop: 10,
|
|
175
81
|
display: "flex"
|
|
176
82
|
}}
|
|
177
83
|
>
|
|
178
84
|
Displayed Columns:
|
|
179
|
-
{doNotSearchHiddenColumns &&
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
85
|
+
{doNotSearchHiddenColumns && (
|
|
86
|
+
<InfoHelper>
|
|
87
|
+
Note: Hidden columns will NOT be used when searching the
|
|
88
|
+
datatable
|
|
89
|
+
</InfoHelper>
|
|
90
|
+
)}
|
|
183
91
|
</h5>
|
|
184
|
-
|
|
185
|
-
|
|
92
|
+
{dragNoticeEl}
|
|
93
|
+
|
|
94
|
+
<div style={{ maxHeight: 360, overflowY: "auto", padding: 2 }}>
|
|
95
|
+
<DraggableColumnOptions
|
|
96
|
+
fields={fields}
|
|
97
|
+
onVisibilityChange={updateColumnVisibility}
|
|
98
|
+
moveColumnPersist={moveColumnPersist}
|
|
99
|
+
numVisible={numVisible}
|
|
100
|
+
/>
|
|
186
101
|
</div>
|
|
187
|
-
<div>{fieldGroupMenu}</div>
|
|
188
102
|
{hasOptionForForcedHidden && (
|
|
189
103
|
<div style={{ marginTop: 15 }}>
|
|
190
104
|
<Switch
|
|
@@ -194,22 +108,15 @@ const DisplayOptions = ({
|
|
|
194
108
|
/>
|
|
195
109
|
</div>
|
|
196
110
|
)}
|
|
197
|
-
<
|
|
198
|
-
style={{
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
111
|
+
<Button
|
|
112
|
+
style={{ marginTop: 5 }}
|
|
113
|
+
onClick={resetDefaultVisibility}
|
|
114
|
+
title="Display Options"
|
|
115
|
+
icon="reset"
|
|
116
|
+
minimal
|
|
203
117
|
>
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
title="Display Options"
|
|
207
|
-
icon="reset"
|
|
208
|
-
minimal
|
|
209
|
-
>
|
|
210
|
-
Reset Column Visibilites
|
|
211
|
-
</Button>
|
|
212
|
-
</div>
|
|
118
|
+
Reset Column Visibilites
|
|
119
|
+
</Button>
|
|
213
120
|
</div>
|
|
214
121
|
</Menu>
|
|
215
122
|
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import React, { useState, useEffect } from "react";
|
|
2
|
+
import { DndContext, MouseSensor, useSensor, useSensors } from "@dnd-kit/core";
|
|
3
|
+
import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
|
|
4
|
+
import {
|
|
5
|
+
SortableContext,
|
|
6
|
+
verticalListSortingStrategy,
|
|
7
|
+
useSortable,
|
|
8
|
+
arrayMove
|
|
9
|
+
} from "@dnd-kit/sortable";
|
|
10
|
+
import { CSS } from "@dnd-kit/utilities";
|
|
11
|
+
import { Checkbox, Classes } from "@blueprintjs/core";
|
|
12
|
+
import InfoHelper from "../InfoHelper";
|
|
13
|
+
|
|
14
|
+
const DraggableColumnOption = ({
|
|
15
|
+
field,
|
|
16
|
+
index,
|
|
17
|
+
onVisibilityChange,
|
|
18
|
+
numVisible
|
|
19
|
+
}) => {
|
|
20
|
+
const { displayName, isHidden, path, subFrag, immovable, type } = field;
|
|
21
|
+
|
|
22
|
+
const { attributes, listeners, setNodeRef, transform, transition } =
|
|
23
|
+
useSortable({
|
|
24
|
+
id: path,
|
|
25
|
+
disabled: immovable === "true"
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (type === "action") {
|
|
29
|
+
return null; // Skip action columns
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const style = {
|
|
33
|
+
transform: CSS.Transform.toString(transform),
|
|
34
|
+
transition,
|
|
35
|
+
cursor: "grab",
|
|
36
|
+
marginBottom: 5
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div
|
|
41
|
+
ref={setNodeRef}
|
|
42
|
+
style={style}
|
|
43
|
+
className="SortableItem"
|
|
44
|
+
data-path={path}
|
|
45
|
+
{...attributes}
|
|
46
|
+
{...listeners}
|
|
47
|
+
>
|
|
48
|
+
<Checkbox
|
|
49
|
+
name={`${path}-${index}`}
|
|
50
|
+
key={index}
|
|
51
|
+
onChange={() => {
|
|
52
|
+
if (numVisible <= 1 && !isHidden) {
|
|
53
|
+
return window.toastr.warning(
|
|
54
|
+
"We have to display at least one column :)"
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
onVisibilityChange({ shouldShow: isHidden, path });
|
|
58
|
+
}}
|
|
59
|
+
checked={!isHidden}
|
|
60
|
+
label={
|
|
61
|
+
<span style={{ display: "flex", marginTop: -17 }}>
|
|
62
|
+
{displayName}{" "}
|
|
63
|
+
{field.fieldGroup && (
|
|
64
|
+
<span
|
|
65
|
+
style={{ fontSize: 10, marginLeft: 5, marginTop: 2 }}
|
|
66
|
+
className={Classes.TEXT_MUTED}
|
|
67
|
+
>
|
|
68
|
+
({field.fieldGroup})
|
|
69
|
+
</span>
|
|
70
|
+
)}
|
|
71
|
+
{subFrag && (
|
|
72
|
+
<InfoHelper
|
|
73
|
+
icon="warning-sign"
|
|
74
|
+
intent="warning"
|
|
75
|
+
style={{ marginLeft: 5 }}
|
|
76
|
+
>
|
|
77
|
+
Viewing this column may cause the table to load slower
|
|
78
|
+
</InfoHelper>
|
|
79
|
+
)}
|
|
80
|
+
</span>
|
|
81
|
+
}
|
|
82
|
+
/>
|
|
83
|
+
</div>
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const DraggableColumnOptions = ({
|
|
88
|
+
fields,
|
|
89
|
+
onVisibilityChange,
|
|
90
|
+
moveColumnPersist,
|
|
91
|
+
numVisible
|
|
92
|
+
}) => {
|
|
93
|
+
const [sortedFields, setSortedFields] = useState(fields);
|
|
94
|
+
|
|
95
|
+
// Update sorted fields when external fields change
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
setSortedFields(fields);
|
|
98
|
+
}, [fields]);
|
|
99
|
+
|
|
100
|
+
const mouseSensor = useSensor(MouseSensor, {
|
|
101
|
+
activationConstraint: {
|
|
102
|
+
distance: 5
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const sensors = useSensors(mouseSensor);
|
|
107
|
+
|
|
108
|
+
const handleDragStart = event => {
|
|
109
|
+
// Add a class to the body to indicate dragging state
|
|
110
|
+
document.body.classList.add("column-dragging");
|
|
111
|
+
|
|
112
|
+
// Add a class to the active drag item
|
|
113
|
+
const { active } = event;
|
|
114
|
+
if (active) {
|
|
115
|
+
const activeNode = document.querySelector(`[data-path="${active.id}"]`);
|
|
116
|
+
if (activeNode) {
|
|
117
|
+
activeNode.classList.add("dragging");
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const handleDragEnd = event => {
|
|
123
|
+
// Remove the dragging class
|
|
124
|
+
document.body.classList.remove("column-dragging");
|
|
125
|
+
|
|
126
|
+
// Remove the class from the active drag item
|
|
127
|
+
const draggingItem = document.querySelector(".SortableItem.dragging");
|
|
128
|
+
if (draggingItem) {
|
|
129
|
+
draggingItem.classList.remove("dragging");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const { active, over } = event;
|
|
133
|
+
|
|
134
|
+
if (!over || !active || active.id === over.id) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const oldIndex = sortedFields.findIndex(f => f.path === active.id);
|
|
139
|
+
const newIndex = sortedFields.findIndex(f => f.path === over.id);
|
|
140
|
+
|
|
141
|
+
// Update the local state immediately for a smooth UI
|
|
142
|
+
const newSortedFields = arrayMove(sortedFields, oldIndex, newIndex);
|
|
143
|
+
setSortedFields(newSortedFields);
|
|
144
|
+
|
|
145
|
+
// Notify parent component to persist the change
|
|
146
|
+
moveColumnPersist({ oldIndex, newIndex });
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<DndContext
|
|
151
|
+
sensors={sensors}
|
|
152
|
+
modifiers={[restrictToVerticalAxis]}
|
|
153
|
+
onDragStart={handleDragStart}
|
|
154
|
+
onDragEnd={handleDragEnd}
|
|
155
|
+
>
|
|
156
|
+
<SortableContext
|
|
157
|
+
items={sortedFields.map(field => field.path)}
|
|
158
|
+
strategy={verticalListSortingStrategy}
|
|
159
|
+
>
|
|
160
|
+
<div>
|
|
161
|
+
{sortedFields.map((field, index) => (
|
|
162
|
+
<DraggableColumnOption
|
|
163
|
+
key={field.path || index}
|
|
164
|
+
field={field}
|
|
165
|
+
index={index}
|
|
166
|
+
onVisibilityChange={onVisibilityChange}
|
|
167
|
+
numVisible={numVisible}
|
|
168
|
+
/>
|
|
169
|
+
))}
|
|
170
|
+
</div>
|
|
171
|
+
</SortableContext>
|
|
172
|
+
</DndContext>
|
|
173
|
+
);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export default DraggableColumnOptions;
|
|
@@ -1,21 +1,34 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { useState, useEffect } from "react";
|
|
2
2
|
import { MouseSensor, useSensor, useSensors, DndContext } from "@dnd-kit/core";
|
|
3
3
|
import {
|
|
4
4
|
SortableContext,
|
|
5
|
-
horizontalListSortingStrategy
|
|
5
|
+
horizontalListSortingStrategy,
|
|
6
|
+
arrayMove as dndArrayMove
|
|
6
7
|
} from "@dnd-kit/sortable";
|
|
7
8
|
import { restrictToHorizontalAxis } from "@dnd-kit/modifiers";
|
|
8
9
|
|
|
9
10
|
const CustomTheadComponent = ({
|
|
10
11
|
children: _children,
|
|
11
12
|
className,
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
moveColumn,
|
|
14
|
+
sortedItemsFull,
|
|
14
15
|
style
|
|
15
16
|
}) => {
|
|
16
17
|
// We need to do this because react table gives the children wrapped
|
|
17
18
|
// in another component
|
|
18
19
|
const children = _children.props.children;
|
|
20
|
+
const [sortedItems, setSortedItems] = useState(() =>
|
|
21
|
+
children.map(c => {
|
|
22
|
+
// Use the path as the ID for sorting instead of the index
|
|
23
|
+
return c.props.path || c.key.split("-")[1];
|
|
24
|
+
})
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
// Update local state when children change
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
setSortedItems(children.map(c => c.props.path || c.key.split("-")[1]));
|
|
30
|
+
}, [children]);
|
|
31
|
+
|
|
19
32
|
const mouseSensor = useSensor(MouseSensor, {
|
|
20
33
|
activationConstraint: {
|
|
21
34
|
distance: 10
|
|
@@ -34,15 +47,21 @@ const CustomTheadComponent = ({
|
|
|
34
47
|
return;
|
|
35
48
|
}
|
|
36
49
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
50
|
+
// Update local state immediately for smooth UI
|
|
51
|
+
// Use path ID directly instead of parsing as integer
|
|
52
|
+
const oldPath = active.id;
|
|
53
|
+
const newPath = over.id;
|
|
54
|
+
const oldIndex = sortedItemsFull.indexOf(oldPath);
|
|
55
|
+
const newIndex = sortedItemsFull.indexOf(newPath);
|
|
56
|
+
const newSortedItems = dndArrayMove(sortedItemsFull, oldIndex, newIndex);
|
|
57
|
+
setSortedItems(newSortedItems);
|
|
58
|
+
|
|
59
|
+
// Pass to parent for persistence
|
|
60
|
+
moveColumn({ oldIndex, newIndex });
|
|
41
61
|
};
|
|
42
62
|
|
|
43
63
|
return (
|
|
44
64
|
<DndContext
|
|
45
|
-
onDragStart={onSortStart}
|
|
46
65
|
onDragEnd={handleDragEnd}
|
|
47
66
|
modifiers={[restrictToHorizontalAxis]}
|
|
48
67
|
sensors={sensors}
|
|
@@ -50,7 +69,7 @@ const CustomTheadComponent = ({
|
|
|
50
69
|
<div className={"rt-thead " + className} style={style}>
|
|
51
70
|
<div className="rt-tr">
|
|
52
71
|
<SortableContext
|
|
53
|
-
items={
|
|
72
|
+
items={sortedItems}
|
|
54
73
|
strategy={horizontalListSortingStrategy}
|
|
55
74
|
>
|
|
56
75
|
{children}
|
|
@@ -61,7 +80,13 @@ const CustomTheadComponent = ({
|
|
|
61
80
|
);
|
|
62
81
|
};
|
|
63
82
|
|
|
64
|
-
const SortableColumns = ({
|
|
83
|
+
const SortableColumns = ({
|
|
84
|
+
className,
|
|
85
|
+
style,
|
|
86
|
+
children,
|
|
87
|
+
moveColumn,
|
|
88
|
+
sortedItemsFull
|
|
89
|
+
}) => {
|
|
65
90
|
const shouldCancelStart = e => {
|
|
66
91
|
const className = e.target.className;
|
|
67
92
|
// if its an svg then it's a blueprint icon
|
|
@@ -70,25 +95,12 @@ const SortableColumns = ({ className, style, children, moveColumn }) => {
|
|
|
70
95
|
);
|
|
71
96
|
};
|
|
72
97
|
|
|
73
|
-
const onSortEnd = (...args) => {
|
|
74
|
-
const { oldIndex, newIndex } = args[0];
|
|
75
|
-
document.body.classList.remove("drag-active");
|
|
76
|
-
moveColumn({
|
|
77
|
-
oldIndex,
|
|
78
|
-
newIndex
|
|
79
|
-
});
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const onSortStart = () => {
|
|
83
|
-
document.body.classList.add("drag-active");
|
|
84
|
-
};
|
|
85
|
-
|
|
86
98
|
return (
|
|
87
99
|
<CustomTheadComponent
|
|
88
100
|
className={className}
|
|
89
101
|
style={style}
|
|
90
|
-
|
|
91
|
-
|
|
102
|
+
sortedItemsFull={sortedItemsFull}
|
|
103
|
+
moveColumn={moveColumn}
|
|
92
104
|
helperClass="above-dialog"
|
|
93
105
|
shouldCancelStart={shouldCancelStart}
|
|
94
106
|
>
|
|
@@ -9,19 +9,31 @@ export const ThComponent = ({
|
|
|
9
9
|
className,
|
|
10
10
|
children,
|
|
11
11
|
style,
|
|
12
|
+
path,
|
|
12
13
|
columnindex,
|
|
13
14
|
...rest
|
|
14
15
|
}) => {
|
|
15
|
-
const index = columnindex
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
const index = columnindex ? path : -1;
|
|
17
|
+
const disabled = !path || immovable === "true" || immovable === true;
|
|
18
|
+
const {
|
|
19
|
+
attributes,
|
|
20
|
+
listeners,
|
|
21
|
+
setNodeRef,
|
|
22
|
+
transform,
|
|
23
|
+
transition,
|
|
24
|
+
isDragging: _isDragging
|
|
25
|
+
} = useSortable({
|
|
26
|
+
id: path,
|
|
27
|
+
disabled
|
|
28
|
+
});
|
|
29
|
+
const isDragging = _isDragging && !disabled;
|
|
30
|
+
if (transform) {
|
|
31
|
+
transform.scaleX = 1; // Prevent column header from shrinking/expanding during drag (looks bad)
|
|
32
|
+
}
|
|
22
33
|
const sortStyles = {
|
|
23
34
|
transform: CSS.Transform.toString(transform),
|
|
24
|
-
transition
|
|
35
|
+
transition,
|
|
36
|
+
zIndex: isDragging ? 999 : undefined
|
|
25
37
|
};
|
|
26
38
|
|
|
27
39
|
return (
|
|
@@ -30,11 +42,12 @@ export const ThComponent = ({
|
|
|
30
42
|
ref={setNodeRef}
|
|
31
43
|
{...attributes}
|
|
32
44
|
{...listeners}
|
|
33
|
-
className={classNames("rt-th", className)}
|
|
45
|
+
className={classNames("rt-th", className, { "th-dragging": isDragging })}
|
|
34
46
|
onClick={e => toggleSort && toggleSort(e)}
|
|
35
47
|
role="columnheader"
|
|
36
48
|
tabIndex="-1" // Resolves eslint issues without implementing keyboard navigation incorrectly
|
|
37
49
|
columnindex={columnindex}
|
|
50
|
+
path={path}
|
|
38
51
|
index={index}
|
|
39
52
|
{...rest}
|
|
40
53
|
>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Classes, Icon } from "@blueprintjs/core";
|
|
2
|
+
|
|
3
|
+
export const dragNoticeEl = (
|
|
4
|
+
<div
|
|
5
|
+
className={Classes.TEXT_MUTED}
|
|
6
|
+
style={{
|
|
7
|
+
padding: 10,
|
|
8
|
+
fontSize: "12px"
|
|
9
|
+
}}
|
|
10
|
+
>
|
|
11
|
+
<Icon icon="info-sign" size={12} /> Drag columns to reorder them
|
|
12
|
+
</div>
|
|
13
|
+
);
|