Skip to content

Commit

Permalink
fix: cleanup size and bandwidth units (#1791)
Browse files Browse the repository at this point in the history
* fix: base-2 file sizes, base-10 network bandwidth

This cleans up code around human readable units:

- base-2 (GiB, MiB, KiB) used for file sizes to remove any unit confusion
  while keeping interop with 1024 mindset

- base-10 (Mbps, kbps) used for network bandwith, to match what ISP are
  selling

Closes #1778

* chore: fix ts lint
  • Loading branch information
lidel committed May 21, 2021
1 parent dd2b161 commit 1d99482
Show file tree
Hide file tree
Showing 14 changed files with 140 additions and 112 deletions.
143 changes: 74 additions & 69 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"details-polyfill": "^1.1.0",
"eslint-plugin-jsx-a11y": "^6.3.1",
"file-extension": "^4.0.5",
"filesize": "^6.1.0",
"filesize": "^6.3.0",
"hashlru": "^2.3.0",
"i18next": "^20.1.0",
"i18next-browser-languagedetector": "^6.1.0",
Expand Down
5 changes: 2 additions & 3 deletions src/components/pinning-manager/PinningManager.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { Fragment, useEffect, useState, useMemo, useRef } from 'react'
import { connect } from 'redux-bundler-react'
// import filesize from 'filesize'
import { AutoSizer, Table, Column, SortDirection } from 'react-virtualized'
import { sortByProperty } from '../../lib/sort'

Expand Down Expand Up @@ -137,8 +136,8 @@ const ServiceCell = ({ rowData, rowIndex }) => (
// const SizeCell = ({ rowData, t }) => (
// <p className={ !rowData.totalSize ? 'gray nowrap' : 'nowrap'}>{ !rowData.totalSize
// ? `${(t('app:terms:loading'))}...`
// : filesize(rowData.totalSize || 0, {
// round: rowData.totalSize >= 1000000000 ? 1 : 0, spacer: ''
// : humanSize(rowData.totalSize || 0, {
// round: rowData.totalSize >= 1073741824 ? 1 : 0, spacer: ''
// })}</p>
// )
const NumberOfPinsCell = ({ rowData, t }) => {
Expand Down
4 changes: 2 additions & 2 deletions src/files/file-import-status/FileImportStatus.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useMemo, useState, useCallback } from 'react'
import filesize from 'filesize'
import { humanSize } from '../../lib/files'
import PropTypes from 'prop-types'
import { connect } from 'redux-bundler-react'
import { withTranslation } from 'react-i18next'
Expand All @@ -20,7 +20,7 @@ const Import = (job, t) =>
<span className="fileImportStatusName truncate">{item.path}</span>
<span className='gray mh2'> |
{ item.entries && (<span> { t('filesImportStatus.count', { count: item.entries.length }) } | </span>) }
<span className='ml2'>{ filesize(item.size) }</span>
<span className='ml2'>{ humanSize(item.size) }</span>
</span>
{viewImportStatus(job, item.progress)}
</li>
Expand Down
5 changes: 2 additions & 3 deletions src/files/file/File.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React, { useRef } from 'react'
import PropTypes from 'prop-types'
import { join, basename } from 'path'
import filesize from 'filesize'
import { withTranslation } from 'react-i18next'
import classnames from 'classnames'
import { normalizeFiles } from '../../lib/files'
import { normalizeFiles, humanSize } from '../../lib/files'
// React DnD
import { useDrag, useDrop } from 'react-dnd'
// Components
Expand Down Expand Up @@ -96,7 +95,7 @@ const File = ({
styles.borderTop = '1px solid #eee'
}

size = size ? filesize(size, { round: 0 }) : '-'
size = size ? humanSize(size, { round: 0 }) : '-'
const hash = cid.toString() || t('hashUnavailable')

const select = (select) => onSelect(name, select)
Expand Down
20 changes: 9 additions & 11 deletions src/files/header/Header.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react'
import filesize from 'filesize'
import classNames from 'classnames'
import { connect } from 'redux-bundler-react'
import { withTranslation } from 'react-i18next'
import { humanSize } from '../../lib/files'
// Components
import Breadcrumbs from '../breadcrumbs/Breadcrumbs'
import FileInput from '../file-input/FileInput'
Expand All @@ -17,13 +17,11 @@ const BarOption = ({ children, text, isLink = false, className = '', ...etc }) =
</div>
)

function humanSize (size) {
if (!size) return 'N/A'

return filesize(size || 0, {
round: size >= 1000000000 ? 1 : 0, spacer: ''
})
}
// Tweak human-readable size format to be more compact
const size = (s) => humanSize(s, {
round: s >= 1073741824 ? 1 : 0, // show decimal > 1GiB
spacer: ''
})

class Header extends React.Component {
handleContextMenu = (ev) => {
Expand Down Expand Up @@ -65,14 +63,14 @@ class Header extends React.Component {
{ hasUpperDirectory
? (
<span>
{ humanSize(currentDirectorySize) }<span className='f5 gray'>/{ humanSize(filesSize) }</span>
{ size(currentDirectorySize) }<span className='f5 gray'>/{ size(filesSize) }</span>
</span>
)
: humanSize(filesSize) }
: size(filesSize) }
</BarOption>

<BarOption title={t('allBlocksDescription')} text={t('allBlocks')}>
{ humanSize(repoSize) }
{ size(repoSize) }
</BarOption>

<div className='pa3'>
Expand Down
10 changes: 1 addition & 9 deletions src/files/modals/pinning-modal/PinningModal.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
import React, { useEffect, useMemo, useState } from 'react'
import PropTypes from 'prop-types'
import { /* Trans, */ withTranslation } from 'react-i18next'
import filesize from 'filesize'
import { humanSize } from '../../../lib/files'
import Button from '../../../components/button/Button'
import Checkbox from '../../../components/checkbox/Checkbox'
import GlyphPin from '../../../icons/GlyphPin'
import { Modal, ModalActions, ModalBody } from '../../../components/modal/Modal'
import { connect } from 'redux-bundler-react'
import './PinningModal.css'

const humanSize = (size) => {
if (!size) return 'N/A'

return filesize(size || 0, {
round: size >= 1000000000 ? 1 : 0, spacer: ''
})
}

const PinIcon = ({ icon, index }) => {
if (icon) {
return <img className="mr1" src={icon} alt='' width={32} height={32} style={{ objectFit: 'contain' }} />
Expand Down
4 changes: 2 additions & 2 deletions src/files/selected-actions/SelectedActions.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import classNames from 'classnames'
import PropTypes from 'prop-types'
import filesize from 'filesize'
import { humanSize } from '../../lib/files'
import { withTranslation } from 'react-i18next'
import StrokePin from '../../icons/StrokePin'
import GlyphSmallCancel from '../../icons/GlyphSmallCancel'
Expand Down Expand Up @@ -120,7 +120,7 @@ class SelectedActions extends React.Component {
</div>
<div className='dn db-l f6'>
<p className='ma0'>{t('filesSelected', { count })}</p>
<p className='ma0 mt1' style={styles.size}>{t('totalSize', { size: filesize(size) })}</p>
<p className='ma0 mt1' style={styles.size}>{t('totalSize', { size: humanSize(size) })}</p>
</div>
</div>
</div>
Expand Down
19 changes: 19 additions & 0 deletions src/lib/files.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import filesize from 'filesize'
/**
* @typedef {import('ipfs').IPFSService} IPFSService
* @typedef {import('../bundles/files/actions').FileStat} FileStat
Expand Down Expand Up @@ -138,3 +139,21 @@ export async function getShareableLink (files, ipfs) {

return `https://ipfs.io/ipfs/${cid}${filename || ''}`
}

/**
* @param {number} size in bytes
* @param {object} opts format customization
* @returns {string} human-readable size
*/
export function humanSize (size, opts) {
if (typeof size === 'undefined') return 'N/A'
return filesize(size || 0, {
// base-2 byte units (GiB, MiB, KiB) to remove any ambiguity
spacer: String.fromCharCode(160), // non-breakable space (&nbsp)
round: size >= 1073741824 ? 1 : 0, // show decimal > 1GiB
standard: 'iec',
base: 2,
bits: false,
...opts
})
}
18 changes: 13 additions & 5 deletions src/status/NodeBandwidthChart.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,16 @@ import PropTypes from 'prop-types'
import filesize from 'filesize'
import { Title } from './Commons'

const chartsize = filesize.partial({ round: 1, exponent: 2, bits: true })
const tootltipSize = filesize.partial({ round: 0, bits: true, output: 'array' })
// network bandwidth units in base-10 bits (Mbps)
// to align with what ISP usually shows on invoice
const humanUnits = {
standard: 'jedec',
base: 10,
bits: true
}

const chartsize = filesize.partial({ round: 1, exponent: 2, ...humanUnits })
const tootltipSize = filesize.partial({ round: 0, output: 'array', ...humanUnits })

const defaultSettings = {
defaultFontFamily: "'Inter UI', system-ui, sans-serif",
Expand All @@ -29,7 +37,7 @@ const defaultSettings = {
yAxes: [{
stacked: true,
ticks: {
callback: v => chartsize(v) + '/s',
callback: v => chartsize(v) + 'ps',
suggestedMax: 200000,
maxTicksLimit: 5
}
Expand Down Expand Up @@ -65,12 +73,12 @@ const Tooltip = ({ t, bw, show, pos }) => {
<div className='dt-row'>
<span className='dtc f7 charcoal tr'>{t('app:terms.in').toLowerCase()}:</span>
<span className='f4 ml1 charcoal-muted'>{bw.in[0]}</span>
<span className='f7 charcoal-muted'>{bw.in[1]}/s</span>
<span className='f7 charcoal-muted'>{bw.in[1]}ps</span>
</div>
<div className='dt-row'>
<span className='dtc f7 charcoal tr'>{t('app:terms.out').toLowerCase()}:</span>
<span className='f4 ml1 charcoal-muted'>{bw.out[0]}</span>
<span className='f7 charcoal-muted'>{bw.out[1]}/s</span>
<span className='f7 charcoal-muted'>{bw.out[1]}ps</span>
</div>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/status/PeerBandwidthTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import React, { Component } from 'react'
import { connect } from 'redux-bundler-react'
import { withTranslation } from 'react-i18next'
import PropTypes from 'prop-types'
import filesize from 'filesize'
import { humanSize } from '../lib/files'
import CountryFlag from 'react-country-flag'
import Box from '../components/box/Box'
import { Title } from './Commons'
import ComponentLoader from '../loader/ComponentLoader.js'

const isWindows = window.navigator.appVersion.indexOf('Win') !== -1
const humansize = filesize.partial({ round: 0 })
const humansize = s => humanSize(s, { round: 0 })

export class PeerBandwidthTable extends Component {
static propTypes = {
Expand Down
6 changes: 5 additions & 1 deletion src/status/Speedometer.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ function Speedometer ({ total = 100, title, filled = 0, noSpeed = false, color =
}
}

// network bandwidth units in base-10 bits (Mbps)
// to align with what ISP usually shows on invoice
const data = filesize(filled, {
standard: 'jedec',
base: 10,
output: 'array',
round: 0,
bits: !noSpeed
Expand All @@ -43,7 +47,7 @@ function Speedometer ({ total = 100, title, filled = 0, noSpeed = false, color =
</div>

<div className='absolute' style={{ top: '60%', left: '50%', transform: 'translate(-50%, -50%)' }} >
<span className='f3'>{data[0]}</span><span className='ml1 f7'>{data[1]}{ noSpeed ? '' : '/s' }</span>
<span className='f3'>{data[0]}</span><span className='ml1 f7'>{data[1]}{ noSpeed ? '' : 'ps' }</span>
<span className='db f7 fw5'>{title}</span>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/status/StatusConnected.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from 'react'
import { withTranslation, Trans } from 'react-i18next'
import { connect } from 'redux-bundler-react'
import filesize from 'filesize'
import { humanSize } from '../lib/files'

export const StatusConnected = ({ t, peersCount, repoSize }) => {
const humanRepoSize = filesize(repoSize || 0, { round: 1 })
const humanRepoSize = humanSize(repoSize || 0)
return (
<header>
<h1 className='montserrat fw2 f3 charcoal ma0 pt0 pb2'>
Expand Down
8 changes: 6 additions & 2 deletions test/e2e/files.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,13 @@ describe('Files screen', () => {
await expect(page).toMatch(result1.cid.toString())
await expect(page).toMatch(result2.cid.toString())

// expect human readable sizes
// expect human readable sizes in format from ./src/lib/files.js#humanSize
// → this ensures metadata was correctly read for each item in the MFS
const human = (b) => (b ? filesize(b, { round: 0 }) : '-')
const human = (b) => (b ? filesize(b, {
standard: 'iec',
base: 2,
round: b >= 1073741824 ? 1 : 0
}) : '-')
for await (const file of ipfs.files.ls('/')) {
await expect(page).toMatch(human(file.size))
}
Expand Down

0 comments on commit 1d99482

Please sign in to comment.