feature/IO-3545-Production-Board-List-DND - Checkpoint
This commit is contained in:
106
client/package-lock.json
generated
106
client/package-lock.json
generated
@@ -12,6 +12,10 @@
|
|||||||
"@amplitude/analytics-browser": "^2.34.0",
|
"@amplitude/analytics-browser": "^2.34.0",
|
||||||
"@ant-design/pro-layout": "^7.22.6",
|
"@ant-design/pro-layout": "^7.22.6",
|
||||||
"@apollo/client": "^4.1.3",
|
"@apollo/client": "^4.1.3",
|
||||||
|
"@dnd-kit/core": "^6.3.1",
|
||||||
|
"@dnd-kit/modifiers": "^9.0.0",
|
||||||
|
"@dnd-kit/sortable": "^10.0.0",
|
||||||
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
"@emotion/is-prop-valid": "^1.4.0",
|
"@emotion/is-prop-valid": "^1.4.0",
|
||||||
"@fingerprintjs/fingerprintjs": "^5.0.1",
|
"@fingerprintjs/fingerprintjs": "^5.0.1",
|
||||||
"@firebase/analytics": "^0.10.19",
|
"@firebase/analytics": "^0.10.19",
|
||||||
@@ -60,7 +64,6 @@
|
|||||||
"react-color": "^2.19.3",
|
"react-color": "^2.19.3",
|
||||||
"react-cookie": "^8.0.1",
|
"react-cookie": "^8.0.1",
|
||||||
"react-dom": "^19.2.4",
|
"react-dom": "^19.2.4",
|
||||||
"react-drag-listview": "^2.0.0",
|
|
||||||
"react-grid-gallery": "^1.0.1",
|
"react-grid-gallery": "^1.0.1",
|
||||||
"react-grid-layout": "^2.2.2",
|
"react-grid-layout": "^2.2.2",
|
||||||
"react-i18next": "^16.5.4",
|
"react-i18next": "^16.5.4",
|
||||||
@@ -2494,6 +2497,73 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@dnd-kit/accessibility": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@dnd-kit/core": {
|
||||||
|
"version": "6.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz",
|
||||||
|
"integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@dnd-kit/accessibility": "^3.1.1",
|
||||||
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.0",
|
||||||
|
"react-dom": ">=16.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@dnd-kit/modifiers": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@dnd-kit/modifiers/-/modifiers-9.0.0.tgz",
|
||||||
|
"integrity": "sha512-ybiLc66qRGuZoC20wdSSG6pDXFikui/dCNGthxv4Ndy8ylErY0N3KVxY2bgo7AWwIbxDmXDg3ylAFmnrjcbVvw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@dnd-kit/core": "^6.3.0",
|
||||||
|
"react": ">=16.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@dnd-kit/sortable": {
|
||||||
|
"version": "10.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-10.0.0.tgz",
|
||||||
|
"integrity": "sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@dnd-kit/core": "^6.3.0",
|
||||||
|
"react": ">=16.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@dnd-kit/utilities": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@dotenvx/dotenvx": {
|
"node_modules/@dotenvx/dotenvx": {
|
||||||
"version": "1.52.0",
|
"version": "1.52.0",
|
||||||
"resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.52.0.tgz",
|
"resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.52.0.tgz",
|
||||||
@@ -8396,16 +8466,6 @@
|
|||||||
"@babel/types": "^7.26.0"
|
"@babel/types": "^7.26.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/babel-runtime": {
|
|
||||||
"version": "6.26.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
|
|
||||||
"integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"core-js": "^2.4.0",
|
|
||||||
"regenerator-runtime": "^0.11.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/bail": {
|
"node_modules/bail": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
|
||||||
@@ -9192,14 +9252,6 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/core-js": {
|
|
||||||
"version": "2.6.12",
|
|
||||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
|
|
||||||
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
|
|
||||||
"deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.",
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/core-js-compat": {
|
"node_modules/core-js-compat": {
|
||||||
"version": "3.47.0",
|
"version": "3.47.0",
|
||||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.47.0.tgz",
|
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.47.0.tgz",
|
||||||
@@ -15376,16 +15428,6 @@
|
|||||||
"react": "^19.2.4"
|
"react": "^19.2.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-drag-listview": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-drag-listview/-/react-drag-listview-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-7Apx/1Xt4qu+JHHP0rH6aLgZgS7c2MX8ocHVGCi03KfeIWEu0t14MhT3boQKM33l5eJrE/IWfExFTvoYq22fsg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"babel-runtime": "^6.26.0",
|
|
||||||
"prop-types": "^15.5.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-draggable": {
|
"node_modules/react-draggable": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.5.0.tgz",
|
||||||
@@ -15972,12 +16014,6 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/regenerator-runtime": {
|
|
||||||
"version": "0.11.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
|
|
||||||
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/regexp.prototype.flags": {
|
"node_modules/regexp.prototype.flags": {
|
||||||
"version": "1.5.4",
|
"version": "1.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
|
||||||
|
|||||||
@@ -11,6 +11,10 @@
|
|||||||
"@amplitude/analytics-browser": "^2.34.0",
|
"@amplitude/analytics-browser": "^2.34.0",
|
||||||
"@ant-design/pro-layout": "^7.22.6",
|
"@ant-design/pro-layout": "^7.22.6",
|
||||||
"@apollo/client": "^4.1.3",
|
"@apollo/client": "^4.1.3",
|
||||||
|
"@dnd-kit/core": "^6.3.1",
|
||||||
|
"@dnd-kit/modifiers": "^9.0.0",
|
||||||
|
"@dnd-kit/sortable": "^10.0.0",
|
||||||
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
"@emotion/is-prop-valid": "^1.4.0",
|
"@emotion/is-prop-valid": "^1.4.0",
|
||||||
"@fingerprintjs/fingerprintjs": "^5.0.1",
|
"@fingerprintjs/fingerprintjs": "^5.0.1",
|
||||||
"@firebase/analytics": "^0.10.19",
|
"@firebase/analytics": "^0.10.19",
|
||||||
@@ -59,7 +63,6 @@
|
|||||||
"react-color": "^2.19.3",
|
"react-color": "^2.19.3",
|
||||||
"react-cookie": "^8.0.1",
|
"react-cookie": "^8.0.1",
|
||||||
"react-dom": "^19.2.4",
|
"react-dom": "^19.2.4",
|
||||||
"react-drag-listview": "^2.0.0",
|
|
||||||
"react-grid-gallery": "^1.0.1",
|
"react-grid-gallery": "^1.0.1",
|
||||||
"react-grid-layout": "^2.2.2",
|
"react-grid-layout": "^2.2.2",
|
||||||
"react-i18next": "^16.5.4",
|
"react-i18next": "^16.5.4",
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
import { SyncOutlined } from "@ant-design/icons";
|
import { HolderOutlined, SyncOutlined } from "@ant-design/icons";
|
||||||
import { PageHeader } from "@ant-design/pro-layout";
|
import { PageHeader } from "@ant-design/pro-layout";
|
||||||
import { useTreatmentsWithConfig } from "@splitsoftware/splitio-react";
|
import { useTreatmentsWithConfig } from "@splitsoftware/splitio-react";
|
||||||
import { Button, Dropdown, Input, Space, Statistic, Table } from "antd";
|
import { Button, Dropdown, Input, Space, Statistic, Table } from "antd";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import ReactDragListView from "react-drag-listview";
|
import { DndContext, DragOverlay, PointerSensor, useSensor, useSensors, closestCenter } from "@dnd-kit/core";
|
||||||
|
import { arrayMove, horizontalListSortingStrategy, SortableContext, useSortable } from "@dnd-kit/sortable";
|
||||||
|
import { CSS } from "@dnd-kit/utilities";
|
||||||
|
import { restrictToHorizontalAxis } from "@dnd-kit/modifiers";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||||
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
||||||
|
import { selectDarkMode } from "../../redux/application/application.selectors.js";
|
||||||
import Prompt from "../../utils/prompt.js";
|
import Prompt from "../../utils/prompt.js";
|
||||||
import AlertComponent from "../alert/alert.component.jsx";
|
import AlertComponent from "../alert/alert.component.jsx";
|
||||||
import ProductionListColumnsAdd from "../production-list-columns/production-list-columns.add.component";
|
import ProductionListColumnsAdd from "../production-list-columns/production-list-columns.add.component";
|
||||||
@@ -23,12 +27,108 @@ import { logImEXEvent } from "../../firebase/firebase.utils.js";
|
|||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
technician: selectTechnician,
|
technician: selectTechnician,
|
||||||
currentUser: selectCurrentUser
|
currentUser: selectCurrentUser,
|
||||||
|
isDarkMode: selectDarkMode
|
||||||
});
|
});
|
||||||
|
|
||||||
export function ProductionListTable({ loading, data, refetch, bodyshop, technician, currentUser }) {
|
// Draggable header cell component - combines drag and resize
|
||||||
|
function DraggableHeaderCell(props) {
|
||||||
|
const { children, columnKey, onResize, width, ...restProps } = props;
|
||||||
|
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
|
||||||
|
id: columnKey,
|
||||||
|
disabled: !columnKey
|
||||||
|
});
|
||||||
|
|
||||||
|
const style = {
|
||||||
|
...restProps.style,
|
||||||
|
transform: CSS.Transform.toString(transform),
|
||||||
|
transition,
|
||||||
|
cursor: "move",
|
||||||
|
opacity: isDragging ? 0.3 : 1
|
||||||
|
};
|
||||||
|
|
||||||
|
// If no columnKey, render as regular header
|
||||||
|
if (!columnKey) {
|
||||||
|
return <ResizeableTitle {...props} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine drag functionality with resize
|
||||||
|
return (
|
||||||
|
<ResizeableTitle
|
||||||
|
{...restProps}
|
||||||
|
ref={setNodeRef}
|
||||||
|
style={style}
|
||||||
|
onResize={onResize}
|
||||||
|
width={width}
|
||||||
|
dragAttributes={attributes}
|
||||||
|
dragListeners={listeners}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</ResizeableTitle>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draggable column title component
|
||||||
|
// function DraggableColumnTitle({ col, onRemove, t }) {
|
||||||
|
// const { attributes, listeners, setNodeRef, isDragging } = useSortable({
|
||||||
|
// id: col.key
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// const menu = {
|
||||||
|
// onClick: onRemove,
|
||||||
|
// items: [
|
||||||
|
// {
|
||||||
|
// key: col.key,
|
||||||
|
// label: t("production.actions.removecolumn")
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// const style = {
|
||||||
|
// display: "flex",
|
||||||
|
// alignItems: "center",
|
||||||
|
// width: "100%",
|
||||||
|
// opacity: isDragging ? 0.4 : 1
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// return (
|
||||||
|
// <div ref={setNodeRef} style={style}>
|
||||||
|
// <span
|
||||||
|
// {...attributes}
|
||||||
|
// {...listeners}
|
||||||
|
// style={{
|
||||||
|
// cursor: "grab",
|
||||||
|
// display: "inline-flex",
|
||||||
|
// alignItems: "center",
|
||||||
|
// padding: "0 4px",
|
||||||
|
// marginRight: "4px",
|
||||||
|
// color: "#999",
|
||||||
|
// fontSize: "14px",
|
||||||
|
// flexShrink: 0
|
||||||
|
// }}
|
||||||
|
// className="drag-handle"
|
||||||
|
// title="Drag to reorder column"
|
||||||
|
// >
|
||||||
|
// <HolderOutlined />
|
||||||
|
// </span>
|
||||||
|
// <Dropdown className="prod-header-dropdown" menu={menu} trigger={["contextMenu"]}>
|
||||||
|
// <span style={{ flex: 1 }}>{col.title}</span>
|
||||||
|
// </Dropdown>
|
||||||
|
// </div>
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
export function ProductionListTable({ loading, data, refetch, bodyshop, technician, currentUser, isDarkMode }) {
|
||||||
const [searchText, setSearchText] = useState("");
|
const [searchText, setSearchText] = useState("");
|
||||||
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
|
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
|
||||||
|
const [activeId, setActiveId] = useState(null);
|
||||||
|
const sensors = useSensors(
|
||||||
|
useSensor(PointerSensor, {
|
||||||
|
activationConstraint: {
|
||||||
|
distance: 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
const {
|
const {
|
||||||
treatments: { Production_List_Status_Colors, Enhanced_Payroll }
|
treatments: { Production_List_Status_Colors, Enhanced_Payroll }
|
||||||
} = useTreatmentsWithConfig({
|
} = useTreatmentsWithConfig({
|
||||||
@@ -118,17 +218,30 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici
|
|||||||
logImEXEvent("production_list_sort_filter", { pagination, filters, sorter });
|
logImEXEvent("production_list_sort_filter", { pagination, filters, sorter });
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDragEnd = (fromIndex, toIndex) => {
|
const onDragStart = ({ active }) => {
|
||||||
if (fromIndex === toIndex) return;
|
setActiveId(active.id);
|
||||||
const columnsCopy = [...columns];
|
};
|
||||||
const [movedItem] = columnsCopy.splice(fromIndex, 1);
|
|
||||||
columnsCopy.splice(toIndex, 0, movedItem);
|
const onDragEnd = ({ active, over }) => {
|
||||||
if (!_.isEqual(columnsCopy, columns)) {
|
setActiveId(null);
|
||||||
setColumns(columnsCopy);
|
if (!over || active.id === over.id) return;
|
||||||
setHasUnsavedChanges(true);
|
|
||||||
|
const oldIndex = columns.findIndex((col) => col.key === active.id);
|
||||||
|
const newIndex = columns.findIndex((col) => col.key === over.id);
|
||||||
|
|
||||||
|
if (oldIndex !== -1 && newIndex !== -1) {
|
||||||
|
const newColumns = arrayMove(columns, oldIndex, newIndex);
|
||||||
|
if (!_.isEqual(newColumns, columns)) {
|
||||||
|
setColumns(newColumns);
|
||||||
|
setHasUnsavedChanges(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onDragCancel = () => {
|
||||||
|
setActiveId(null);
|
||||||
|
};
|
||||||
|
|
||||||
const removeColumn = (e) => {
|
const removeColumn = (e) => {
|
||||||
const { key } = e;
|
const { key } = e;
|
||||||
const newColumns = columns.filter((i) => i.key !== key);
|
const newColumns = columns.filter((i) => i.key !== key);
|
||||||
@@ -172,10 +285,14 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown className="prod-header-dropdown" menu={menu} trigger={["contextMenu"]}>
|
<div style={{ display: "flex", alignItems: "center", width: "100%" }}>
|
||||||
<span>{col.title}</span>
|
<HolderOutlined style={{ marginRight: "8px", color: "#999", cursor: "move" }} />
|
||||||
</Dropdown>
|
<Dropdown className="prod-header-dropdown" menu={menu} trigger={["contextMenu"]}>
|
||||||
|
<span style={{ flex: 1 }}>{col.title}</span>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -286,60 +403,99 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<ProductionListDetail jobs={dataSource} />
|
<ProductionListDetail jobs={dataSource} />
|
||||||
<ReactDragListView.DragColumn onDragEnd={onDragEnd} nodeSelector="th" handleSelector=".prod-header-dropdown">
|
<DndContext
|
||||||
<Table
|
sensors={sensors}
|
||||||
sticky
|
onDragStart={onDragStart}
|
||||||
pagination={false}
|
onDragEnd={onDragEnd}
|
||||||
size="small"
|
onDragCancel={onDragCancel}
|
||||||
{...(Production_List_Status_Colors.treatment === "on" && {
|
collisionDetection={closestCenter}
|
||||||
onRow: (record, index) => {
|
modifiers={[restrictToHorizontalAxis]}
|
||||||
if (!bodyshop.md_ro_statuses.production_colors) return null;
|
>
|
||||||
const color = bodyshop.md_ro_statuses.production_colors.find((x) => x.status === record.status);
|
<SortableContext items={columns.map((col) => col.key)} strategy={horizontalListSortingStrategy}>
|
||||||
if (!color) {
|
<Table
|
||||||
if (index % 2 === 0)
|
sticky
|
||||||
return {
|
pagination={false}
|
||||||
style: {
|
size="small"
|
||||||
backgroundColor: "var(--table-row-even-bg)"
|
{...(Production_List_Status_Colors.treatment === "on" && {
|
||||||
}
|
onRow: (record, index) => {
|
||||||
};
|
if (!bodyshop.md_ro_statuses.production_colors) return null;
|
||||||
return null;
|
const color = bodyshop.md_ro_statuses.production_colors.find((x) => x.status === record.status);
|
||||||
}
|
if (!color) {
|
||||||
return {
|
if (index % 2 === 0)
|
||||||
className: "rowWithColor",
|
return {
|
||||||
style: {
|
style: {
|
||||||
"--bgColor": color.color
|
backgroundColor: "var(--table-row-even-bg)"
|
||||||
? `rgba(${color.color.r},${color.color.g},${color.color.b},${color.color.a || 1})`
|
}
|
||||||
: "var(--status-row-bg-fallback)"
|
};
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
|
className: "rowWithColor",
|
||||||
|
style: {
|
||||||
|
"--bgColor": color.color
|
||||||
|
? `rgba(${color.color.r},${color.color.g},${color.color.b},${color.color.a || 1})`
|
||||||
|
: "var(--status-row-bg-fallback)"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
components={{
|
||||||
|
header: {
|
||||||
|
cell: DraggableHeaderCell
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
columns={columns.map((c, index) => {
|
||||||
|
return {
|
||||||
|
...c,
|
||||||
|
filteredValue: state.filteredInfo[c.key] || null,
|
||||||
|
sortOrder: state.sortedInfo.columnKey === c.key && state.sortedInfo.order,
|
||||||
|
title: headerItem(c),
|
||||||
|
ellipsis: true,
|
||||||
|
width: c.width ?? 100,
|
||||||
|
onHeaderCell: (column) => ({
|
||||||
|
columnKey: column.key,
|
||||||
|
width: column.width,
|
||||||
|
onResize: handleResize(index)
|
||||||
|
})
|
||||||
};
|
};
|
||||||
}
|
})}
|
||||||
})}
|
rowKey="id"
|
||||||
components={{
|
loading={loading}
|
||||||
header: {
|
dataSource={dataSource}
|
||||||
cell: ResizeableTitle
|
scroll={{ x: 1000 }}
|
||||||
}
|
onChange={handleTableChange}
|
||||||
}}
|
/>
|
||||||
columns={columns.map((c, index) => {
|
</SortableContext>
|
||||||
return {
|
<DragOverlay dropAnimation={null}>
|
||||||
...c,
|
{activeId ? (
|
||||||
filteredValue: state.filteredInfo[c.key] || null,
|
<div
|
||||||
sortOrder: state.sortedInfo.columnKey === c.key && state.sortedInfo.order,
|
style={{
|
||||||
title: headerItem(c),
|
backgroundColor: isDarkMode ? "#141414" : "white",
|
||||||
ellipsis: true,
|
color: isDarkMode ? "white" : "#000",
|
||||||
width: c.width ?? 100,
|
border: `2px solid ${isDarkMode ? "#177ddc" : "#1890ff"}`,
|
||||||
onHeaderCell: (column) => ({
|
borderRadius: "4px",
|
||||||
width: column.width,
|
padding: "12px 16px",
|
||||||
onResize: handleResize(index)
|
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.25)",
|
||||||
})
|
cursor: "grabbing",
|
||||||
};
|
display: "flex",
|
||||||
})}
|
alignItems: "center",
|
||||||
rowKey="id"
|
fontWeight: 500,
|
||||||
loading={loading}
|
minWidth: "120px"
|
||||||
dataSource={dataSource}
|
}}
|
||||||
scroll={{ x: 1000 }}
|
>
|
||||||
onChange={handleTableChange}
|
<HolderOutlined style={{ marginRight: "8px", color: isDarkMode ? "white" : "#000", fontSize: "16px" }} />
|
||||||
/>
|
<span>
|
||||||
</ReactDragListView.DragColumn>
|
{(() => {
|
||||||
|
const col = columns.find((c) => c.key === activeId);
|
||||||
|
const title = typeof col?.title === 'string' ? col.title :
|
||||||
|
(col?.dataIndex || col?.key || "Column");
|
||||||
|
return title;
|
||||||
|
})()}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</DragOverlay>
|
||||||
|
</DndContext>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
import { forwardRef } from "react";
|
||||||
import { Resizable } from "react-resizable";
|
import { Resizable } from "react-resizable";
|
||||||
|
|
||||||
export default function ResizableComponent(props) {
|
const ResizableComponent = forwardRef((props, ref) => {
|
||||||
const { onResize, width, ...restProps } = props;
|
const { onResize, width, dragAttributes, dragListeners, ...restProps } = props;
|
||||||
|
|
||||||
if (!width) {
|
if (!width) {
|
||||||
return <th {...restProps} />;
|
return <th ref={ref} {...restProps} {...(dragAttributes || {})} {...(dragListeners || {})} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -22,7 +23,11 @@ export default function ResizableComponent(props) {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<th {...restProps} />
|
<th ref={ref} {...restProps} {...(dragAttributes || {})} {...(dragListeners || {})} />
|
||||||
</Resizable>
|
</Resizable>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
ResizableComponent.displayName = "ResizableComponent";
|
||||||
|
|
||||||
|
export default ResizableComponent;
|
||||||
|
|||||||
Reference in New Issue
Block a user