diff --git a/Client/package-lock.json b/Client/package-lock.json index 86e7f43d5..4c153bafe 100644 --- a/Client/package-lock.json +++ b/Client/package-lock.json @@ -25,8 +25,7 @@ "jwt-decode": "^4.0.0", "mui-color-input": "^5.0.1", "react": "^18.2.0", - "react-dnd": "^16.0.1", - "react-dnd-html5-backend": "^16.0.1", + "react-beautiful-dnd": "^13.1.1", "react-dom": "^18.2.0", "react-redux": "9.2.0", "react-router": "^6.23.0", @@ -1630,21 +1629,6 @@ "url": "https://opencollective.com/popperjs" } }, - "node_modules/@react-dnd/asap": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz", - "integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==" - }, - "node_modules/@react-dnd/invariant": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz", - "integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==" - }, - "node_modules/@react-dnd/shallowequal": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz", - "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==" - }, "node_modules/@react-spring/animated": { "version": "9.7.5", "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.5.tgz", @@ -2386,6 +2370,15 @@ "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "license": "MIT" }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz", + "integrity": "sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", @@ -2418,6 +2411,25 @@ "@types/react": "^18.0.0" } }, + "node_modules/@types/react-redux": { + "version": "7.1.34", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.34.tgz", + "integrity": "sha512-GdFaVjEbYv4Fthm2ZLvj1VSCedV7TqE5y1kNwnjSdBOTXuRSgowux6J8TAct15T3CKBr63UMk+2CO7ilRhyrAQ==", + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, + "node_modules/@types/react-redux/node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, "node_modules/@types/react-transition-group": { "version": "4.4.12", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", @@ -2959,6 +2971,14 @@ "node": ">= 8" } }, + "node_modules/css-box-model": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", + "integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==", + "dependencies": { + "tiny-invariant": "^1.0.6" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -3242,24 +3262,6 @@ "node": ">=0.4.0" } }, - "node_modules/dnd-core": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz", - "integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==", - "dependencies": { - "@react-dnd/asap": "^5.0.1", - "@react-dnd/invariant": "^4.0.1", - "redux": "^4.2.0" - } - }, - "node_modules/dnd-core/node_modules/redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "dependencies": { - "@babel/runtime": "^7.9.2" - } - }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -3830,6 +3832,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, "license": "MIT" }, "node_modules/fast-equals": { @@ -4974,6 +4977,11 @@ "node": ">= 0.4" } }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -5452,6 +5460,11 @@ ], "license": "MIT" }, + "node_modules/raf-schd": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", + "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==" + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -5464,41 +5477,60 @@ "node": ">=0.10.0" } }, - "node_modules/react-dnd": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz", - "integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==", + "node_modules/react-beautiful-dnd": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz", + "integrity": "sha512-0Lvs4tq2VcrEjEgDXHjT98r+63drkKEgqyxdA7qD3mvKwga6a5SscbdLPO2IExotU1jW8L0Ksdl0Cj2AF67nPQ==", + "deprecated": "react-beautiful-dnd is now deprecated. Context and options: https://github.com/atlassian/react-beautiful-dnd/issues/2672", "dependencies": { - "@react-dnd/invariant": "^4.0.1", - "@react-dnd/shallowequal": "^4.0.1", - "dnd-core": "^16.0.1", - "fast-deep-equal": "^3.1.3", - "hoist-non-react-statics": "^3.3.2" + "@babel/runtime": "^7.9.2", + "css-box-model": "^1.2.0", + "memoize-one": "^5.1.1", + "raf-schd": "^4.0.2", + "react-redux": "^7.2.0", + "redux": "^4.0.4", + "use-memo-one": "^1.1.1" }, "peerDependencies": { - "@types/hoist-non-react-statics": ">= 3.3.1", - "@types/node": ">= 12", - "@types/react": ">= 16", - "react": ">= 16.14" + "react": "^16.8.5 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.5 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-beautiful-dnd/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "node_modules/react-beautiful-dnd/node_modules/react-redux": { + "version": "7.2.9", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", + "integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==", + "dependencies": { + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "react": "^16.8.3 || ^17 || ^18" }, "peerDependenciesMeta": { - "@types/hoist-non-react-statics": { + "react-dom": { "optional": true }, - "@types/node": { - "optional": true - }, - "@types/react": { + "react-native": { "optional": true } } }, - "node_modules/react-dnd-html5-backend": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz", - "integrity": "sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==", + "node_modules/react-beautiful-dnd/node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", "dependencies": { - "dnd-core": "^16.0.1" + "@babel/runtime": "^7.9.2" } }, "node_modules/react-dom": { @@ -6420,6 +6452,14 @@ "punycode": "^2.1.0" } }, + "node_modules/use-memo-one": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz", + "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/use-sync-external-store": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", diff --git a/Client/package.json b/Client/package.json index 8417ad1fa..7f3d9cfe7 100644 --- a/Client/package.json +++ b/Client/package.json @@ -28,8 +28,7 @@ "jwt-decode": "^4.0.0", "mui-color-input": "^5.0.1", "react": "^18.2.0", - "react-dnd": "^16.0.1", - "react-dnd-html5-backend": "^16.0.1", + "react-beautiful-dnd": "^13.1.1", "react-dom": "^18.2.0", "react-redux": "9.2.0", "react-router": "^6.23.0", diff --git a/Client/src/Components/Inputs/TextInput/Adornments/index.jsx b/Client/src/Components/Inputs/TextInput/Adornments/index.jsx index 3c69d35a2..d69a5edb6 100644 --- a/Client/src/Components/Inputs/TextInput/Adornments/index.jsx +++ b/Client/src/Components/Inputs/TextInput/Adornments/index.jsx @@ -67,10 +67,12 @@ PasswordEndAdornment.propTypes = { setFieldType: PropTypes.func, }; -export const ServerStartAdornment = () => { +export const ServerStartAdornment = (props) => { return ( - + + + ); }; diff --git a/Client/src/Components/TabPanels/Status/Card/ItemTypes.js b/Client/src/Components/TabPanels/Status/Card/ItemTypes.js deleted file mode 100644 index a7cde4907..000000000 --- a/Client/src/Components/TabPanels/Status/Card/ItemTypes.js +++ /dev/null @@ -1,4 +0,0 @@ -export default { - CARD: 'card', - } - \ No newline at end of file diff --git a/Client/src/Components/TabPanels/Status/Card/Server/index.jsx b/Client/src/Components/TabPanels/Status/Card/Server/index.jsx deleted file mode 100644 index e4a701d60..000000000 --- a/Client/src/Components/TabPanels/Status/Card/Server/index.jsx +++ /dev/null @@ -1,50 +0,0 @@ -import { - ServerEndAdornment, -} from "../../../../Inputs/TextInput/Adornments"; -import Search from "../../../../Inputs/Search"; -import { useState } from "react"; -import ReorderRoundedIcon from "@mui/icons-material/ReorderRounded"; -import { Stack, IconButton } from "@mui/material"; -import React from "react"; -/** - * - * @param {*} id The Id of the Server component - * @param {*} removeItem The function used to remove a single server - * @param {*} onChange The Change handler function to handle when the server value is changed - * used to update the server(monitor) lists - * @param {*} monitors The server monitors options - * @param {*} value the option label of the server/monitor, namely the monitor name field - * @returns - */ -const Server = (props) => { - const [search, setSearch] = useState(""); - const handleSearch = (val) => { - setSearch(val); - }; - return ( - - - - - - } - handleInputChange={handleSearch} - handleChange={props.onChange} - /> - - ); -}; - -export default Server; diff --git a/Client/src/Components/TabPanels/Status/Card/index.jsx b/Client/src/Components/TabPanels/Status/Card/index.jsx deleted file mode 100644 index 2d2c49fd1..000000000 --- a/Client/src/Components/TabPanels/Status/Card/index.jsx +++ /dev/null @@ -1,109 +0,0 @@ -import React, { useRef } from "react"; -import { useDrag, useDrop } from "react-dnd"; -import ItemTypes from "./ItemTypes"; -import Card from "@mui/material/Card"; -import Server from "./Server" -import { CardContent } from "@mui/material"; - -/** - * CustomCard is a React Forward Ref component that - * passes properties to its wrapped component with - * ref that carrys the drag and drop feature etc - */ -const CustomCard = React.forwardRef((props, ref) => ( - - - - - -)); - -/** - * @param {*} id The Id of the Server component - * @param {*} index The index of the Card in its natural order of placement - * @param {*} moveCard The function to actually move a card - * @param {*} removeCard The function to remote the card - * @param {*} onChange The Change handler function to handle when the server value is changed - * used to update the server(monitor) lists - * @param {*} monitors The server monitors options - * @param {*} value the option label of the server/monitor, namely the monitor name field - * @returns The Card component representing a singler server/monitor that is capable of being - * dragged and droped - */ - -const MyCard = ({ id, index, moveCard, removeCard, value, onChange, monitors }) => { - const ref = useRef(null); - const [, drop] = useDrop({ - accept: ItemTypes.CARD, - hover(item, monitor) { - if (!ref.current) { - return; - } - const dragIndex = item.index; - const hoverIndex = index; - - // Don't replace items with themselves - if (dragIndex === hoverIndex) { - return; - } - - // Determine rectangle on screen - const hoverBoundingRect = ref.current.getBoundingClientRect(); - // Get vertical middle - const hoverMiddleY = - (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; - // Determine mouse position - const clientOffset = monitor.getClientOffset(); - // Get pixels to the top - const hoverClientY = clientOffset.y - hoverBoundingRect.top; - // Only perform the move when the mouse has crossed half of the items height - // When dragging downwards, only move when the cursor is below 50% - // When dragging upwards, only move when the cursor is above 50% - // Dragging downwards - - if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { - return; - } - // Dragging upwards - if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { - return; - } - - // Time to actually perform the action - moveCard(dragIndex, hoverIndex); - // Note: we're mutating the monitor item here! - // Generally it's better to avoid mutations, - // but it's good here for the sake of performance - // to avoid expensive index searches. - item.index = hoverIndex; - } - }); - const [ _, drag] = useDrag({ - type: ItemTypes.CARD, - item: {id: id, index:index}, - collect: monitor => ({ - isDragging: monitor.isDragging() - }) - }); - drag(drop(ref)); - return ( - - ); -}; - -export default MyCard; - - diff --git a/Client/src/Components/TabPanels/Status/ContentPanel.jsx b/Client/src/Components/TabPanels/Status/ContentPanel.jsx index e08cd03cf..2b78039bf 100644 --- a/Client/src/Components/TabPanels/Status/ContentPanel.jsx +++ b/Client/src/Components/TabPanels/Status/ContentPanel.jsx @@ -1,15 +1,15 @@ -import { useState, useCallback, useContext, useEffect } from "react"; +import { useState, useContext, useEffect } from "react"; import { Button, Box, Stack, Typography } from "@mui/material"; import ConfigBox from "../../../Components/ConfigBox"; import { useTheme } from "@emotion/react"; import TabPanel from "@mui/lab/TabPanel"; -import Card from "./Card"; -import update from "immutability-helper"; import { StatusFormContext } from "../../../Pages/Status/CreateStatusContext"; import { useSelector } from "react-redux"; import { logger } from "../../../Utils/Logger" import { createToast } from "../../../Utils/toastUtils"; import { networkService } from "../../../main"; +import ServersList from "./ServersList"; + /** * Content Panel is used to compose the second part of the status page @@ -24,6 +24,7 @@ const ContentPanel = () => { const {user, authToken } = useSelector((state) => state.auth); const [monitors, setMonitors] = useState([]); + useEffect(() => { const fetchMonitors = async () => { try { @@ -54,44 +55,6 @@ const ContentPanel = () => { }; fetchMonitors(); }, [user, authToken]); - - const moveCard = useCallback( - (dragIndex, hoverIndex) => { - const dragCard = cards[dragIndex]; - setCards( - update(cards, { - $splice: [ - [dragIndex, 1], - [hoverIndex, 0, dragCard], - ], - }) - ); - }, - [cards] - ); - - const handleCardChange = (event, val) => { - event.preventDefault(); - const { id } = event.target; - let idx = cards.findIndex((a) => { - let found = false; - let optionIdx = id.indexOf("-option"); - if (optionIdx !== -1) found = a.id == id.substr(0, optionIdx); - else found = a.id == id; - return found; - }); - let newCards; - if (idx >= 0) { - let x = JSON.parse(JSON.stringify(cards[idx])); - x.val = val; - newCards = update(cards, { $splice: [[idx, 1, x]] }); - setCards(newCards); - } else { - newCards = update(cards, { $push: [{ id: id, val: val }] }); - setCards(newCards); - } - setForm({ ...form, monitors: newCards.map(c=>c.val) }); - }; const handleAddNew = () => { if (cards.length === monitors.length) return; const newCards = [...cards, { id: "" + Math.random(),val:{} }]; @@ -172,21 +135,14 @@ const ContentPanel = () => { direction="column" gap={theme.spacing(2)} > - {cards.map((card, idx) => { - return ( - - ); - })} + )} {errors["monitors"] && ( diff --git a/Client/src/Components/TabPanels/Status/ServersList/Server/index.jsx b/Client/src/Components/TabPanels/Status/ServersList/Server/index.jsx new file mode 100644 index 000000000..8e6c0361f --- /dev/null +++ b/Client/src/Components/TabPanels/Status/ServersList/Server/index.jsx @@ -0,0 +1,58 @@ +import { ServerStartAdornment, ServerEndAdornment } from "../../../../Inputs/TextInput/Adornments"; +import Search from "../../../../Inputs/Search"; +import {useState} from "react" +import React from "react"; +import { Stack } from "@mui/material"; + +/** + * + * @param {*} id The Id of the Server component + * @param {*} monitors The server monitors options + * @param {*} value the option label of the server/monitor, namely the monitor name field + * @param {*} removeItem The function used to remove a single server + * @param {*} onChange The Change handler function to handle when the server value is changed + * used to update the server(monitor) lists* + * @param {*} dragHandleProps the dragHandleProps passed on to the designated dom node + * so that there will be a draging indicator when mouse over it + * @returns A single server whose value is one of the existing monitors + */ + +const Server = ({ id, value, monitors, onChange, removeItem, dragHandleProps }) => { + const [search, setSearch] = useState(""); + const handleSearch = (val) => { + setSearch(val); + }; + return ( + + } + endAdornment={ + + } + handleInputChange={handleSearch} + handleChange={onChange} + /> + + ); +}; + +Server.propTypes = { + id: PropTypes.string.isRequired, + monitors: PropTypes.array.isRequired, + value: PropTypes.string.isRequired, + removeItem: PropTypes.function.isRequired, + onChange: PropTypes.function.isRequired, + dragHandleProps: PropTypes.object.isRequired, +}; + +export default Server; \ No newline at end of file diff --git a/Client/src/Components/TabPanels/Status/ServersList/index.jsx b/Client/src/Components/TabPanels/Status/ServersList/index.jsx new file mode 100644 index 000000000..18f021592 --- /dev/null +++ b/Client/src/Components/TabPanels/Status/ServersList/index.jsx @@ -0,0 +1,136 @@ +import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd"; +import Server from "./Server"; +import update from "immutability-helper"; + +/** + * + * @param {*} monitors The server monitors options + * @param {*} cards A set of servers/monitors user can add/remove/drag/drop to be displayed in status page + * each card can be autocompleted/selected from the existing monitors list + * @param {*} setCards Function to set the cards + * @param {*} form The Status page form + * @param {*} setForm Function to set the form + * @param {*} removeItem The function used to remove a single server + * @returns A list of user selected Servers/Monitors + */ + + +const ServersList = ({ monitors, cards, setCards, form, setForm, removeItem }) => { + const grid = 8; + + const handleCardChange = (event, val) => { + let newCards; + const { id } = event.target; + let idx = cards.findIndex((a) => { + let found = false; + let optionIdx = id.indexOf("-option"); + if (optionIdx !== -1) found = a.id == id.substr(0, optionIdx); + else found = a.id == id; + return found; + }); + + if (idx >= 0) { + let x = JSON.parse(JSON.stringify(cards[idx])); + x.val = val; + newCards = update(cards, { $splice: [[idx, 1, x]] }); + } else { + newCards = update(cards, { $push: [{ id: id, val: val }] }); + } + setCards(newCards); + setForm({ ...form, monitors: newCards.map((c) => c.val) }); + }; + + const moveCard = (dragIndex, hoverIndex) => { + const dragCard = cards[dragIndex]; + const newCards = update(cards, { + $splice: [ + [dragIndex, 1], + [hoverIndex, 0, dragCard], + ], + }); + setCards(newCards); + setForm({ ...form, monitors: newCards.map((c) => c.val) }); + }; + + const handleDragEnd = (result) => { + // dropped outside the list + if (!result.destination) { + return; + } + moveCard(result.source.index, result.destination.index); + }; + + const getItemStyle = (isDragging, draggableStyle) => ({ + // some basic styles to make the items look a bit nicer + userSelect: "none", + padding: grid * 2, + margin: `0 0 ${grid}px 0`, + + // change background colour if dragging + background: isDragging ? "lightgreen" : "lightgrey", + + // styles we need to apply on draggables + ...draggableStyle, + }); + + const getListStyle = (isDraggingOver) => ({ + background: isDraggingOver ? "lightblue" : "white", + padding: grid, + width: 550, + }); + + return ( + + + {(provided, snapshot) => ( +
+ {cards.map((item, index) => ( + + {(provided, snapshot) => ( +
+ +
+ )} +
+ ))} + {provided.placeholder} +
+ )} +
+
+ ); +}; + +ServersList.propTypes = { + monitors: PropTypes.array.isRequired, + cards: PropTypes.array.isRequired, + setCards: PropTypes.function.isRequired, + form: PropTypes.object.isRequired, + setForm: PropTypes.function.isRequired, + removeItem: PropTypes.function.isRequired +}; + +export default ServersList; diff --git a/Client/src/main.jsx b/Client/src/main.jsx index d6226c393..7ee52132e 100644 --- a/Client/src/main.jsx +++ b/Client/src/main.jsx @@ -6,8 +6,6 @@ import { Provider } from "react-redux"; import { persistor, store } from "./store"; import { PersistGate } from "redux-persist/integration/react"; import NetworkServiceProvider from "./Utils/NetworkServiceProvider.jsx"; -import { DndProvider } from 'react-dnd' -import { HTML5Backend } from 'react-dnd-html5-backend' import { networkService } from "./Utils/NetworkService"; export { networkService }; @@ -19,9 +17,7 @@ ReactDOM.createRoot(document.getElementById("root")).render( > - -