diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx
index a1453ae99c..6b1882fd7e 100644
--- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx
+++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx
@@ -1,13 +1,43 @@
import React, { useEffect, useState, useRef } from 'react' // eslint-disable-line
import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line
-import Draggable from 'react-draggable' // eslint-disable-line
+import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd' // eslint-disable-line
+import * as async from 'async'
+import * as Gists from 'gists'
import * as helper from '../../../../../apps/remix-ide/src/lib/helper'
+import QueryParams from '../../../../../apps/remix-ide/src/lib/query-params'
import { FileExplorerProps, File } from './types'
import './css/file-explorer.css'
+const queryParams = new QueryParams()
+
+function packageFiles (filesProvider, directory, callback) {
+ const ret = {}
+ filesProvider.resolveDirectory(directory, (error, files) => {
+ if (error) callback(error)
+ else {
+ async.eachSeries(Object.keys(files), (path, cb) => {
+ if (filesProvider.isDirectory(path)) {
+ cb()
+ } else {
+ filesProvider.get(path, (error, content) => {
+ if (error) return cb(error)
+ if (/^\s+$/.test(content) || !content.length) {
+ content = '// this line is added to create a gist. Empty file is not allowed.'
+ }
+ ret[path] = { content }
+ cb()
+ })
+ }
+ }, (error) => {
+ callback(error, ret)
+ })
+ }
+ })
+}
+
export const FileExplorer = (props: FileExplorerProps) => {
- const { files, name, registry } = props
+ const { files, name, registry, plugin } = props
const uploadFile = (target) => {
// TODO The file explorer is merely a view on the current state of
// the files module. Please ask the user here if they want to overwrite
@@ -47,34 +77,6 @@ export const FileExplorer = (props: FileExplorerProps) => {
})
})
}
- const publishToGist = () => {
- // modalDialogCustom.confirm(
- // 'Create a public gist',
- // 'Are you sure you want to publish all your files in browser directory anonymously as a public gist on github.com? Note: this will not include directories.',
- // () => { this.toGist() }
- // )
- }
- const createNewFile = (parentFolder = 'browser') => {
- // const self = this
- // modalDialogCustom.prompt('Create new file', 'File Name (e.g Untitled.sol)', 'Untitled.sol', (input) => {
- // if (!input) input = 'New file'
- // helper.createNonClashingName(parentFolder + '/' + input, self.files, async (error, newName) => {
- // if (error) return tooltip('Failed to create file ' + newName + ' ' + error)
- // const fileManager = self._deps.fileManager
- // const createFile = await fileManager.writeFile(newName, '')
-
- // if (!createFile) {
- // tooltip('Failed to create file ' + newName)
- // } else {
- // await fileManager.open(newName)
- // if (newName.includes('_test.sol')) {
- // self.events.trigger('newTestFileCreated', [newName])
- // }
- // }
- // })
- // }, null, true)
- }
-
const containerRef = useRef(null)
const [state, setState] = useState({
focusElement: [],
@@ -102,23 +104,28 @@ export const FileExplorer = (props: FileExplorerProps) => {
}
].filter(item => props.menuItems && props.menuItems.find((name) => { return name === item.action })),
files: [],
- actions: {
- updateGist: () => {},
- uploadFile,
- publishToGist,
- createNewFile
- },
+ actions: {},
fileManager: null,
- ctrlKey: false
+ tokenAccess: null,
+ ctrlKey: false,
+ newFileName: ''
})
useEffect(() => {
(async () => {
+ console.log('registry: ', registry)
const fileManager = registry.get('filemanager').api
+ const config = registry.get('config').api
+ const tokenAccess = config.get('settings/gist-access-token').api
const files = await fetchDirectoryContent(name)
+ const actions = {
+ updateGist: () => {},
+ uploadFile,
+ publishToGist
+ }
setState(prevState => {
- return { ...prevState, fileManager, files }
+ return { ...prevState, fileManager, tokenAccess, files, actions }
})
})()
}, [])
@@ -150,22 +157,6 @@ export const FileExplorer = (props: FileExplorerProps) => {
})
}
- const label = (data) => {
- return (
-
-
- { data.path.split('/').pop() }
-
-
- )
- }
-
const normalize = (path, filesList): File[] => {
const folders = []
const files = []
@@ -198,100 +189,147 @@ export const FileExplorer = (props: FileExplorerProps) => {
return keyPath[keyPath.length - 1]
}
- const toGist = (id) => {
- // const proccedResult = function (error, data) {
- // if (error) {
- // modalDialogCustom.alert('Failed to manage gist: ' + error)
- // console.log('Failed to manage gist: ' + error)
- // } else {
- // if (data.html_url) {
- // modalDialogCustom.confirm('Gist is ready', `The gist is at ${data.html_url}. Would you like to open it in a new window?`, () => {
- // window.open(data.html_url, '_blank')
- // })
- // } else {
- // modalDialogCustom.alert(data.message + ' ' + data.documentation_url + ' ' + JSON.stringify(data.errors, null, '\t'))
- // }
- // }
- // }
+ const createNewFile = (parentFolder = 'browser') => {
+ // const self = this
+ // modalDialogCustom.prompt('Create new file', 'File Name (e.g Untitled.sol)', 'Untitled.sol', (input) => {
+ // if (!input) input = 'New file'
+ // get filename from state (state.newFileName)
+ const fileManager = state.fileManager
+ const newFileName = parentFolder + '/' + 'unnamed' + Math.floor(Math.random() * 101)
+
+ helper.createNonClashingName(newFileName, files, async (error, newName) => {
+ // if (error) return tooltip('Failed to create file ' + newName + ' ' + error)
+ if (error) return
+ const createFile = await fileManager.writeFile(newName, '')
+
+ if (!createFile) {
+ // tooltip('Failed to create file ' + newName)
+ } else {
+ if (parentFolder === name) {
+ // const updatedFiles = await resolveDirectory(parentFolder, state.files)
- // /**
- // * This function is to get the original content of given gist
- // * @params id is the gist id to fetch
- // */
- // async function getOriginalFiles (id) {
- // if (!id) {
- // return []
- // }
-
- // const url = `https://api.github.com/gists/${id}`
- // const res = await fetch(url)
- // const data = await res.json()
- // return data.files || []
- // }
-
- // // If 'id' is not defined, it is not a gist update but a creation so we have to take the files from the browser explorer.
- // const folder = id ? 'browser/gists/' + id : 'browser/'
- // this.packageFiles(this.files, folder, (error, packaged) => {
- // if (error) {
- // console.log(error)
- // modalDialogCustom.alert('Failed to create gist: ' + error.message)
- // } else {
- // // check for token
- // var tokenAccess = this._deps.config.get('settings/gist-access-token')
- // if (!tokenAccess) {
- // modalDialogCustom.alert(
- // 'Remix requires an access token (which includes gists creation permission). Please go to the settings tab to create one.'
- // )
- // } else {
- // const description = 'Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. \n Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=' +
- // queryParams.get().version + '&optimize=' + queryParams.get().optimize + '&runs=' + queryParams.get().runs + '&gist='
- // const gists = new Gists({ token: tokenAccess })
-
- // if (id) {
- // const originalFileList = getOriginalFiles(id)
- // // Telling the GIST API to remove files
- // const updatedFileList = Object.keys(packaged)
- // const allItems = Object.keys(originalFileList)
- // .filter(fileName => updatedFileList.indexOf(fileName) === -1)
- // .reduce((acc, deleteFileName) => ({
- // ...acc,
- // [deleteFileName]: null
- // }), originalFileList)
- // // adding new files
- // updatedFileList.forEach((file) => {
- // const _items = file.split('/')
- // const _fileName = _items[_items.length - 1]
- // allItems[_fileName] = packaged[file]
- // })
-
- // tooltip('Saving gist (' + id + ') ...')
- // gists.edit({
- // description: description,
- // public: true,
- // files: allItems,
- // id: id
- // }, (error, result) => {
- // proccedResult(error, result)
- // if (!error) {
- // for (const key in allItems) {
- // if (allItems[key] === null) delete allItems[key]
- // }
- // }
- // })
- // } else {
- // // id is not existing, need to create a new gist
- // tooltip('Creating a new gist ...')
- // gists.create({
- // description: description,
- // public: true,
- // files: packaged
- // }, (error, result) => {
- // proccedResult(error, result)
- // })
- // }
- // }
- // }
- // })
+ setState(prevState => {
+ return {
+ ...prevState,
+ files: [...prevState.files, {
+ path: newFileName,
+ name: extractNameFromKey(newFileName),
+ isDirectory: false
+ }]
+ }
+ })
+ }
+ await fileManager.open(newName)
+ if (newName.includes('_test.sol')) {
+ plugin.events.trigger('newTestFileCreated', [newName])
+ }
+ }
+ })
+ // }, null, true)
+ }
+
+ const publishToGist = () => {
+ // modalDialogCustom.confirm(
+ // 'Create a public gist',
+ // 'Are you sure you want to publish all your files in browser directory anonymously as a public gist on github.com? Note: this will not include directories.',
+ // () => { this.toGist() }
+ toGist()
+ // )
+ }
+
+ const toGist = (id?: string) => {
+ const proccedResult = function (error, data) {
+ if (error) {
+ // modalDialogCustom.alert('Failed to manage gist: ' + error)
+ console.log('Failed to manage gist: ' + error)
+ } else {
+ if (data.html_url) {
+ // modalDialogCustom.confirm('Gist is ready', `The gist is at ${data.html_url}. Would you like to open it in a new window?`, () => {
+ // window.open(data.html_url, '_blank')
+ // })
+ } else {
+ // modalDialogCustom.alert(data.message + ' ' + data.documentation_url + ' ' + JSON.stringify(data.errors, null, '\t'))
+ }
+ }
+ }
+
+ /**
+ * This function is to get the original content of given gist
+ * @params id is the gist id to fetch
+ */
+ async function getOriginalFiles (id) {
+ if (!id) {
+ return []
+ }
+
+ const url = `https://api.github.com/gists/${id}`
+ const res = await fetch(url)
+ const data = await res.json()
+ return data.files || []
+ }
+
+ // If 'id' is not defined, it is not a gist update but a creation so we have to take the files from the browser explorer.
+ const folder = id ? 'browser/gists/' + id : 'browser/'
+ packageFiles(files, folder, (error, packaged) => {
+ if (error) {
+ console.log(error)
+ // modalDialogCustom.alert('Failed to create gist: ' + error.message)
+ } else {
+ // check for token
+ if (!state.tokenAccess) {
+ // modalDialogCustom.alert(
+ // 'Remix requires an access token (which includes gists creation permission). Please go to the settings tab to create one.'
+ // )
+ } else {
+ const description = 'Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. \n Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=' +
+ queryParams.get().version + '&optimize=' + queryParams.get().optimize + '&runs=' + queryParams.get().runs + '&gist='
+ const gists = new Gists({ token: state.tokenAccess })
+
+ if (id) {
+ const originalFileList = getOriginalFiles(id)
+ // Telling the GIST API to remove files
+ const updatedFileList = Object.keys(packaged)
+ const allItems = Object.keys(originalFileList)
+ .filter(fileName => updatedFileList.indexOf(fileName) === -1)
+ .reduce((acc, deleteFileName) => ({
+ ...acc,
+ [deleteFileName]: null
+ }), originalFileList)
+ // adding new files
+ updatedFileList.forEach((file) => {
+ const _items = file.split('/')
+ const _fileName = _items[_items.length - 1]
+ allItems[_fileName] = packaged[file]
+ })
+
+ // tooltip('Saving gist (' + id + ') ...')
+ gists.edit({
+ description: description,
+ public: true,
+ files: allItems,
+ id: id
+ }, (error, result) => {
+ proccedResult(error, result)
+ if (!error) {
+ for (const key in allItems) {
+ if (allItems[key] === null) delete allItems[key]
+ }
+ }
+ })
+ } else {
+ // id is not existing, need to create a new gist
+ // tooltip('Creating a new gist ...')
+ gists.create({
+ description: description,
+ public: true,
+ files: packaged
+ }, (error, result) => {
+ proccedResult(error, result)
+ })
+ }
+ }
+ }
+ })
}
// self._components = {}
@@ -359,6 +397,26 @@ export const FileExplorer = (props: FileExplorerProps) => {
// }
// }
+ const label = (data) => {
+ return (
+
+
+ { data.path.split('/').pop() }
+
+
+ )
+ }
+
+ const onDragEnd = result => {
+
+ }
+
const handleClickFile = (path) => {
state.fileManager.open(path)
setState(prevState => {
@@ -414,7 +472,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
data-id={'fileExplorerNewFile' + action}
onClick={(e) => {
e.stopPropagation()
- state.actions[action]()
+ action === 'createNewFile' ? createNewFile() : state.actions[action]()
}}
className={'newFile ' + icon + ' remixui_newFile'}
title={title}
@@ -436,45 +494,55 @@ export const FileExplorer = (props: FileExplorerProps) => {
const renderFiles = (file, index) => {
if (file.isDirectory) {
return (
-
- {
- e.stopPropagation()
- handleClickFolder(file.path)
- }}
- labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' }
- controlBehaviour={ state.ctrlKey }
- >
- {
- file.child ? {
- file.child.map((file, index) => {
- return renderFiles(file, index)
- })
+
+ {(provided) => (
+ {
+ e.stopPropagation()
+ handleClickFolder(file.path)
+ }}
+ labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' }
+ controlBehaviour={ state.ctrlKey }
+ >
+ {
+ file.child ? {
+ file.child.map((file, index) => {
+ return renderFiles(file, index)
+ })
+ }
+ :
}
- :
- }
-
-
+ { provided.placeholder }
+
+ )}
+
)
} else {
return (
-
- {
- e.stopPropagation()
- handleClickFile(file.path)
- }}
- icon='fa fa-file'
- labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' }
- />
+
+ {(provided) => (
+ {
+ e.stopPropagation()
+ handleClickFile(file.path)
+ }}
+ icon='fa fa-file'
+ labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' }
+ />
+ )}
)
}
@@ -486,14 +554,12 @@ export const FileExplorer = (props: FileExplorerProps) => {
tabIndex={-1}
onKeyDown={(e) => {
if (e.shiftKey) {
- console.log('TRUE')
setState(prevState => {
return { ...prevState, ctrlKey: true }
})
}
}}
onKeyUp={() => {
- console.log('FALSE')
setState(prevState => {
return { ...prevState, ctrlKey: false }
})
@@ -501,17 +567,24 @@ export const FileExplorer = (props: FileExplorerProps) => {
>
- false}>
-
-
-
-
+
+
+ {(provided) => (
+
+
+ { provided.placeholder }
+
+ )}
+
+
diff --git a/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx b/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx
index b3aa60cd9f..c570de5f07 100644
--- a/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx
+++ b/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx
@@ -4,7 +4,7 @@ import { TreeViewItemProps } from '../../types'
import './tree-view-item.css'
export const TreeViewItem = (props: TreeViewItemProps) => {
- const { id, children, label, labelClass, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon, controlBehaviour = false, ...otherProps } = props
+ const { id, children, label, labelClass, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon, controlBehaviour = false, innerRef, ...otherProps } = props
const [isExpanded, setIsExpanded] = useState(false)
useEffect(() => {
@@ -12,7 +12,7 @@ export const TreeViewItem = (props: TreeViewItemProps) => {
}, [expand])
return (
-
+
!controlBehaviour && setIsExpanded(!isExpanded)}>
{ children ?
: icon ?
: null }
diff --git a/libs/remix-ui/tree-view/src/types/index.ts b/libs/remix-ui/tree-view/src/types/index.ts
index e3d54e71b3..cf8f850b52 100644
--- a/libs/remix-ui/tree-view/src/types/index.ts
+++ b/libs/remix-ui/tree-view/src/types/index.ts
@@ -15,4 +15,5 @@ export interface TreeViewItemProps {
icon?: string,
labelClass?: string,
controlBehaviour?: boolean
+ innerRef?: any
}
diff --git a/package-lock.json b/package-lock.json
index bb2393535c..e2dbf90fc6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7597,6 +7597,15 @@
"csstype": "^2.2.0"
}
},
+ "@types/react-beautiful-dnd": {
+ "version": "13.0.0",
+ "resolved": "https://registry.npmjs.org/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.0.0.tgz",
+ "integrity": "sha512-by80tJ8aTTDXT256Gl+RfLRtFjYbUWOnZuEigJgNsJrSEGxvFe5eY6k3g4VIvf0M/6+xoLgfYWoWonlOo6Wqdg==",
+ "dev": true,
+ "requires": {
+ "@types/react": "*"
+ }
+ },
"@types/react-dom": {
"version": "16.9.4",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.4.tgz",
@@ -13509,6 +13518,14 @@
"insert-css": "^0.2.0"
}
},
+ "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==",
+ "requires": {
+ "tiny-invariant": "^1.0.6"
+ }
+ },
"css-color-names": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
@@ -20226,6 +20243,14 @@
"minimalistic-crypto-utils": "^1.0.1"
}
},
+ "hoist-non-react-statics": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+ "requires": {
+ "react-is": "^16.7.0"
+ }
+ },
"homedir-polyfill": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
@@ -25592,6 +25617,11 @@
}
}
},
+ "memoize-one": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz",
+ "integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA=="
+ },
"memory-fs": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
@@ -35427,6 +35457,11 @@
"integrity": "sha1-W4h48ROlgheEjGSCAmxz4bpXcn8=",
"dev": true
},
+ "raf-schd": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.2.tgz",
+ "integrity": "sha512-VhlMZmGy6A6hrkJWHLNTGl5gtgMUm+xfGza6wbwnE914yeQ5Ybm18vgM734RZhMgfw4tacUrWseGZlpUrrakEQ=="
+ },
"ramda": {
"version": "0.26.1",
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz",
@@ -35534,6 +35569,20 @@
"prop-types": "^15.6.2"
}
},
+ "react-beautiful-dnd": {
+ "version": "13.0.0",
+ "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.0.0.tgz",
+ "integrity": "sha512-87It8sN0ineoC3nBW0SbQuTFXM6bUqM62uJGY4BtTf0yzPl8/3+bHMWkgIe0Z6m8e+gJgjWxefGRVfpE3VcdEg==",
+ "requires": {
+ "@babel/runtime": "^7.8.4",
+ "css-box-model": "^1.2.0",
+ "memoize-one": "^5.1.1",
+ "raf-schd": "^4.0.2",
+ "react-redux": "^7.1.1",
+ "redux": "^4.0.4",
+ "use-memo-one": "^1.1.1"
+ }
+ },
"react-bootstrap": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-1.3.0.tgz",
@@ -35586,15 +35635,6 @@
"scheduler": "^0.19.1"
}
},
- "react-draggable": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.3.tgz",
- "integrity": "sha512-jV4TE59MBuWm7gb6Ns3Q1mxX8Azffb7oTtDtBgFkxRvhDp38YAARmRplrj0+XGkhOJB5XziArX+4HUUABtyZ0w==",
- "requires": {
- "classnames": "^2.2.5",
- "prop-types": "^15.6.0"
- }
- },
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@@ -35620,6 +35660,28 @@
"warning": "^4.0.3"
}
},
+ "react-redux": {
+ "version": "7.2.2",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.2.tgz",
+ "integrity": "sha512-8+CQ1EvIVFkYL/vu6Olo7JFLWop1qRUeb46sGtIMDCSpgwPQq8fPLpirIB0iTqFe9XYEFPHssdX8/UwN6pAkEA==",
+ "requires": {
+ "@babel/runtime": "^7.12.1",
+ "hoist-non-react-statics": "^3.3.2",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.7.2",
+ "react-is": "^16.13.1"
+ },
+ "dependencies": {
+ "@babel/runtime": {
+ "version": "7.12.5",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz",
+ "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==",
+ "requires": {
+ "regenerator-runtime": "^0.13.4"
+ }
+ }
+ }
+ },
"react-transition-group": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz",
@@ -35904,6 +35966,15 @@
"esprima": "~4.0.0"
}
},
+ "redux": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz",
+ "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==",
+ "requires": {
+ "loose-envify": "^1.4.0",
+ "symbol-observable": "^1.2.0"
+ }
+ },
"regenerate": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz",
@@ -39146,8 +39217,7 @@
"symbol-observable": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
- "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==",
- "dev": true
+ "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
},
"symbol-tree": {
"version": "3.2.4",
@@ -39735,6 +39805,11 @@
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
"dev": true
},
+ "tiny-invariant": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz",
+ "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw=="
+ },
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -40752,6 +40827,11 @@
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
},
+ "use-memo-one": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.1.tgz",
+ "integrity": "sha512-oFfsyun+bP7RX8X2AskHNTxu+R3QdE/RC5IefMbqptmACAA/gfol1KDD5KRzPsGMa62sWxGZw+Ui43u6x4ddoQ=="
+ },
"utf8": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz",
diff --git a/package.json b/package.json
index 50a14088df..e232e3750a 100644
--- a/package.json
+++ b/package.json
@@ -153,9 +153,9 @@
"merge": "^1.2.0",
"npm-install-version": "^6.0.2",
"react": "16.13.1",
+ "react-beautiful-dnd": "^13.0.0",
"react-bootstrap": "^1.3.0",
"react-dom": "16.13.1",
- "react-draggable": "^4.4.3",
"signale": "^1.4.0",
"time-stamp": "^2.2.0",
"winston": "^3.3.3",
@@ -191,6 +191,7 @@
"@types/nightwatch": "^1.1.6",
"@types/node": "~8.9.4",
"@types/react": "16.9.17",
+ "@types/react-beautiful-dnd": "^13.0.0",
"@types/react-dom": "16.9.4",
"@types/react-router-dom": "5.1.3",
"@types/ws": "^7.2.4",