Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: upload and pin table refactor (#2018)
WIP: Refactoring the table renderer for uploads and pins. TODO: - [x] Ensure responsive behaviour on mobile - [x] Add "edit" upload name functionality - [x] Add select row functionality - [x] Add delete Upload functionality - [x] Add delete many functionality - [ ] Refactor Pins table Co-authored-by: Paolo <paolo@potatolondon.com>
- Loading branch information
Showing
17 changed files
with
1,039 additions
and
994 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
packages/website/components/account/filesManager/cellRendererComponents/cidCell.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { useMemo } from 'react'; | ||
|
||
import CopyIcon from 'assets/icons/copy'; | ||
import { addTextToClipboard, truncateString } from 'lib/utils'; | ||
|
||
/** | ||
* @type {import('react').FC} | ||
* Used to render a checkbox cell within a table component. | ||
* @param {Object} props | ||
* @param {string} props.cid the CID of the upload. | ||
* @param {string} props.gatewayPrefix the gateway prefix used for linking to the file in a gateway. | ||
* @returns | ||
*/ | ||
function CidCellRenderer({ cid, gatewayPrefix }) { | ||
const truncatedCID = useMemo(() => truncateString(cid, 5, '...', 'double'), [cid]); | ||
return ( | ||
<span className="cid-cell"> | ||
<a className="cid-truncate underline" href={`${gatewayPrefix}${cid}`} target="_blank" rel="noreferrer"> | ||
{truncatedCID} | ||
</a> | ||
<button | ||
className="copy-icon" | ||
onClick={() => { | ||
addTextToClipboard(cid); | ||
}} | ||
> | ||
<CopyIcon /> | ||
</button> | ||
</span> | ||
); | ||
} | ||
|
||
export default CidCellRenderer; |
92 changes: 92 additions & 0 deletions
92
...ages/website/components/account/filesManager/cellRendererComponents/editUploadNameCell.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import { useRef, useState } from 'react'; | ||
import clsx from 'clsx'; | ||
|
||
import PencilIcon from 'assets/icons/pencil'; | ||
import Loading from 'components/loading/loading'; | ||
|
||
/** | ||
* @type {import('react').FC} | ||
* @param {Object} props | ||
* @param {string} props.name Name of the upload. | ||
* @param {string} props.cid CID of the upload. | ||
* @param {function} props.onNameEdit On edit callback. | ||
* @param {function} props.renameUploadAction Async method to call to rename the upload. | ||
* @returns | ||
*/ | ||
function EditUploadNameRenderer({ name, cid, onNameEdit, renameUploadAction }) { | ||
const [isEditingName, setIsEditingName] = useState(false); | ||
const [isLoading, setIsLoading] = useState(false); | ||
const [editError, setEditError] = useState(''); | ||
|
||
/** @type {import('react').RefObject<HTMLTextAreaElement>} */ | ||
const textAreaInput = useRef(null); | ||
|
||
const toggleEdit = () => { | ||
setIsEditingName(!isEditingName); | ||
}; | ||
|
||
const saveNewName = async (oldName, cid) => { | ||
const newName = textAreaInput.current?.value; | ||
|
||
setIsLoading(true); | ||
|
||
try { | ||
await renameUploadAction(cid, newName); | ||
} catch (error) { | ||
setEditError('Unable to set name.'); | ||
} | ||
|
||
if (editError) { | ||
setEditError(''); | ||
} | ||
|
||
setIsLoading(false); | ||
toggleEdit(); | ||
onNameEdit(); | ||
}; | ||
|
||
return ( | ||
<div className="file-name"> | ||
<div className={clsx(isEditingName && 'editing', 'file-name__container')}> | ||
{/* <span className="file-row-label medium-down-only">{'fileRowLabels.name.label'}</span> */} | ||
{!isEditingName ? ( | ||
<span>{name}</span> | ||
) : ( | ||
<span className="textarea-container"> | ||
<textarea | ||
className={clsx(editError && 'file-name__textarea--error', 'file-name__textarea')} | ||
ref={textAreaInput} | ||
disabled={isLoading} | ||
defaultValue={name} | ||
/> | ||
</span> | ||
)} | ||
<div className="file-name__action-button-container"> | ||
{isEditingName && ( | ||
<button | ||
className="file-name__action-buttons file-name__action-buttons--save" | ||
disabled={isLoading} | ||
onClick={() => { | ||
saveNewName(name, cid); | ||
}} | ||
> | ||
{isLoading ? <Loading size="small" /> : 'Save'} | ||
</button> | ||
)} | ||
<button | ||
className={clsx(isEditingName && 'file-name__action-buttons--cancel', 'file-name__action-buttons')} | ||
disabled={isLoading} | ||
onClick={() => { | ||
toggleEdit(); | ||
}} | ||
> | ||
{isEditingName ? 'Cancel' : <PencilIcon className={clsx('pencil-icon')} />} | ||
</button> | ||
</div> | ||
</div> | ||
{editError && isEditingName && <span className="file-name__textarea-hint-text--error">{editError}</span>} | ||
</div> | ||
); | ||
} | ||
|
||
export default EditUploadNameRenderer; |
55 changes: 55 additions & 0 deletions
55
...es/website/components/account/filesManager/cellRendererComponents/storageProvidersCell.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { renderToString } from 'react-dom/server'; | ||
|
||
import Tooltip from 'ZeroComponents/tooltip/tooltip'; | ||
|
||
/** | ||
* @typedef {import('web3.storage').Deal} Deal | ||
*/ | ||
/** | ||
* @type {import('react').FC} | ||
* @param {object} props | ||
* @param {Deal[]} props.deals list of deals associated with an upload | ||
* @param {string} props.tooltipText strings | ||
* @returns | ||
*/ | ||
function StorageProvidersCellRenderer({ deals, tooltipText }) { | ||
const storageProviders = Array.isArray(deals) | ||
? deals | ||
.filter(deal => !!deal.storageProvider) | ||
.map((deal, indx, deals) => ( | ||
<span key={deal.dealId}> | ||
<a | ||
className="underline" | ||
href={`https://filfox.info/en/deal/${deal.dealId}`} | ||
target="_blank" | ||
rel="noreferrer" | ||
> | ||
{`${deal.storageProvider}`} | ||
</a> | ||
{indx !== deals.length - 1 && ', '} | ||
</span> | ||
)) | ||
: null; | ||
|
||
if (!storageProviders) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<span className="file-storage-providers"> | ||
{!storageProviders.length ? ( | ||
<> | ||
Queuing... | ||
<Tooltip position="right" content={tooltipText} /> | ||
</> | ||
) : ( | ||
<> | ||
Stored ({storageProviders.length}) | ||
<Tooltip position="right" content={renderToString(<p>{storageProviders}</p>)} /> | ||
</> | ||
)} | ||
</span> | ||
); | ||
} | ||
|
||
export default StorageProvidersCellRenderer; |
48 changes: 48 additions & 0 deletions
48
packages/website/components/account/filesManager/cellRendererComponents/uploadStatusCell.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { BsFillInfoCircleFill } from 'react-icons/bs'; | ||
|
||
import Tooltip from 'ZeroComponents/tooltip/tooltip'; | ||
|
||
export const PinStatus = { | ||
PINNED: 'Pinned', | ||
PINNING: 'Pinning', | ||
PIN_QUEUED: 'PinQueued', | ||
QUEUING: 'Queuing...', | ||
}; | ||
|
||
/** | ||
* @typedef {import('web3.storage').Pin} Pin | ||
*/ | ||
|
||
/** | ||
* @type {import('react').FC} | ||
* @param {object} props | ||
* @param {Pin[]} props.pins All pin data for the upload. | ||
* @param {object} props.statusMessages Status message strings for the status tooltip. | ||
* @returns | ||
*/ | ||
function UploadStatusTableRenderer({ pins, statusMessages }) { | ||
if (!pins) { | ||
// TODO: Ensure we return something to convey to the user no pins are on this upload. | ||
return <span></span>; | ||
} | ||
|
||
const status = Object.values(PinStatus).find(status => pins.some(pin => status === pin.status)) || PinStatus.QUEUING; | ||
|
||
const statusTooltips = { | ||
[PinStatus.QUEUING]: statusMessages.queuing, | ||
[PinStatus.PIN_QUEUED]: statusMessages.pin_queued, | ||
[PinStatus.PINNING]: statusMessages.pinning, | ||
[PinStatus.PINNED]: statusMessages.pinned.replace('*numberOfPins*', `${pins.length}`), | ||
}; | ||
|
||
const statusTooltip = statusTooltips[status]; | ||
|
||
const tooltip = statusTooltip ? <Tooltip icon={<BsFillInfoCircleFill />} content={statusTooltip} /> : null; | ||
return ( | ||
<span> | ||
{status === PinStatus.PINNED ? 'Complete' : status} {tooltip} | ||
</span> | ||
); | ||
} | ||
|
||
export default UploadStatusTableRenderer; |
Oops, something went wrong.