mirror of
https://github.com/rowyio/rowy.git
synced 2025-12-29 00:16:39 +01:00
dnd column ordering
This commit is contained in:
@@ -33,6 +33,8 @@
|
||||
"react-color": "^2.17.3",
|
||||
"react-data-grid": "^7.0.0-canary.27",
|
||||
"react-div-100vh": "^0.3.8",
|
||||
"react-dnd": "^11.1.3",
|
||||
"react-dnd-html5-backend": "^11.1.3",
|
||||
"react-dom": "^16.9.0",
|
||||
"react-dropzone": "^10.1.8",
|
||||
"react-hook-form": "^6.5.0",
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React from "react";
|
||||
import clsx from "clsx";
|
||||
import { Column } from "react-data-grid";
|
||||
|
||||
import { Column, HeaderRendererProps } from "react-data-grid";
|
||||
import { useDrag, useDrop, DragObjectWithType } from "react-dnd";
|
||||
import { useCombinedRefs } from "react-data-grid/lib/hooks";
|
||||
import {
|
||||
makeStyles,
|
||||
createStyles,
|
||||
@@ -85,7 +86,15 @@ const useStyles = makeStyles((theme) =>
|
||||
})
|
||||
);
|
||||
|
||||
const ColumnHeader: Column<any>["headerRenderer"] = ({ column }) => {
|
||||
interface ColumnDragObject extends DragObjectWithType {
|
||||
key: string;
|
||||
}
|
||||
|
||||
export default function DraggableHeaderRenderer<R>({
|
||||
column,
|
||||
}: HeaderRendererProps<R> & {
|
||||
onColumnsReorder: (sourceKey: string, targetKey: string) => void;
|
||||
}) {
|
||||
const classes = useStyles();
|
||||
|
||||
const {
|
||||
@@ -94,6 +103,28 @@ const ColumnHeader: Column<any>["headerRenderer"] = ({ column }) => {
|
||||
userClaims,
|
||||
columnMenuRef,
|
||||
} = useFiretableContext();
|
||||
const [{ isDragging }, drag] = useDrag({
|
||||
item: { key: column.key, type: "COLUMN_DRAG" },
|
||||
collect: (monitor) => ({
|
||||
isDragging: !!monitor.isDragging(),
|
||||
}),
|
||||
});
|
||||
|
||||
const [{ isOver }, drop] = useDrop({
|
||||
accept: "COLUMN_DRAG",
|
||||
drop({ key, type }: ColumnDragObject) {
|
||||
if (type === "COLUMN_DRAG") {
|
||||
// onColumnsReorder(key, props.column.key);
|
||||
tableActions?.column.reorder(key, column.key);
|
||||
}
|
||||
},
|
||||
collect: (monitor) => ({
|
||||
isOver: !!monitor.isOver(),
|
||||
canDrop: !!monitor.canDrop(),
|
||||
}),
|
||||
});
|
||||
|
||||
const headerRef = useCombinedRefs(drag, drop);
|
||||
if (!columnMenuRef || !tableState || !tableActions) return null;
|
||||
const { orderBy } = tableState;
|
||||
|
||||
@@ -124,7 +155,18 @@ const ColumnHeader: Column<any>["headerRenderer"] = ({ column }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container className={classes.root} alignItems="center" wrap="nowrap">
|
||||
<Grid
|
||||
ref={headerRef}
|
||||
container
|
||||
className={classes.root}
|
||||
style={{
|
||||
opacity: isDragging ? 0.5 : 1,
|
||||
backgroundColor: isOver ? "#ececec" : "inherit",
|
||||
cursor: "move",
|
||||
}}
|
||||
alignItems="center"
|
||||
wrap="nowrap"
|
||||
>
|
||||
<Tooltip
|
||||
title={
|
||||
<>
|
||||
@@ -215,6 +257,16 @@ const ColumnHeader: Column<any>["headerRenderer"] = ({ column }) => {
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default ColumnHeader;
|
||||
// return (
|
||||
// <div
|
||||
// ref={useCombinedRefs(drag, drop)}
|
||||
// style={{
|
||||
// opacity: isDragging ? 0.5 : 1,
|
||||
// backgroundColor: isOver ? '#ececec' : 'inherit',
|
||||
// cursor: 'move'
|
||||
// }}
|
||||
// >
|
||||
// {props.column.name}
|
||||
// </div>
|
||||
// );
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ import _orderBy from "lodash/orderBy";
|
||||
import _isEmpty from "lodash/isEmpty";
|
||||
import _find from "lodash/find";
|
||||
import _difference from "lodash/difference";
|
||||
|
||||
import { DndProvider } from "react-dnd";
|
||||
import { HTML5Backend } from "react-dnd-html5-backend";
|
||||
import BulkActions from "./BulkActions";
|
||||
import "react-data-grid/dist/react-data-grid.css";
|
||||
import DataGrid, {
|
||||
@@ -29,7 +30,6 @@ import useWindowSize from "hooks/useWindowSize";
|
||||
import useStyles from "./styles";
|
||||
import { useAppContext } from "contexts/appContext";
|
||||
import _get from "lodash/get";
|
||||
// const Hotkeys = lazy(() => import("./HotKeys" /* webpackChunkName: "HotKeys" */));
|
||||
|
||||
export type FiretableColumn = Column<any> & {
|
||||
isNew?: boolean;
|
||||
@@ -116,8 +116,8 @@ export default function Table() {
|
||||
),
|
||||
[columns, tableState?.rows]
|
||||
) ?? [];
|
||||
const rowsContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const rowsContainerRef = useRef<HTMLDivElement>(null);
|
||||
const [selectedRowsSet, setSelectedRowsSet] = useState<Set<React.Key>>();
|
||||
const [selectedRows, setSelectedRows] = useState<any[]>([]);
|
||||
// Gets more rows when scrolled down.
|
||||
@@ -161,113 +161,96 @@ export default function Table() {
|
||||
/>
|
||||
|
||||
{!tableState.loadingColumns ? (
|
||||
<DataGrid
|
||||
onColumnResize={tableActions.column.resize}
|
||||
onScroll={handleScroll}
|
||||
ref={dataGridRef}
|
||||
rows={rows}
|
||||
columns={columns as any}
|
||||
rowHeight={rowHeight ?? 43}
|
||||
headerRowHeight={44}
|
||||
className="rdg-light" // Handle dark mode in MUI theme
|
||||
enableCellCopyPaste
|
||||
enableCellDragAndDrop
|
||||
cellNavigationMode="LOOP_OVER_ROW"
|
||||
rowKeyGetter={rowKeyGetter}
|
||||
selectedRows={selectedRowsSet}
|
||||
onSelectedRowsChange={(newSelectedSet) => {
|
||||
const newSelectedArray = newSelectedSet
|
||||
? [...newSelectedSet]
|
||||
: [];
|
||||
const prevSelectedRowsArray = selectedRowsSet
|
||||
? [...selectedRowsSet]
|
||||
: [];
|
||||
const addedSelections = _difference(
|
||||
newSelectedArray,
|
||||
prevSelectedRowsArray
|
||||
);
|
||||
const removedSelections = _difference(
|
||||
prevSelectedRowsArray,
|
||||
newSelectedArray
|
||||
);
|
||||
addedSelections.forEach((id) => {
|
||||
const newRow = _find(rows, { id });
|
||||
setSelectedRows([...selectedRows, newRow]);
|
||||
});
|
||||
removedSelections.forEach((rowId) => {
|
||||
setSelectedRows(selectedRows.filter((row) => row.id !== rowId));
|
||||
});
|
||||
setSelectedRowsSet(newSelectedSet);
|
||||
}}
|
||||
onRowsUpdate={(e) => {
|
||||
const { action, fromRow, toRow, updated, cellKey } = e;
|
||||
switch (action) {
|
||||
case "CELL_UPDATE":
|
||||
break;
|
||||
case "CELL_DRAG":
|
||||
if (toRow > fromRow)
|
||||
[...rows]
|
||||
.splice(fromRow, toRow - fromRow + 1)
|
||||
.forEach((row) => row.ref.update(updated));
|
||||
if (toRow < fromRow)
|
||||
[...rows]
|
||||
.splice(toRow, fromRow - toRow + 1)
|
||||
.forEach((row) => row.ref.update(updated));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}}
|
||||
onRowClick={(rowIdx, row, column) => {
|
||||
if (sideDrawerRef?.current) {
|
||||
sideDrawerRef.current.setCell({
|
||||
row: rowIdx,
|
||||
column: column.key as string,
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<DataGrid
|
||||
onColumnResize={tableActions.column.resize}
|
||||
onScroll={handleScroll}
|
||||
ref={dataGridRef}
|
||||
rows={rows}
|
||||
columns={columns}
|
||||
rowHeight={rowHeight ?? 43}
|
||||
headerRowHeight={44}
|
||||
className="rdg-light" // Handle dark mode in MUI theme
|
||||
enableCellCopyPaste
|
||||
enableCellDragAndDrop
|
||||
cellNavigationMode="LOOP_OVER_ROW"
|
||||
rowKeyGetter={rowKeyGetter}
|
||||
selectedRows={selectedRowsSet}
|
||||
onSelectedRowsChange={(newSelectedSet) => {
|
||||
const newSelectedArray = newSelectedSet
|
||||
? [...newSelectedSet]
|
||||
: [];
|
||||
const prevSelectedRowsArray = selectedRowsSet
|
||||
? [...selectedRowsSet]
|
||||
: [];
|
||||
const addedSelections = _difference(
|
||||
newSelectedArray,
|
||||
prevSelectedRowsArray
|
||||
);
|
||||
const removedSelections = _difference(
|
||||
prevSelectedRowsArray,
|
||||
newSelectedArray
|
||||
);
|
||||
addedSelections.forEach((id) => {
|
||||
const newRow = _find(rows, { id });
|
||||
setSelectedRows([...selectedRows, newRow]);
|
||||
});
|
||||
}
|
||||
}}
|
||||
|
||||
// onGridRowsUpdated={(event) => {
|
||||
// const { action, cellKey, updated } = event;
|
||||
// if (action === "CELL_UPDATE" && updated !== null)
|
||||
// updateCell!(rows[event.toRow].ref, cellKey as string, updated);
|
||||
// }}
|
||||
|
||||
// TODO: Investigate why setting a numeric value causes
|
||||
// LOADING to pop up on screen when scrolling horizontally
|
||||
// width={windowSize.width - DRAWER_COLLAPSED_WIDTH}
|
||||
// minWidth={tableWidth}
|
||||
// minHeight={windowSize.height - APP_BAR_HEIGHT - TABLE_HEADER_HEIGHT}
|
||||
// enableCellCopyPaste
|
||||
// enableCellDragAndDrop
|
||||
|
||||
//cellNavigationMode={CellNavigationMode.CHANGE_ROW}
|
||||
|
||||
// onCheckCellIsEditable={({ column }) =>
|
||||
// Boolean(
|
||||
// column.editable &&
|
||||
// column.editor?.displayName &&
|
||||
// column.editor?.displayName === "WithStyles(TextEditor)"
|
||||
// )
|
||||
// }
|
||||
// enableCellSelect
|
||||
|
||||
// RowsContainer={(props) => (
|
||||
// <>
|
||||
// <div {...props} ref={rowsContainerRef} />
|
||||
// <Grid
|
||||
// container
|
||||
// className={classes.loadingContainer}
|
||||
// alignItems="center"
|
||||
// justify="center"
|
||||
// >
|
||||
// {tableState.rows.length > 0 && tableState.loadingRows && (
|
||||
// <CircularProgress disableShrink />
|
||||
// )}
|
||||
// </Grid>
|
||||
// </>
|
||||
// )}
|
||||
/>
|
||||
removedSelections.forEach((rowId) => {
|
||||
setSelectedRows(
|
||||
selectedRows.filter((row) => row.id !== rowId)
|
||||
);
|
||||
});
|
||||
setSelectedRowsSet(newSelectedSet);
|
||||
}}
|
||||
onRowsUpdate={(e) => {
|
||||
const { action, fromRow, toRow, updated, cellKey } = e;
|
||||
switch (action) {
|
||||
case "CELL_UPDATE":
|
||||
break;
|
||||
case "CELL_DRAG":
|
||||
if (toRow > fromRow)
|
||||
[...rows]
|
||||
.splice(fromRow, toRow - fromRow + 1)
|
||||
.forEach((row) => row.ref.update(updated));
|
||||
if (toRow < fromRow)
|
||||
[...rows]
|
||||
.splice(toRow, fromRow - toRow + 1)
|
||||
.forEach((row) => row.ref.update(updated));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}}
|
||||
onRowClick={(rowIdx, row, column) => {
|
||||
if (sideDrawerRef?.current) {
|
||||
sideDrawerRef.current.setCell({
|
||||
row: rowIdx,
|
||||
column: column.key as string,
|
||||
});
|
||||
}
|
||||
}}
|
||||
// TODO: Investigate why setting a numeric value causes
|
||||
// LOADING to pop up on screen when scrolling horizontally
|
||||
// width={windowSize.width - DRAWER_COLLAPSED_WIDTH}
|
||||
// minWidth={tableWidth}
|
||||
// minHeight={windowSize.height - APP_BAR_HEIGHT - TABLE_HEADER_HEIGHT}
|
||||
// RowsContainer={(props) => (
|
||||
// <>
|
||||
// <div {...props} ref={rowsContainerRef} />
|
||||
// <Grid
|
||||
// container
|
||||
// className={classes.loadingContainer}
|
||||
// alignItems="center"
|
||||
// justify="center"
|
||||
// >
|
||||
// {tableState.rows.length > 0 && tableState.loadingRows && (
|
||||
// <CircularProgress disableShrink />
|
||||
// )}
|
||||
// </Grid>
|
||||
// </>
|
||||
// )}
|
||||
/>
|
||||
</DndProvider>
|
||||
) : (
|
||||
<Loading message="Fetching columns" />
|
||||
)}
|
||||
|
||||
@@ -2286,6 +2286,21 @@
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
|
||||
integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
|
||||
|
||||
"@react-dnd/asap@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-dnd/asap/-/asap-4.0.0.tgz#b300eeed83e9801f51bd66b0337c9a6f04548651"
|
||||
integrity sha512-0XhqJSc6pPoNnf8DhdsPHtUhRzZALVzYMTzRwV4VI6DJNJ/5xxfL9OQUwb8IH5/2x7lSf7nAZrnzUD+16VyOVQ==
|
||||
|
||||
"@react-dnd/invariant@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-dnd/invariant/-/invariant-2.0.0.tgz#09d2e81cd39e0e767d7da62df9325860f24e517e"
|
||||
integrity sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==
|
||||
|
||||
"@react-dnd/shallowequal@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz#a3031eb54129f2c66b2753f8404266ec7bf67f0a"
|
||||
integrity sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==
|
||||
|
||||
"@sindresorhus/is@^0.14.0":
|
||||
version "0.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
|
||||
@@ -2508,6 +2523,14 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.5.tgz#527d20ef68571a4af02ed74350164e7a67544860"
|
||||
integrity sha512-wLD/Aq2VggCJXSjxEwrMafIP51Z+13H78nXIX0ABEuIGhmB5sNGbR113MOKo+yfw+RDo1ZU3DM6yfnnRF/+ouw==
|
||||
|
||||
"@types/hoist-non-react-statics@^3.3.1":
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
|
||||
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
hoist-non-react-statics "^3.3.0"
|
||||
|
||||
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff"
|
||||
@@ -5481,6 +5504,15 @@ dir-glob@2.0.0:
|
||||
arrify "^1.0.1"
|
||||
path-type "^3.0.0"
|
||||
|
||||
dnd-core@^11.1.3:
|
||||
version "11.1.3"
|
||||
resolved "https://registry.yarnpkg.com/dnd-core/-/dnd-core-11.1.3.tgz#f92099ba7245e49729d2433157031a6267afcc98"
|
||||
integrity sha512-QugF55dNW+h+vzxVJ/LSJeTeUw9MCJ2cllhmVThVPEtF16ooBkxj0WBE5RB+AceFxMFo1rO6bJKXtqKl+JNnyA==
|
||||
dependencies:
|
||||
"@react-dnd/asap" "^4.0.0"
|
||||
"@react-dnd/invariant" "^2.0.0"
|
||||
redux "^4.0.4"
|
||||
|
||||
dns-equal@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
|
||||
@@ -12350,6 +12382,23 @@ react-div-100vh@^0.3.8:
|
||||
resolved "https://registry.yarnpkg.com/react-div-100vh/-/react-div-100vh-0.3.8.tgz#54e4c32d0286a65e92367fc0a07cc3f2f00739d8"
|
||||
integrity sha512-1kDFW+HXYpfac1tfJ4BcQmgTSeTtLVs2FO2ZNHcwLIga+oVluexUEISCBJvr9xq98DK8tcygY3259EvIy5O+3g==
|
||||
|
||||
react-dnd-html5-backend@^11.1.3:
|
||||
version "11.1.3"
|
||||
resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-11.1.3.tgz#2749f04f416ec230ea193f5c1fbea2de7dffb8f7"
|
||||
integrity sha512-/1FjNlJbW/ivkUxlxQd7o3trA5DE33QiRZgxent3zKme8DwF4Nbw3OFVhTRFGaYhHFNL1rZt6Rdj1D78BjnNLw==
|
||||
dependencies:
|
||||
dnd-core "^11.1.3"
|
||||
|
||||
react-dnd@^11.1.3:
|
||||
version "11.1.3"
|
||||
resolved "https://registry.yarnpkg.com/react-dnd/-/react-dnd-11.1.3.tgz#f9844f5699ccc55dfc81462c2c19f726e670c1af"
|
||||
integrity sha512-8rtzzT8iwHgdSC89VktwhqdKKtfXaAyC4wiqp0SywpHG12TTLvfOoL6xNEIUWXwIEWu+CFfDn4GZJyynCEuHIQ==
|
||||
dependencies:
|
||||
"@react-dnd/shallowequal" "^2.0.0"
|
||||
"@types/hoist-non-react-statics" "^3.3.1"
|
||||
dnd-core "^11.1.3"
|
||||
hoist-non-react-statics "^3.3.0"
|
||||
|
||||
react-dom@^16.9.0:
|
||||
version "16.13.0"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.0.tgz#cdde54b48eb9e8a0ca1b3dc9943d9bb409b81866"
|
||||
|
||||
Reference in New Issue
Block a user