mirror of
https://github.com/outline/outline.git
synced 2026-05-13 05:40:13 -05:00
Fix file size display to use binary units instead of decimal (#10095)
* Fix file size display to use binary units instead of decimal - Update bytesToHumanReadable function to use 1024-based units (KB, MB, GB) - This matches user expectations from operating systems like Windows - Fixes issue where 87.2MB file was displayed as 91.53MB - Update unit tests to reflect binary unit calculations - Resolves GitHub issue #10085 Co-authored-by: Tom Moor <tom@getoutline.com> * Make file size display platform-aware - Use decimal units (base 1000) on macOS to match Finder behavior - Use binary units (base 1024) on Windows to match Explorer behavior - Import isMac utility from shared/utils/browser - Update comprehensive tests for both platforms - Resolves platform-specific file size display discrepancies Co-authored-by: Tom Moor <tom@getoutline.com> --------- Co-authored-by: codegen-sh[bot] <131295404+codegen-sh[bot]@users.noreply.github.com> Co-authored-by: Tom Moor <tom@getoutline.com>
This commit is contained in:
+66
-12
@@ -1,18 +1,72 @@
|
||||
import { bytesToHumanReadable, getFileNameFromUrl } from "./files";
|
||||
import * as browser from "./browser";
|
||||
|
||||
// Mock the browser detection
|
||||
jest.mock("./browser", () => ({
|
||||
isMac: jest.fn(),
|
||||
}));
|
||||
|
||||
const mockIsMac = browser.isMac as jest.MockedFunction<typeof browser.isMac>;
|
||||
|
||||
describe("bytesToHumanReadable", () => {
|
||||
it("outputs readable string", () => {
|
||||
expect(bytesToHumanReadable(0)).toBe("0 Bytes");
|
||||
expect(bytesToHumanReadable(0.0)).toBe("0 Bytes");
|
||||
expect(bytesToHumanReadable(33)).toBe("33 Bytes");
|
||||
expect(bytesToHumanReadable(500)).toBe("500 Bytes");
|
||||
expect(bytesToHumanReadable(1000)).toBe("1 kB");
|
||||
expect(bytesToHumanReadable(15000)).toBe("15 kB");
|
||||
expect(bytesToHumanReadable(12345)).toBe("12.34 kB");
|
||||
expect(bytesToHumanReadable(123456)).toBe("123.45 kB");
|
||||
expect(bytesToHumanReadable(1234567)).toBe("1.23 MB");
|
||||
expect(bytesToHumanReadable(1234567890)).toBe("1.23 GB");
|
||||
expect(bytesToHumanReadable(undefined)).toBe("0 Bytes");
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe("on macOS (decimal units)", () => {
|
||||
beforeEach(() => {
|
||||
mockIsMac.mockReturnValue(true);
|
||||
});
|
||||
|
||||
it("outputs readable string using decimal units", () => {
|
||||
expect(bytesToHumanReadable(0)).toBe("0 Bytes");
|
||||
expect(bytesToHumanReadable(0.0)).toBe("0 Bytes");
|
||||
expect(bytesToHumanReadable(33)).toBe("33 Bytes");
|
||||
expect(bytesToHumanReadable(500)).toBe("500 Bytes");
|
||||
expect(bytesToHumanReadable(1000)).toBe("1 KB");
|
||||
expect(bytesToHumanReadable(15000)).toBe("15 KB");
|
||||
expect(bytesToHumanReadable(12345)).toBe("12.35 KB");
|
||||
expect(bytesToHumanReadable(123456)).toBe("123.46 KB");
|
||||
expect(bytesToHumanReadable(1234567)).toBe("1.23 MB");
|
||||
expect(bytesToHumanReadable(1234567890)).toBe("1.23 GB");
|
||||
expect(bytesToHumanReadable(undefined)).toBe("0 Bytes");
|
||||
});
|
||||
});
|
||||
|
||||
describe("on Windows/other platforms (binary units)", () => {
|
||||
beforeEach(() => {
|
||||
mockIsMac.mockReturnValue(false);
|
||||
});
|
||||
|
||||
it("outputs readable string using binary units", () => {
|
||||
expect(bytesToHumanReadable(0)).toBe("0 Bytes");
|
||||
expect(bytesToHumanReadable(0.0)).toBe("0 Bytes");
|
||||
expect(bytesToHumanReadable(33)).toBe("33 Bytes");
|
||||
expect(bytesToHumanReadable(500)).toBe("500 Bytes");
|
||||
expect(bytesToHumanReadable(1000)).toBe("1000 Bytes");
|
||||
expect(bytesToHumanReadable(1024)).toBe("1 KB");
|
||||
expect(bytesToHumanReadable(1536)).toBe("1.5 KB");
|
||||
expect(bytesToHumanReadable(15360)).toBe("15 KB");
|
||||
expect(bytesToHumanReadable(12345)).toBe("12.06 KB");
|
||||
expect(bytesToHumanReadable(126464)).toBe("123.5 KB");
|
||||
expect(bytesToHumanReadable(1048576)).toBe("1 MB");
|
||||
expect(bytesToHumanReadable(1073741824)).toBe("1 GB");
|
||||
expect(bytesToHumanReadable(undefined)).toBe("0 Bytes");
|
||||
});
|
||||
});
|
||||
|
||||
describe("platform-specific behavior for issue #10085", () => {
|
||||
const fileSize = 91435827; // 87.2MB in binary, ~91.44MB in decimal
|
||||
|
||||
it("displays correctly on macOS (decimal)", () => {
|
||||
mockIsMac.mockReturnValue(true);
|
||||
expect(bytesToHumanReadable(fileSize)).toBe("91.44 MB");
|
||||
});
|
||||
|
||||
it("displays correctly on Windows (binary)", () => {
|
||||
mockIsMac.mockReturnValue(false);
|
||||
expect(bytesToHumanReadable(fileSize)).toBe("87.2 MB");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+15
-8
@@ -1,5 +1,8 @@
|
||||
import { isMac } from "./browser";
|
||||
|
||||
/**
|
||||
* Converts bytes to human readable string for display
|
||||
* Uses binary units (1024-based) on Windows and decimal units (1000-based) on macOS
|
||||
*
|
||||
* @param bytes filesize in bytes
|
||||
* @returns Human readable filesize as a string
|
||||
@@ -9,19 +12,23 @@ export function bytesToHumanReadable(bytes: number | undefined) {
|
||||
return "0 Bytes";
|
||||
}
|
||||
|
||||
const out = ("0".repeat((bytes.toString().length * 2) % 3) + bytes).match(
|
||||
/.{3}/g
|
||||
);
|
||||
// Use decimal units (base 1000) on macOS, binary units (base 1024) on other platforms
|
||||
const useMacUnits = isMac();
|
||||
const base = useMacUnits ? 1000 : 1024;
|
||||
const threshold = useMacUnits ? 1000 : 1024;
|
||||
|
||||
if (!out || bytes < 1000) {
|
||||
if (bytes < threshold) {
|
||||
return bytes + " Bytes";
|
||||
}
|
||||
|
||||
const f = (out[1] ?? "").substring(0, 2);
|
||||
const units = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||
const exponent = Math.floor(Math.log(bytes) / Math.log(base));
|
||||
const value = bytes / Math.pow(base, exponent);
|
||||
|
||||
return `${Number(out[0])}${f === "00" ? "" : `.${f}`} ${
|
||||
" kMGTPEZY"[out.length]
|
||||
}B`;
|
||||
// Format to 2 decimal places and remove trailing zeros
|
||||
const formatted = parseFloat(value.toFixed(2));
|
||||
|
||||
return `${formatted} ${units[exponent]}`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user