diff --git a/packages/dashboard-v2/package.json b/packages/dashboard-v2/package.json
index 80070815..2e17c56b 100644
--- a/packages/dashboard-v2/package.json
+++ b/packages/dashboard-v2/package.json
@@ -33,7 +33,6 @@
"nanoid": "^3.3.1",
"path-browserify": "^1.0.1",
"postcss": "^8.4.6",
- "pretty-bytes": "^6.0.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-dropzone": "^12.0.4",
diff --git a/packages/dashboard-v2/src/components/CurrentPlan/CurrentPlan.js b/packages/dashboard-v2/src/components/CurrentPlan/CurrentPlan.js
index d6df8506..f9bc101a 100644
--- a/packages/dashboard-v2/src/components/CurrentPlan/CurrentPlan.js
+++ b/packages/dashboard-v2/src/components/CurrentPlan/CurrentPlan.js
@@ -1,9 +1,9 @@
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
-import prettyBytes from "pretty-bytes";
import { useUser } from "../../contexts/user";
import useActivePlan from "../../hooks/useActivePlan";
+import humanBytes from "../../lib/humanBytes";
import { ContainerLoadingIndicator } from "../LoadingIndicator";
import LatestPayment from "./LatestPayment";
@@ -33,7 +33,7 @@ const CurrentPlan = () => {
{activePlan.price === 0 && activePlan.limits && (
-
{prettyBytes(activePlan.limits.storageLimit, { binary: true })} without paying a dime! 🎉
+
{humanBytes(activePlan.limits.storageLimit)} without paying a dime! 🎉
)}
{activePlan.price !== 0 &&
(user.subscriptionCancelAtPeriodEnd ? (
diff --git a/packages/dashboard-v2/src/components/CurrentUsage/CurrentUsage.js b/packages/dashboard-v2/src/components/CurrentUsage/CurrentUsage.js
index f9dbbc36..c678585b 100644
--- a/packages/dashboard-v2/src/components/CurrentUsage/CurrentUsage.js
+++ b/packages/dashboard-v2/src/components/CurrentUsage/CurrentUsage.js
@@ -1,5 +1,4 @@
import { useEffect, useMemo, useState } from "react";
-import fileSize from "pretty-bytes";
import { Link } from "gatsby";
import cn from "classnames";
import useSWR from "swr";
@@ -10,6 +9,7 @@ import { ContainerLoadingIndicator } from "../LoadingIndicator";
import { GraphBar } from "./GraphBar";
import { UsageGraph } from "./UsageGraph";
+import humanBytes from "../../lib/humanBytes";
const useUsageData = () => {
const { user } = useUser();
@@ -45,7 +45,7 @@ const useUsageData = () => {
};
const size = (bytes) => {
- const text = fileSize(bytes ?? 0, { maximumFractionDigits: 0, binary: true });
+ const text = humanBytes(bytes ?? 0, { precision: 0 });
const [value, unit] = text.split(" ");
return {
diff --git a/packages/dashboard-v2/src/components/FileList/useFormattedFilesData.js b/packages/dashboard-v2/src/components/FileList/useFormattedFilesData.js
index 87bf1af6..10639458 100644
--- a/packages/dashboard-v2/src/components/FileList/useFormattedFilesData.js
+++ b/packages/dashboard-v2/src/components/FileList/useFormattedFilesData.js
@@ -1,7 +1,7 @@
import { useMemo } from "react";
-import prettyBytes from "pretty-bytes";
import dayjs from "dayjs";
import { DATE_FORMAT } from "../../lib/config";
+import humanBytes from "../../lib/humanBytes";
const parseFileName = (fileName) => {
const lastDotIndex = Math.max(0, fileName.lastIndexOf(".")) || Infinity;
@@ -16,7 +16,7 @@ const formatItem = ({ size, name: rawFileName, uploadedOn, downloadedOn, ...rest
return {
...rest,
date,
- size: prettyBytes(size),
+ size: humanBytes(size, { precision: 2 }),
type,
name,
};
diff --git a/packages/dashboard-v2/src/components/Uploader/UploaderItem.js b/packages/dashboard-v2/src/components/Uploader/UploaderItem.js
index 46653877..7e19051b 100644
--- a/packages/dashboard-v2/src/components/Uploader/UploaderItem.js
+++ b/packages/dashboard-v2/src/components/Uploader/UploaderItem.js
@@ -1,6 +1,5 @@
import * as React from "react";
import cn from "classnames";
-import bytes from "pretty-bytes";
import { StatusCodes } from "http-status-codes";
import copy from "copy-text-to-clipboard";
import path from "path-browserify";
@@ -9,6 +8,7 @@ import { ProgressBar } from "./ProgressBar";
import UploaderItemIcon from "./UploaderItemIcon";
import buildUploadErrorMessage from "./buildUploadErrorMessage";
import skynetClient from "../../services/skynetClient";
+import humanBytes from "../../lib/humanBytes";
const getFilePath = (file) => file.webkitRelativePath || file.path || file.name;
@@ -88,7 +88,7 @@ export default function UploaderItem({ onUploadStateChange, upload }) {
{upload.status === "uploading" && (
- Uploading {bytes(upload.file.size * upload.progress)} of {bytes(upload.file.size)}
+ Uploading {humanBytes(upload.file.size * upload.progress)} of {humanBytes(upload.file.size)}
)}
{upload.status === "enqueued" &&
Upload in queue, please wait}
diff --git a/packages/dashboard-v2/src/components/Uploader/buildUploadErrorMessage.js b/packages/dashboard-v2/src/components/Uploader/buildUploadErrorMessage.js
index c41cd717..11cfed4b 100644
--- a/packages/dashboard-v2/src/components/Uploader/buildUploadErrorMessage.js
+++ b/packages/dashboard-v2/src/components/Uploader/buildUploadErrorMessage.js
@@ -1,5 +1,5 @@
import { getReasonPhrase } from "http-status-codes";
-import bytes from "pretty-bytes";
+import humanBytes from "../../lib/humanBytes";
export default function buildUploadErrorMessage(error) {
// The request was made and the server responded with a status code that falls out of the range of 2xx
@@ -29,7 +29,7 @@ export default function buildUploadErrorMessage(error) {
const matchTusMaxFileSizeError = error.message.match(/upload exceeds maximum size: \d+ > (?
\d+)/);
if (matchTusMaxFileSizeError) {
- return `File exceeds size limit of ${bytes(parseInt(matchTusMaxFileSizeError.groups.limit, 10))}`;
+ return `File exceeds size limit of ${humanBytes(matchTusMaxFileSizeError.groups.limit, { precision: 0 })}`;
}
// TODO: We should add a note "our team has been notified" and have some kind of notification with this error.
diff --git a/packages/dashboard-v2/src/lib/humanBytes.js b/packages/dashboard-v2/src/lib/humanBytes.js
new file mode 100644
index 00000000..ac1fbfa2
--- /dev/null
+++ b/packages/dashboard-v2/src/lib/humanBytes.js
@@ -0,0 +1,21 @@
+const UNITS = ["B", "kB", "MB", "GB", "TB", "PB", "EB"];
+const BASE = 1024;
+const DEFAULT_OPTIONS = { precision: 1 };
+
+export default function humanBytes(bytes, { precision } = DEFAULT_OPTIONS) {
+ if (!Number.isFinite(bytes) || bytes < 0) {
+ throw new TypeError(`Expected a finite, positive number. Received: ${typeof bytes}: ${bytes}`);
+ }
+
+ let value = bytes;
+ let unitIndex = 0;
+
+ while (value >= BASE) {
+ value /= BASE;
+ unitIndex += 1;
+ }
+
+ const localizedValue = value.toLocaleString(undefined, { maximumFractionDigits: precision });
+
+ return `${localizedValue} ${UNITS[unitIndex]}`;
+}
diff --git a/packages/dashboard-v2/src/pages/auth/registration.js b/packages/dashboard-v2/src/pages/auth/registration.js
index 5764ad6a..899abe50 100644
--- a/packages/dashboard-v2/src/pages/auth/registration.js
+++ b/packages/dashboard-v2/src/pages/auth/registration.js
@@ -1,5 +1,4 @@
import { useCallback, useState } from "react";
-import bytes from "pretty-bytes";
import AuthLayout from "../../layouts/AuthLayout";
@@ -10,12 +9,13 @@ import { usePortalSettings } from "../../contexts/portal-settings";
import { PlansProvider, usePlans } from "../../contexts/plans";
import { Metadata } from "../../components/Metadata";
import { useUser } from "../../contexts/user";
+import humanBytes from "../../lib/humanBytes";
const FreePortalHeader = () => {
const { plans } = usePlans();
const freePlan = plans.find(({ price }) => price === 0);
- const freeStorage = freePlan?.limits ? bytes(freePlan.limits?.storageLimit, { binary: true }) : null;
+ const freeStorage = freePlan?.limits ? humanBytes(freePlan.limits?.storageLimit, { binary: true }) : null;
return (
diff --git a/packages/dashboard-v2/src/pages/upgrade.js b/packages/dashboard-v2/src/pages/upgrade.js
index 9f69487e..f3a531da 100644
--- a/packages/dashboard-v2/src/pages/upgrade.js
+++ b/packages/dashboard-v2/src/pages/upgrade.js
@@ -1,5 +1,4 @@
import * as React from "react";
-import bytes from "pretty-bytes";
import styled from "styled-components";
import { useUser } from "../contexts/user";
@@ -14,6 +13,7 @@ import { usePortalSettings } from "../contexts/portal-settings";
import { Alert } from "../components/Alert";
import HighlightedLink from "../components/HighlightedLink";
import { Metadata } from "../components/Metadata";
+import humanBytes from "../lib/humanBytes";
const PAID_PORTAL_BREAKPOINTS = [
{
@@ -67,9 +67,9 @@ const Price = ({ price }) => (
);
-const bandwidth = (value) => `${bytes(value, { bits: true })}/s`;
+const bandwidth = (value) => `${humanBytes(value, { bits: true })}/s`;
-const storage = (value) => bytes(value, { binary: true });
+const storage = (value) => humanBytes(value, { binary: true });
const localizedNumber = (value) => value.toLocaleString();
diff --git a/packages/dashboard-v2/yarn.lock b/packages/dashboard-v2/yarn.lock
index 0ac39653..bf3123ca 100644
--- a/packages/dashboard-v2/yarn.lock
+++ b/packages/dashboard-v2/yarn.lock
@@ -12696,11 +12696,6 @@ pretty-bytes@^5.4.1:
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==
-pretty-bytes@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-6.0.0.tgz#928be2ad1f51a2e336add8ba764739f9776a8140"
- integrity sha512-6UqkYefdogmzqAZWzJ7laYeJnaXDy2/J+ZqiiMtS7t7OfpXWTlaeGMwX8U6EFvPV/YWWEKRkS8hKS4k60WHTOg==
-
pretty-error@^2.1.1, pretty-error@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6"