Skip to content

Commit

Permalink
WIP: bulk import modal UX
Browse files Browse the repository at this point in the history
  • Loading branch information
MattWong-ca committed Dec 6, 2024
1 parent 35e392d commit 31ea252
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 7 deletions.
9 changes: 6 additions & 3 deletions src/files/FilesPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import FilesList from './files-list/FilesList.js'
import { getJoyrideLocales } from '../helpers/i8n.js'

// Icons
import Modals, { DELETE, NEW_FOLDER, SHARE, RENAME, ADD_BY_PATH, CLI_TUTOR_MODE, PINNING, PUBLISH } from './modals/Modals.js'
import Modals, { DELETE, NEW_FOLDER, SHARE, RENAME, ADD_BY_PATH, BULK_CID_IMPORT, CLI_TUTOR_MODE, PINNING, PUBLISH } from './modals/Modals.js'
import Header from './header/Header.js'
import FileImportStatus from './file-import-status/FileImportStatus.js'
import { useExplore } from 'ipld-explorer-components/providers'
Expand Down Expand Up @@ -72,7 +72,7 @@ const FilesPage = ({
doFilesWrite(raw, root)
}

const onAddBulkCid = (raw, root = '') => {
const onBulkCidImport = (raw, root = '') => {
if (root === '') root = files.path
doFilesAddBulkCid(raw, root)
}
Expand Down Expand Up @@ -209,9 +209,11 @@ const FilesPage = ({
files={files}
onNavigate={doFilesNavigateTo}
onAddFiles={onAddFiles}
onAddBulkCid={onAddBulkCid}
// onAddBulkCid={onAddBulkCid}
// onBulkCidImport={onBulkCidImport}
onMove={doFilesMove}
onAddByPath={(files) => showModal(ADD_BY_PATH, files)}
onBulkCidImport={(files) => showModal(BULK_CID_IMPORT, files)}
onNewFolder={(files) => showModal(NEW_FOLDER, files)}
onCliTutorMode={() => showModal(CLI_TUTOR_MODE)}
handleContextMenu={(...args) => handleContextMenu(...args, true)} />
Expand All @@ -232,6 +234,7 @@ const FilesPage = ({
onShareLink={doFilesShareLink}
onRemove={doFilesDelete}
onAddByPath={onAddByPath}
onBulkCidImport={onBulkCidImport}
onPinningSet={doSetPinning}
onPublish={doPublishIpnsKey}
cliOptions={cliOptions}
Expand Down
14 changes: 11 additions & 3 deletions src/files/file-input/FileInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ class FileInput extends React.Component {
}

onBulkCidInputChange = (input) => async () => {
this.props.onAddBulkCid(normalizeFiles(input.files))
console.log('onBulkCidInputChange', input)
this.props.onBulkCidImport(normalizeFiles(input.files))
input.value = null
}

Expand All @@ -60,6 +61,11 @@ class FileInput extends React.Component {
this.toggleDropdown()
}

onBulkCidImport = () => {
this.props.onBulkCidImport()
this.toggleDropdown()
}

onNewFolder = () => {
this.props.onNewFolder()
this.toggleDropdown()
Expand Down Expand Up @@ -102,7 +108,9 @@ class FileInput extends React.Component {
<NewFolderIcon className='fill-aqua w2 h2 mr1' />
{t('newFolder')}
</Option>
<Option onClick={this.onAddBulkCid}
<Option
// onClick={this.onAddBulkCid}
onClick={this.onBulkCidImport}
// TO-DO:
// id='add-bulk-cid'
// onCliTutorMode={() => this.onCliTutorMode(cliCmdKeys.FROM_IPFS)}
Expand Down Expand Up @@ -149,7 +157,7 @@ FileInput.propTypes = {
onAddFiles: PropTypes.func.isRequired,
onAddByPath: PropTypes.func.isRequired,
onNewFolder: PropTypes.func.isRequired,
onAddBulkCid: PropTypes.func.isRequired
onBulkCidImport: PropTypes.func.isRequired
}

export default connect(
Expand Down
2 changes: 1 addition & 1 deletion src/files/header/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class Header extends React.Component {
onNewFolder={this.props.onNewFolder}
onAddFiles={this.props.onAddFiles}
onAddByPath={this.props.onAddByPath}
onAddBulkCid={this.props.onAddBulkCid}
onBulkCidImport={this.props.onBulkCidImport}
onCliTutorMode={this.props.onCliTutorMode}
/>
: <div ref={el => { this.dotsWrapper = el }}>
Expand Down
18 changes: 18 additions & 0 deletions src/files/modals/Modals.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import RenameModal from './rename-modal/RenameModal.js'
import PinningModal from './pinning-modal/PinningModal.js'
import RemoveModal from './remove-modal/RemoveModal.js'
import AddByPathModal from './add-by-path-modal/AddByPathModal.js'
import BulkImportModal from './bulk-import-modal/BulkImportModal.js'
import PublishModal from './publish-modal/PublishModal.js'
import CliTutorMode from '../../components/cli-tutor-mode/CliTutorMode.js'
import { cliCommandList, cliCmdKeys } from '../../bundles/files/consts.js'
Expand All @@ -20,6 +21,7 @@ const SHARE = 'share'
const RENAME = 'rename'
const DELETE = 'delete'
const ADD_BY_PATH = 'add_by_path'
const BULK_CID_IMPORT = 'bulk_cid_import'
const CLI_TUTOR_MODE = 'cli_tutor_mode'
const PINNING = 'pinning'
const PUBLISH = 'publish'
Expand All @@ -30,6 +32,7 @@ export {
RENAME,
DELETE,
ADD_BY_PATH,
BULK_CID_IMPORT,
CLI_TUTOR_MODE,
PINNING,
PUBLISH
Expand Down Expand Up @@ -63,6 +66,11 @@ class Modals extends React.Component {
this.leave()
}

onBulkCidImport = () => {
this.props.onBulkCidImport()
this.leave()
}

makeDir = (path) => {
this.props.onMakeDir(join(this.props.root, path))
this.leave()
Expand Down Expand Up @@ -152,6 +160,9 @@ class Modals extends React.Component {
case ADD_BY_PATH:
this.setState({ readyToShow: true })
break
case BULK_CID_IMPORT:
this.setState({ readyToShow: true })
break
case CLI_TUTOR_MODE:
this.setState({ command: this.cliCommand(cliOptions, files, root) }, () => {
this.setState({ readyToShow: true })
Expand Down Expand Up @@ -254,6 +265,13 @@ class Modals extends React.Component {
onCancel={this.leave} />
</Overlay>

<Overlay show={show === BULK_CID_IMPORT && readyToShow} onLeave={this.leave}>
<BulkImportModal
className='outline-0'
onBulkCidImport={this.onBulkCidImport}
onCancel={this.leave} />
</Overlay>

<Overlay show={show === CLI_TUTOR_MODE && readyToShow} onLeave={this.leave}>
<CliTutorMode onLeave={this.leave} filesPage={true} command={command} t={t}/>
</Overlay>
Expand Down
185 changes: 185 additions & 0 deletions src/files/modals/bulk-import-modal/BulkImportModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import React from 'react'
import PropTypes from 'prop-types'
import Button from '../../../components/button/button.tsx'
import { Modal, ModalActions, ModalBody } from '../../../components/modal/Modal.js'
import { withTranslation } from 'react-i18next'
import * as isIPFS from 'is-ipfs'
import Icon from '../../../icons/StrokeDocument.js'
import { normalizeFiles } from '../../../lib/files.js'

class BulkImportModal extends React.Component {
static propTypes = {
onCancel: PropTypes.func.isRequired,
onBulkCidImport: PropTypes.func.isRequired,
className: PropTypes.string
}

static defaultProps = {
className: ''
}

state = {
path: '',
name: '',
selectedFile: null
}

validatePath = (p) => {
if (!p.startsWith('/ipfs/')) {
p = `/ipfs/${p}`
}

return isIPFS.ipfsPath(p)
}

onChange = (event) => {
const target = event.target
const value = target.value
const name = target.name
this.setState({ [name]: value })
}

handleFileSelect = (event) => {
console.log('File select triggered', event)
const file = event.target.files[0]
this.setState({ selectedFile: file })
}

onBulkCidInputChange = (event) => async () => {
console.log('event', event)
console.log('event.files', event.files)
// const input = event.target
// console.log('Input element:', input)
// console.log('Input files:', input?.files)
// if (!input || !input.files) {
// console.error('Input or files not available')
// return
// }
this.props.onBulkCidImport(normalizeFiles(event))
// input.value = null
}

onSubmit = () => {
console.log('submit')
}

// onSubmit = () => {
// let { path, name } = this.state
// if (this.validatePath(path)) {
// // avoid issues with paths by forcing a flat filename without leading/trailing spaces
// name = name.replaceAll('/', '_').trim()
// this.props.onSubmit(path, name)
// }
// }

// onKeyPress = (event) => {
// if (event.key === 'Enter') {
// this.onSubmit()
// }
// }

get inputClass () {
if (this.state.path === '') {
return ''
}

if (this.validatePath(this.state.path)) {
return 'b--green-muted focus-outline-green'
}

return 'b--red-muted focus-outline-red'
}

// get isDisabled () {
// if (this.state.path === '') {
// return true
// }

// return !this.validatePath(this.state.path)
// }

render () {
const {
t, onCancel, className
} = this.props

const codeClass = 'w-100 mb1 pa1 tl bg-snow f7 charcoal-muted truncate'

return (
<Modal className={className} onCancel={onCancel}>
<ModalBody title={'Bulk Import with Text File'} Icon={Icon}>
<div className='mb3 flex flex-column items-center'>
<p className='mt0 charcoal tl w-100'>{'Upload a text file with a list of CIDs (names are optional).' + ' ' + 'Example:'}</p>
<code className={codeClass}>bafkreibm6jg3ux5qumhcn2b3flc3tyu6dmlb4xa7u5bf44yegnrjhc4yeq<br/>QmawceGscqN4o8Y8Fv26UUmB454kn2bnkXV5tEQYc4jBd6 barrel.png<br/>QmbvrHYWXAU1BuxMPNRtfeF4DS2oPmo5hat7ocqAkNPr74 pi equals.png</code>
</div>

<input
type='file'
className='dn'
multiple
accept='.txt'
onChange={this.handleFileSelect}
// className='input-reset'
id='bulk-import'
ref={el => {
console.log('Setting ref:', el)
this.bulkCidInput = el
}}
// onChange={this.onBulkCidInputChange(this.bulkCidInput)}
// onChange={(e) => {
// console.log('onChange triggered, current ref:', this.bulkCidInput)
// console.log('onChange event:', e)
// console.log('onChange target:', e.target)
// console.log('onChange files:', e.target.files)
// this.onBulkCidInputChange(this.bulkCidInput)
// }}
// onChange={() => {
// // Make sure we're using the current ref
// console.log('onChange triggered, current ref:', this.bulkCidInput)
// this.onBulkCidInputChange(this.bulkCidInput)()
// }}
/>
<Button
// onClick={() => {
// if (this.bulkCidInput) {
// this.bulkCidInput.click()
// }
// }}
onClick={(e) => {
console.log('clicked')
document.getElementById('bulk-import').click()
}}
className='ma2 tc'
bg='bg-teal'
type='button'
>
{'Select File'}
</Button>
{this.state.selectedFile && (
<p className='mt2 charcoal'>
Selected file: {this.state.selectedFile.name}
</p>
)}

{/* <input
onChange={this.onChange}
onKeyPress={this.onKeyPress}
value={this.state.value}
name='path'
required
placeholder={t('addByPathModal.importPathPlaceholder')}
className={`input-reset charcoal ba b--black-20 br1 pa2 mb2 db w-90 center focus-outline ${this.inputClass}`}
type='text' /> */}

</ModalBody>

<ModalActions>
<Button className='ma2 tc' bg='bg-gray' onClick={onCancel}>{t('actions.cancel')}</Button>
<Button className='ma2 tc' bg='bg-teal' /* disabled={this.isDisabled} */ onClick={this.onBulkCidInputChange(this.bulkCidInput)}>{t('app:actions.import')}</Button>
</ModalActions>
</Modal>
)
}
}

export default withTranslation('files')(BulkImportModal)

0 comments on commit 31ea252

Please sign in to comment.