Publish to gist

pull/668/head
ioedeveloper 4 years ago
parent 71cee4b01c
commit 568324e84c
  1. 465
      libs/remix-ui/file-explorer/src/lib/file-explorer.tsx
  2. 4
      libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx
  3. 1
      libs/remix-ui/tree-view/src/types/index.ts
  4. 102
      package-lock.json
  5. 3
      package.json

@ -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 (
<div className='remixui_items'>
<span
title={data.path}
className={'remixui_label ' + (data.isDirectory ? 'folder' : 'remixui_leaf')}
data-path={data.path}
// onkeydown=${editModeOff}
// onblur=${editModeOff}
>
{ data.path.split('/').pop() }
</span>
</div>
)
}
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 (
<div className='remixui_items'>
<span
title={data.path}
className={'remixui_label ' + (data.isDirectory ? 'folder' : 'remixui_leaf')}
data-path={data.path}
// onkeydown=${editModeOff}
// onblur=${editModeOff}
>
{ data.path.split('/').pop() }
</span>
</div>
)
}
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 (
<Draggable key={index} axis="y" bounds="parent">
<TreeViewItem
id={`treeViewItem${file.path}`}
iconX='pr-3 far fa-folder'
iconY='pr-3 far fa-folder-open'
key={`${file.path + index}`}
label={label(file)}
onClick={(e) => {
e.stopPropagation()
handleClickFolder(file.path)
}}
labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' }
controlBehaviour={ state.ctrlKey }
>
{
file.child ? <TreeView id={`treeView${file.path}`} key={index}>{
file.child.map((file, index) => {
return renderFiles(file, index)
})
<Droppable droppableId={file.path} key={index}>
{(provided) => (
<TreeViewItem
{ ...provided.droppableProps }
innerRef={ provided.innerRef }
id={`treeViewItem${file.path}`}
iconX='pr-3 far fa-folder'
iconY='pr-3 far fa-folder-open'
key={`${file.path + index}`}
label={label(file)}
onClick={(e) => {
e.stopPropagation()
handleClickFolder(file.path)
}}
labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' }
controlBehaviour={ state.ctrlKey }
>
{
file.child ? <TreeView id={`treeView${file.path}`} key={index}>{
file.child.map((file, index) => {
return renderFiles(file, index)
})
}
</TreeView> : <TreeView id={`treeView${file.path}`} key={index} />
}
</TreeView> : <TreeView id={`treeView${file.path}`} key={index} />
}
</TreeViewItem>
</Draggable>
{ provided.placeholder }
</TreeViewItem>
)}
</Droppable>
)
} else {
return (
<Draggable key={index} axis="y" bounds="parent">
<TreeViewItem
id={`treeViewItem${file.path}`}
key={index}
label={label(file)}
onClick={(e) => {
e.stopPropagation()
handleClickFile(file.path)
}}
icon='fa fa-file'
labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' }
/>
<Draggable draggableId={file.path} index={index} key={index}>
{(provided) => (
<TreeViewItem
{...provided.draggableProps}
{...provided.dragHandleProps}
innerRef={provided.innerRef}
id={`treeViewItem${file.path}`}
key={index}
label={label(file)}
onClick={(e) => {
e.stopPropagation()
handleClickFile(file.path)
}}
icon='fa fa-file'
labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' }
/>
)}
</Draggable>
)
}
@ -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) => {
>
<TreeView id='treeView'>
<TreeViewItem id="treeViewItem" label={renderMenuItems()} expand={true}>
<Draggable onStart={() => false}>
<div>
<TreeView id='treeViewMenu'>
{
state.files.map((file, index) => {
return renderFiles(file, index)
})
}
</TreeView>
</div>
</Draggable>
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId='droppableTreeView'>
{(provided) => (
<div
{ ...provided.droppableProps }
ref={ provided.innerRef }>
<TreeView id='treeViewMenu'>
{
state.files.map((file, index) => {
return renderFiles(file, index)
})
}
</TreeView>
{ provided.placeholder }
</div>
)}
</Droppable>
</DragDropContext>
</TreeViewItem>
</TreeView>
</div>

@ -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 (
<li key={`treeViewLi${id}`} data-id={`treeViewLi${id}`} className='li_tv' {...otherProps}>
<li ref={innerRef} key={`treeViewLi${id}`} data-id={`treeViewLi${id}`} className='li_tv' {...otherProps}>
<div key={`treeViewDiv${id}`} data-id={`treeViewDiv${id}`} className={`d-flex flex-row align-items-center ${labelClass}`} onClick={() => !controlBehaviour && setIsExpanded(!isExpanded)}>
{ children ? <div className={isExpanded ? `px-1 ${iconY} caret caret_tv` : `px-1 ${iconX} caret caret_tv`} style={{ visibility: children ? 'visible' : 'hidden' }}></div> : icon ? <div className={`pr-3 pl-1 ${icon} caret caret_tv`}></div> : null }
<span className='w-100 pl-1'>

@ -15,4 +15,5 @@ export interface TreeViewItemProps {
icon?: string,
labelClass?: string,
controlBehaviour?: boolean
innerRef?: any
}

102
package-lock.json generated

@ -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",

@ -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",

Loading…
Cancel
Save