diff --git a/packages/files-ui/package.json b/packages/files-ui/package.json
index 74413f7d1d..dbe13d718f 100644
--- a/packages/files-ui/package.json
+++ b/packages/files-ui/package.json
@@ -27,8 +27,8 @@
"mime-matcher": "^1.0.5",
"react": "^16.14.0",
"react-beforeunload": "^2.4.0",
- "react-dnd": "^11.1.3",
- "react-dnd-html5-backend": "^11.1.3",
+ "react-dnd": "14.0.2",
+ "react-dnd-html5-backend": "14.0.0",
"react-dom": "^16.14.0",
"react-h5-audio-player": "^3.5.0",
"react-hotkeys-hook": "^2.4.0",
diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/views/DragPreviewLayer.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/views/DragPreviewLayer.tsx
new file mode 100644
index 0000000000..95722994b4
--- /dev/null
+++ b/packages/files-ui/src/Components/Modules/FileBrowsers/views/DragPreviewLayer.tsx
@@ -0,0 +1,197 @@
+import { FolderFilledSvg, FileImageSvg, FilePdfSvg, FileTextSvg, Typography } from "@chainsafe/common-components"
+import { makeStyles } from "@chainsafe/common-theme"
+import clsx from "clsx"
+import React from "react"
+import { useDragLayer, XYCoord } from "react-dnd"
+import { FileSystemItem } from "../../../../Contexts/DriveContext"
+import { CSFTheme } from "../../../../Themes/types"
+import { DragTypes } from "../DragConstants"
+import { BrowserView } from "../types"
+
+const useStyles = makeStyles(({ breakpoints, constants, palette }: CSFTheme) => {
+ return ({
+ rowItem: {
+ display: "flex",
+ height: 70,
+ border: "2px solid transparent"
+ },
+ fileIcon: {
+ "& svg": {
+ width: constants.generalUnit * 2.5,
+ fill: constants.fileSystemItemRow.icon
+ },
+ [breakpoints.up("md")]: {
+ paddingLeft: constants.generalUnit * 8.5
+ },
+ paddingRight: constants.generalUnit * 6
+ },
+ folderIcon: {
+ "& svg": {
+ fill: palette.additional.gray[9]
+ }
+ },
+ filename: {
+ whiteSpace: "nowrap",
+ textOverflow: "ellipsis",
+ overflow: "hidden"
+ },
+ previewDragLayer: {
+ position: "fixed",
+ pointerEvents: "none",
+ zIndex: 100,
+ left: 0,
+ top: 0,
+ bottom: 0,
+ right: 0
+ },
+ dropdownIcon: {
+ "& svg": {
+ fill: constants.fileSystemItemRow.dropdownIcon
+ }
+ },
+ gridViewContainer: {
+ display: "flex",
+ flex: 1,
+ maxWidth: constants.generalUnit * 24
+ },
+ gridFolderName: {
+ textAlign: "center",
+ wordBreak: "break-all",
+ overflowWrap: "break-word",
+ padding: constants.generalUnit
+ },
+ gridViewIconNameBox: {
+ display: "flex",
+ flexDirection: "column",
+ width: "100%",
+ cursor: "pointer"
+ },
+ gridIcon: {
+ display: "flex",
+ justifyContent: "center",
+ alignItems: "center",
+ height: constants.generalUnit * 16,
+ maxWidth: constants.generalUnit * 24,
+ border: `1px solid ${palette.additional["gray"][6]}`,
+ boxShadow: constants.filesTable.gridItemShadow,
+ "& svg": {
+ width: "30%"
+ },
+ [breakpoints.down("lg")]: {
+ height: constants.generalUnit * 16
+ },
+ [breakpoints.down("sm")]: {
+ height: constants.generalUnit * 16
+ }
+ },
+ menuTitleGrid: {
+ padding: `0 ${constants.generalUnit * 0.5}px`,
+ [breakpoints.down("md")]: {
+ padding: 0
+ }
+ }
+ })})
+
+const DragPreviewRowItem: React.FC<{item: FileSystemItem; icon: React.ReactNode}> = ({
+ item: { name, isFolder },
+ icon
+}) => {
+ const classes = useStyles()
+ return (
+
+
+ {icon}
+
+
+ {name}
+
+
+ )
+}
+
+const DragPreviewGridItem: React.FC<{item: FileSystemItem; icon: React.ReactNode}> = ({
+ item: { name, isFolder },
+ icon
+}) => {
+ const classes = useStyles()
+ return (
+
+ )
+}
+
+export const DragPreviewLayer: React.FC<{items: FileSystemItem[]; previewType: BrowserView} > = ({ items, previewType }) => {
+ const classes = useStyles()
+ const { isDragging, dragItems, itemType, currentOffset } = useDragLayer(monitor => ({
+ itemType: monitor.getItemType(),
+ dragItems: monitor.getItem() as {ids: string[]},
+ isDragging: monitor.isDragging(),
+ initialOffset: monitor.getInitialSourceClientOffset(),
+ currentOffset: monitor.getSourceClientOffset()
+ }))
+
+ const getItemStyles = (currentOffset: XYCoord | null) => {
+ if (!currentOffset) {
+ return {
+ display: "none"
+ }
+ }
+ const { x, y } = currentOffset
+
+ const transform = `translate(${x}px, ${y}px)`
+ return {
+ transform,
+ WebkitTransform: transform
+ }
+ }
+
+ return (!isDragging || itemType !== DragTypes.MOVABLE_FILE)
+ ? null
+ :
+
+ {dragItems.ids.map(di => {
+ const previewItem = items.find(i => i.cid === di)
+
+ if (previewItem) {
+ let Icon
+ if (previewItem.isFolder) {
+ Icon = FolderFilledSvg
+ } else if (previewItem.content_type.includes("image")) {
+ Icon = FileImageSvg
+ } else if (previewItem.content_type.includes("pdf")) {
+ Icon = FilePdfSvg
+ } else {
+ Icon = FileTextSvg
+ }
+
+ return (previewType === "table")
+ ? }
+ key={previewItem.cid}
+ />
+ : }
+ key={previewItem.cid}
+ />
+ } else {
+ return null
+ }})}
+
+
+}
diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/views/FileSystemItem/FileSystemItem.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/views/FileSystemItem/FileSystemItem.tsx
index 07af776323..b40892d13b 100644
--- a/packages/files-ui/src/Components/Modules/FileBrowsers/views/FileSystemItem/FileSystemItem.tsx
+++ b/packages/files-ui/src/Components/Modules/FileBrowsers/views/FileSystemItem/FileSystemItem.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useRef } from "react"
+import React, { useCallback, useEffect, useRef } from "react"
import {
FormikTextInput,
Typography,
@@ -25,7 +25,7 @@ import CustomModal from "../../../../Elements/CustomModal"
import { Trans } from "@lingui/macro"
import { useDrag, useDrop } from "react-dnd"
import { DragTypes } from "../../DragConstants"
-import { NativeTypes } from "react-dnd-html5-backend"
+import { getEmptyImage, NativeTypes } from "react-dnd-html5-backend"
import { BrowserView, FileOperation } from "../../types"
import { CSFTheme } from "../../../../../Themes/types"
import FileItemTableItem from "./FileSystemTableItem"
@@ -131,7 +131,6 @@ const FileSystemItemRow = ({
setEditing,
renameSchema,
handleRename,
- handleMove,
deleteFile,
recoverFile,
viewFolder,
@@ -144,7 +143,7 @@ const FileSystemItemRow = ({
browserView,
resetSelectedFiles
}: IFileSystemItemRowProps) => {
- const { downloadFile, currentPath, handleUploadOnDrop, moduleRootPath } = useFileBrowser()
+ const { downloadFile, currentPath, handleUploadOnDrop, moduleRootPath, handleMove } = useFileBrowser()
const { cid, name, isFolder, content_type } = file
let Icon
if (isFolder) {
@@ -268,22 +267,41 @@ const FileSystemItemRow = ({
(itemOperation) => allMenuItems[itemOperation]
)
- const [, dragMoveRef, preview] = useDrag({
- item: { type: DragTypes.MOVABLE_FILE, payload: file }
+ const [, dragMoveRef, preview] = useDrag(() =>
+ ({ type: DragTypes.MOVABLE_FILE,
+ item: () => {
+ if (selected.includes(file.cid)) {
+ return { ids: selected }
+ } else {
+ return { ids: [...selected, file.cid] }
+ }
+ }
+ }), [selected])
+
+ useEffect(() => {
+ // This gets called after every render, by default
+
+ // Use empty image as a drag preview so browsers don't draw it
+ // and we can draw whatever we want on the custom drag layer instead.
+ preview(getEmptyImage(), {
+ // IE fallback: specify that we'd rather screenshot the node
+ // when it already knows it's being dragged so we can hide it with CSS.
+ captureDraggingState: true
+ })
})
const [{ isOverMove }, dropMoveRef] = useDrop({
accept: DragTypes.MOVABLE_FILE,
canDrop: () => isFolder,
- drop: async (item: {
- type: typeof DragTypes.MOVABLE_FILE
- payload: FileSystemItem
- }) => {
- handleMove &&
- (await handleMove(
- `${currentPath}${item.payload.name}`,
- `${currentPath}${name}/${item.payload.name}`
- ))
+ drop: (item: {ids: string[]}) => {
+ item.ids.forEach((cid) => {
+ const fileToMove = files.find(f => f.cid === cid)
+ handleMove && fileToMove &&
+ handleMove(
+ `${currentPath}${fileToMove.name}`,
+ `${currentPath}${name}/${fileToMove.name}`
+ )
+ })
},
collect: (monitor) => ({
isOverMove: monitor.isOver()
diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/views/FilesTable.view.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/views/FilesTable.view.tsx
index 6a2854be9b..3774edc756 100644
--- a/packages/files-ui/src/Components/Modules/FileBrowsers/views/FilesTable.view.tsx
+++ b/packages/files-ui/src/Components/Modules/FileBrowsers/views/FilesTable.view.tsx
@@ -48,6 +48,7 @@ import MimeMatcher from "../../../../Utils/MimeMatcher"
import { useLanguageContext } from "../../../../Contexts/LanguageContext"
import { getPathWithFile } from "../../../../Utils/pathUtils"
import SurveyBanner from "../../../SurveyBanner"
+import { DragPreviewLayer } from "./DragPreviewLayer"
import { useFileBrowser } from "../../../../Contexts/FileBrowserContext"
interface IStyleProps {
@@ -311,6 +312,8 @@ const FilesTableView = () => {
const [selectedCids, setSelectedCids] = useState([])
const [previewFileIndex, setPreviewFileIndex] = useState()
const { selectedLocale } = useLanguageContext()
+ const { redirect } = useHistory()
+
const items: FileSystemItem[] = useMemo(() => {
let temp = []
@@ -342,8 +345,6 @@ const FilesTableView = () => {
: temp.sort(sortFoldersFirst)
}, [sourceFiles, direction, column, selectedLocale])
- const { redirect } = useHistory()
-
const files = useMemo(() => items.filter((i) => !i.isFolder), [items])
const selectedFiles = useMemo(
@@ -412,13 +413,13 @@ const FilesTableView = () => {
[selectedCids]
)
- const toggleAll = () => {
+ const toggleAll = useCallback(() => {
if (selectedCids.length === items.length) {
setSelectedCids([])
} else {
setSelectedCids([...items.map((file: FileSystemItem) => file.cid)])
}
- }
+ }, [setSelectedCids, items, selectedCids])
const invalidFilenameRegex = new RegExp("/")
const renameSchema = object().shape({
@@ -466,6 +467,7 @@ const FilesTableView = () => {
// Bulk operations
const [validBulkOps, setValidBulkOps] = useState([])
+
useEffect(() => {
if (bulkOperations) {
let filteredList: FileOperation[] = [
@@ -575,14 +577,17 @@ const FilesTableView = () => {
setSelectedCids([])
}, [])
+ useEffect(() => {
+ setSelectedCids([])
+ }, [currentPath])
+
const onHideSurveyBanner = useCallback(() => {
setIsSurveyBannerVisible(false)
}, [setIsSurveyBannerVisible])
const handleViewFolder = useCallback((cid: string) => {
- resetSelectedCids()
viewFolder && viewFolder(cid)
- }, [viewFolder, resetSelectedCids])
+ }, [viewFolder])
return (
{
Drop to upload files
+
{crumbs && moduleRootPath ? (
{
- const manager = useRef(RNDContext)
- if (manager.current?.dragDropManager) {
- return (
-
- {children}
-
- )
- }
- return <>{children}>
-}
+const DragAndDrop: React.FC = ({ children }) => (
+
+ {children}
+
+)
export default DragAndDrop
diff --git a/packages/files-ui/src/Utils/pathUtils.ts b/packages/files-ui/src/Utils/pathUtils.ts
index 3554703e36..ef4174ac5a 100644
--- a/packages/files-ui/src/Utils/pathUtils.ts
+++ b/packages/files-ui/src/Utils/pathUtils.ts
@@ -45,7 +45,6 @@ export function getParentPathFromFilePath(filePath: string) {
else return parentPath
}
-
export function extractDrivePath(pathname: string) {
return pathname.split("/").slice(2).join("/").concat("/")
}
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 7cb9a92c00..49393b31e2 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4758,7 +4758,7 @@
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.7.tgz#613957d900fab9ff84c8dfb24fa3eef0c2a40896"
integrity sha512-2xtoL22/3Mv6a70i4+4RB7VgbDDORoWwjcqeNysojZA0R7NK17RbY5Gof/2QiFfJgX+KkWghbwJ+d/2SB8Ndzg==
-"@types/hoist-non-react-statics@*", "@types/hoist-non-react-statics@^3.3.1":
+"@types/hoist-non-react-statics@*":
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==
@@ -9510,14 +9510,14 @@ dir-glob@^3.0.1:
dependencies:
path-type "^4.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==
+dnd-core@14.0.0:
+ version "14.0.0"
+ resolved "https://registry.yarnpkg.com/dnd-core/-/dnd-core-14.0.0.tgz#973ab3470d0a9ac5a0fa9021c4feba93ad12347d"
+ integrity sha512-wTDYKyjSqWuYw3ZG0GJ7k+UIfzxTNoZLjDrut37PbcPGNfwhlKYlPUqjAKUjOOv80izshUiqusaKgJPItXSevA==
dependencies:
"@react-dnd/asap" "^4.0.0"
"@react-dnd/invariant" "^2.0.0"
- redux "^4.0.4"
+ redux "^4.0.5"
dns-equal@^1.0.0:
version "1.0.0"
@@ -17933,22 +17933,23 @@ react-dev-utils@^9.0.0:
strip-ansi "5.2.0"
text-table "0.2.0"
-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==
+react-dnd-html5-backend@14.0.0:
+ version "14.0.0"
+ resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-14.0.0.tgz#28d660a2ad1e07447c34a65cd25f7de8f1657194"
+ integrity sha512-2wAQqRFC1hbRGmk6+dKhOXsyQQOn3cN8PSZyOUeOun9J8t3tjZ7PS2+aFu7CVu2ujMDwTJR3VTwZh8pj2kCv7g==
dependencies:
- dnd-core "^11.1.3"
+ dnd-core "14.0.0"
-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==
+react-dnd@14.0.2:
+ version "14.0.2"
+ resolved "https://registry.yarnpkg.com/react-dnd/-/react-dnd-14.0.2.tgz#57266baec92b887301f81fa3b77f87168d159733"
+ integrity sha512-JoEL78sBCg8SzjOKMlkR70GWaPORudhWuTNqJ56lb2P8Vq0eM2+er3ZrMGiSDhOmzaRPuA9SNBz46nHCrjn11A==
dependencies:
+ "@react-dnd/invariant" "^2.0.0"
"@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"
+ dnd-core "14.0.0"
+ fast-deep-equal "^3.1.3"
+ hoist-non-react-statics "^3.3.2"
react-docgen@^5.0.0:
version "5.3.0"
@@ -18513,13 +18514,12 @@ redent@^3.0.0:
indent-string "^4.0.0"
strip-indent "^3.0.0"
-redux@^4.0.4:
- version "4.0.5"
- resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f"
- integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==
+redux@^4.0.5:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.0.tgz#eb049679f2f523c379f1aff345c8612f294c88d4"
+ integrity sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==
dependencies:
- loose-envify "^1.4.0"
- symbol-observable "^1.2.0"
+ "@babel/runtime" "^7.9.2"
refractor@^2.4.1:
version "2.10.1"
@@ -20292,7 +20292,7 @@ svgo@^1.0.0, svgo@^1.2.2:
unquote "~1.1.1"
util.promisify "~1.0.0"
-symbol-observable@^1.1.0, symbol-observable@^1.2.0:
+symbol-observable@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==