Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion public/locales/en/files.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@
},
"shareModal": {
"title": "Share files",
"description": "Copy the link below and share it with your friends."
"description": "Copy the link below and share it with your friends.",
"descriptionLocal": "Use this link to open in apps running on this machine.",
"useLocalLink": "Local link for other apps on this machine",
"useSubdomains": "Use localhost subdomains for web apps"
},
"renameModal": {
"titleFile": "Rename file",
Expand Down
16 changes: 15 additions & 1 deletion src/bundles/files/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -600,12 +600,26 @@ const actions = () => ({
// ensureMFS deliberately omitted here, see https://github.com/ipfs/ipfs-webui/issues/1744 for context.
const publicGateway = store.selectPublicGateway()
const publicSubdomainGateway = store.selectPublicSubdomainGateway()
const gatewayUrl = store.selectGatewayUrl()
const { link: shareableLink, cid } = await getShareableLink(files, publicGateway, publicSubdomainGateway, ipfs)

// Build local gateway link for use in external apps
let filename = ''
if (files.length === 1 && files[0].type === 'file') {
filename = `?filename=${encodeURIComponent(files[0].name)}`
}
const localLink = `${gatewayUrl}/ipfs/${cid}${filename}`

// Build localhost subdomain link for web apps (origin isolation)
const gwUrl = new URL(gatewayUrl)
const base32Cid = cid.toV1().toString()
const port = gwUrl.port ? `:${gwUrl.port}` : ''
const subdomainLocalLink = `http://${base32Cid}.ipfs.localhost${port}/${filename}`

// Trigger background provide operation with the CID from getShareableLink
dispatchAsyncProvide(cid, ipfs)

return shareableLink
return { link: shareableLink, localLink, subdomainLocalLink }
}),

/**
Expand Down
14 changes: 12 additions & 2 deletions src/files/modals/Modals.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ class Modals extends React.Component {
files: []
},
link: '',
localLink: '',
subdomainLocalLink: '',
command: 'ipfs --help'
}

Expand Down Expand Up @@ -132,10 +134,16 @@ class Modals extends React.Component {
case SHARE: {
this.setState({
link: t('generating'),
localLink: '',
subdomainLocalLink: '',
readyToShow: true
})

onShareLink(files).then(link => this.setState({ link }))
onShareLink(files).then(result => this.setState({
link: result.link,
localLink: result.localLink,
subdomainLocalLink: result.subdomainLocalLink
}))
break
}
case RENAME: {
Expand Down Expand Up @@ -245,7 +253,7 @@ class Modals extends React.Component {

render () {
const { show, t } = this.props
const { readyToShow, link, rename, command } = this.state
const { readyToShow, link, localLink, subdomainLocalLink, rename, command } = this.state
return (
<div>
<Overlay show={show === NEW_FOLDER && readyToShow} onLeave={this.leave}>
Expand All @@ -259,6 +267,8 @@ class Modals extends React.Component {
<ShareModal
className='outline-0'
link={link}
localLink={localLink}
subdomainLocalLink={subdomainLocalLink}
onLeave={this.leave} />
</Overlay>

Expand Down
93 changes: 65 additions & 28 deletions src/files/modals/share-modal/ShareModal.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,85 @@
import React from 'react'
import React, { useState } from 'react'
import PropTypes from 'prop-types'
import QRCode from 'react-qr-code'
import Button from '../../../components/button/button.tsx'
import Checkbox from '../../../components/checkbox/Checkbox.js'
import { withTranslation } from 'react-i18next'
import { CopyToClipboard } from 'react-copy-to-clipboard'
import { Modal, ModalActions, ModalBody } from '../../../components/modal/modal'

const ShareModal = ({ t, tReady, onLeave, link, className, ...props }) => (
<Modal {...props} className={className} onCancel={onLeave} >
<ModalBody title={t('shareModal.title')}>
<p className='charcoal w-90 center'>{t('shareModal.description')}</p>
<div className='flex justify-center pb3'>
<QRCode
size={180}
value={link}
/>
</div>
<div className='flex center w-90 pb2'>
<input
value={link}
readOnly
className={'input-reset flex-grow-1 charcoal-muted ba b--black-20 br1 pa2 mr2 focus-outline'}
type='text' />
</div>
</ModalBody>
const ShareModal = ({ t, tReady, onLeave, link, localLink, subdomainLocalLink, className, ...props }) => {
const [useLocalLink, setUseLocalLink] = useState(false)
const [useSubdomains, setUseSubdomains] = useState(false)

<ModalActions>
<Button className='ma2 tc' bg='bg-gray' onClick={onLeave}>{t('app:actions.close')}</Button>
<CopyToClipboard text={link} onCopy={onLeave}>
<Button className='ma2 tc'>{t('app:actions.copy')}</Button>
</CopyToClipboard>
</ModalActions>
</Modal>
)
let activeLink = link
if (useLocalLink && localLink) {
activeLink = useSubdomains && subdomainLocalLink ? subdomainLocalLink : localLink
}

return (
<Modal {...props} className={className} onCancel={onLeave} >
<ModalBody title={t('shareModal.title')}>
<p className='charcoal w-90 center'>
{useLocalLink ? t('shareModal.descriptionLocal') : t('shareModal.description')}
</p>
{!useLocalLink && (
<div className='flex justify-center pb3'>
<QRCode
size={180}
value={activeLink}
/>
</div>
)}
<div className='flex center w-90 pb2'>
<input
value={activeLink}
readOnly
className={'input-reset flex-grow-1 charcoal-muted ba b--black-20 br1 pa2 mr2 focus-outline'}
type='text' />
</div>
{localLink && (
<div className='flex center w-90 pb2'>
<Checkbox
checked={useLocalLink}
onChange={setUseLocalLink}
label={t('shareModal.useLocalLink')}
/>
</div>
)}
{useLocalLink && subdomainLocalLink && (
<div className='flex center w-90 pb2 ml3'>
<Checkbox
checked={useSubdomains}
onChange={setUseSubdomains}
label={t('shareModal.useSubdomains')}
/>
</div>
)}
</ModalBody>

<ModalActions>
<Button className='ma2 tc' bg='bg-gray' onClick={onLeave}>{t('app:actions.close')}</Button>
<CopyToClipboard text={activeLink} onCopy={onLeave}>
<Button className='ma2 tc'>{t('app:actions.copy')}</Button>
</CopyToClipboard>
</ModalActions>
</Modal>
)
}

ShareModal.propTypes = {
onLeave: PropTypes.func.isRequired,
link: PropTypes.string,
localLink: PropTypes.string,
subdomainLocalLink: PropTypes.string,
t: PropTypes.func.isRequired,
tReady: PropTypes.bool.isRequired
}

ShareModal.defaultProps = {
className: ''
className: '',
localLink: '',
subdomainLocalLink: ''
}

export default withTranslation('files')(ShareModal)
2 changes: 2 additions & 0 deletions src/files/modals/share-modal/ShareModal.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export const Share = () => (
<ShareModal
onLeave={action('Leave')}
link="https://ipfs.io/ipfs/QmQK3p7MmycDutWkWAzJ4hNN1YBKK9bLTDz9jTtkWf16wC"
localLink="http://127.0.0.1:8080/ipfs/QmQK3p7MmycDutWkWAzJ4hNN1YBKK9bLTDz9jTtkWf16wC"
subdomainLocalLink="http://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi.ipfs.localhost:8080/"
/>
</div>
)
Loading