Use kB and avoid unit conversion for tables

This is to keep units from varying within the same context. This
change includes the perf panel 3P table, network & memory panel tables

Bug: 398040368
Change-Id: Ib170f2f9a1a0126c8d190698a654d84f23e0843d
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6300607
Reviewed-by: Paul Irish <[email protected]>
Reviewed-by: Connor Clark <[email protected]>
Reviewed-by: Danil Somsikov <[email protected]>
Commit-Queue: Jack Franklin <[email protected]>
diff --git a/front_end/core/i18n/ByteUtilities.test.ts b/front_end/core/i18n/ByteUtilities.test.ts
index c0a9db4..83326aa 100644
--- a/front_end/core/i18n/ByteUtilities.test.ts
+++ b/front_end/core/i18n/ByteUtilities.test.ts
@@ -31,4 +31,29 @@
       assert.deepEqual(i18n.ByteUtilities.bytesToString(twoHundredAndTenMegabytes), '210\xA0MB');
     });
   });
+  describe('formatBytesToKb', () => {
+    it('formats for < 1000 bytes', () => {
+      // The formatter rounds up from 0.05 -> 0.1.
+      assert.deepEqual(i18n.ByteUtilities.formatBytesToKb(50), '0.1\xA0kB');
+    });
+
+    it('formats for < 100 kilobytes', () => {
+      assert.deepEqual(i18n.ByteUtilities.formatBytesToKb(5 * 1000), '5.0\xA0kB');
+    });
+
+    it('formats for < 1000 kilobytes', () => {
+      assert.deepEqual(i18n.ByteUtilities.formatBytesToKb(500 * 1000), '500\xA0kB');
+    });
+
+    it('formats for < 100 megabytes', () => {
+      const oneAndAHalfMegabytes = 1500 * 1000;
+      assert.deepEqual(i18n.ByteUtilities.formatBytesToKb(oneAndAHalfMegabytes), '1,500\xA0kB');
+    });
+
+    it('formats for > 100 megabytes', () => {
+      const oneMegabyte = 1000 * 1000;
+      const twoHundredAndTenMegabytes = oneMegabyte * 210;
+      assert.deepEqual(i18n.ByteUtilities.formatBytesToKb(twoHundredAndTenMegabytes), '210,000\xA0kB');
+    });
+  });
 });
diff --git a/front_end/core/i18n/ByteUtilities.ts b/front_end/core/i18n/ByteUtilities.ts
index 7a79200..696efc6 100644
--- a/front_end/core/i18n/ByteUtilities.ts
+++ b/front_end/core/i18n/ByteUtilities.ts
@@ -44,6 +44,10 @@
   maximumFractionDigits: 0,
 });
 
+/**
+ * Returns string for bytes with legible units.
+ * If necessary, can convert bytes to Kb or MB.
+ */
 export const bytesToString = (bytes: number): string => {
   if (bytes < 1000) {
     return narrowBytes.format(bytes);
@@ -63,3 +67,16 @@
   }
   return narrowMegabytesInteger.format(megabytes);
 };
+
+/**
+ * Returns a string for bytes converted to Kb.
+ * This is currently used on tables/rows to maintain consistency
+ * and avoid varying units.
+ */
+export const formatBytesToKb = (bytes: number): string => {
+  const kilobytes = bytes / 1000;
+  if (kilobytes < 100) {
+    return narrowKilobytesDecimal.format(kilobytes);
+  }
+  return narrowKilobytesInteger.format(kilobytes);
+};
diff --git a/front_end/panels/network/NetworkDataGridNode.test.ts b/front_end/panels/network/NetworkDataGridNode.test.ts
index 4906597..e931abe 100644
--- a/front_end/panels/network/NetworkDataGridNode.test.ts
+++ b/front_end/panels/network/NetworkDataGridNode.test.ts
@@ -473,9 +473,9 @@
         {} as Network.NetworkDataGridNode.NetworkLogViewInterface, request);
     const el = document.createElement('div');
     networkRequestNode.renderCell(el, 'size');
-    assert.strictEqual(el.innerText, '(ServiceWorker router)4\xa0B');
+    assert.strictEqual(el.innerText, '(ServiceWorker router)0.0\xa0kB');
     const tooltip = el.getAttribute('title')!;
-    const expected = 'Matched to ServiceWorker router#1, 2\xa0B transferred over network, resource size: 4\xa0B';
+    const expected = 'Matched to ServiceWorker router#1, 0.0\xa0kB transferred over network, resource size: 0.0\xa0kB';
     assert.strictEqual(tooltip, expected);
   });
 
diff --git a/front_end/panels/network/NetworkDataGridNode.ts b/front_end/panels/network/NetworkDataGridNode.ts
index 5634797..8dd6413 100644
--- a/front_end/panels/network/NetworkDataGridNode.ts
+++ b/front_end/panels/network/NetworkDataGridNode.ts
@@ -1392,7 +1392,7 @@
   }
 
   private renderSizeCell(cell: HTMLElement): void {
-    const resourceSize = i18n.ByteUtilities.bytesToString(this.requestInternal.resourceSize);
+    const resourceSize = i18n.ByteUtilities.formatBytesToKb(this.requestInternal.resourceSize);
 
     if (this.requestInternal.cachedInMemory()) {
       UI.UIUtils.createTextChild(cell, i18nString(UIStrings.memoryCache));
@@ -1405,7 +1405,7 @@
       UI.UIUtils.createTextChild(cell, i18n.i18n.lockedString('(ServiceWorker router)'));
       let tooltipText;
       if (serviceWorkerRouterInfo.matchedSourceType === Protocol.Network.ServiceWorkerRouterSource.Network) {
-        const transferSize = i18n.ByteUtilities.bytesToString(this.requestInternal.transferSize);
+        const transferSize = i18n.ByteUtilities.formatBytesToKb(this.requestInternal.transferSize);
         tooltipText = i18nString(
             UIStrings.matchedToServiceWorkerRouterWithNetworkSource,
             {PH1: ruleIdMatched, PH2: transferSize, PH3: resourceSize});
@@ -1435,7 +1435,7 @@
       UI.Tooltip.Tooltip.install(cell, i18nString(UIStrings.servedFromDiskCacheResourceSizeS, {PH1: resourceSize}));
       cell.classList.add('network-dim-cell');
     } else {
-      const transferSize = i18n.ByteUtilities.bytesToString(this.requestInternal.transferSize);
+      const transferSize = i18n.ByteUtilities.formatBytesToKb(this.requestInternal.transferSize);
       UI.UIUtils.createTextChild(cell, transferSize);
       UI.Tooltip.Tooltip.install(cell, `${transferSize} transferred over network, resource size: ${resourceSize}`);
     }
diff --git a/front_end/panels/network/NetworkLogView.ts b/front_end/panels/network/NetworkLogView.ts
index f02c996..37737ce 100644
--- a/front_end/panels/network/NetworkLogView.ts
+++ b/front_end/panels/network/NetworkLogView.ts
@@ -1288,15 +1288,15 @@
       this.summaryToolbarInternal.appendSeparator();
       appendChunk(
           i18nString(UIStrings.sSTransferred, {
-            PH1: i18n.ByteUtilities.bytesToString(selectedTransferSize),
-            PH2: i18n.ByteUtilities.bytesToString(transferSize),
+            PH1: i18n.ByteUtilities.formatBytesToKb(selectedTransferSize),
+            PH2: i18n.ByteUtilities.formatBytesToKb(transferSize),
           }),
           i18nString(UIStrings.sBSBTransferredOverNetwork, {PH1: selectedTransferSize, PH2: transferSize}));
       this.summaryToolbarInternal.appendSeparator();
       appendChunk(
           i18nString(UIStrings.sSResources, {
-            PH1: i18n.ByteUtilities.bytesToString(selectedResourceSize),
-            PH2: i18n.ByteUtilities.bytesToString(resourceSize),
+            PH1: i18n.ByteUtilities.formatBytesToKb(selectedResourceSize),
+            PH2: i18n.ByteUtilities.formatBytesToKb(resourceSize),
           }),
           i18nString(UIStrings.sBSBResourcesLoadedByThePage, {PH1: selectedResourceSize, PH2: resourceSize}));
     } else {
diff --git a/front_end/panels/profiler/HeapSnapshotGridNodes.ts b/front_end/panels/profiler/HeapSnapshotGridNodes.ts
index a6e03d3..5e220b0 100644
--- a/front_end/panels/profiler/HeapSnapshotGridNodes.ts
+++ b/front_end/panels/profiler/HeapSnapshotGridNodes.ts
@@ -581,8 +581,8 @@
 
     this.data = {
       distance: this.toUIDistance(this.distance),
-      shallowSize: i18n.ByteUtilities.bytesToString(this.shallowSize),
-      retainedSize: i18n.ByteUtilities.bytesToString(this.retainedSize),
+      shallowSize: i18n.ByteUtilities.formatBytesToKb(this.shallowSize),
+      retainedSize: i18n.ByteUtilities.formatBytesToKb(this.retainedSize),
       'shallowSize-percent': this.toPercentString(shallowSizePercent),
       'retainedSize-percent': this.toPercentString(retainedSizePercent),
     };
@@ -1031,10 +1031,10 @@
       data['addedCount'] = '';
       data['addedSize'] = '';
       data['removedCount'] = '\u2022';
-      data['removedSize'] = i18n.ByteUtilities.bytesToString(this.shallowSize || 0);
+      data['removedSize'] = i18n.ByteUtilities.formatBytesToKb(this.shallowSize || 0);
     } else {
       data['addedCount'] = '\u2022';
-      data['addedSize'] = i18n.ByteUtilities.bytesToString(this.shallowSize || 0);
+      data['addedSize'] = i18n.ByteUtilities.formatBytesToKb(this.shallowSize || 0);
       data['removedCount'] = '';
       data['removedSize'] = '';
     }
@@ -1128,8 +1128,8 @@
       object: this.nameInternal,
       count: Platform.NumberUtilities.withThousandsSeparator(this.count),
       distance: this.toUIDistance(this.distance),
-      shallowSize: i18n.ByteUtilities.bytesToString(this.shallowSize),
-      retainedSize: i18n.ByteUtilities.bytesToString(this.retainedSize),
+      shallowSize: i18n.ByteUtilities.formatBytesToKb(this.shallowSize),
+      retainedSize: i18n.ByteUtilities.formatBytesToKb(this.retainedSize),
       'shallowSize-percent': this.toPercentString(shallowSizePercent),
       'retainedSize-percent': this.toPercentString(retainedSizePercent),
     };
diff --git a/front_end/panels/timeline/TimelineTreeView.ts b/front_end/panels/timeline/TimelineTreeView.ts
index 45c37ac..6cff645 100644
--- a/front_end/panels/timeline/TimelineTreeView.ts
+++ b/front_end/panels/timeline/TimelineTreeView.ts
@@ -841,9 +841,9 @@
       textDiv = cell.createChild('div');
       textDiv.createChild('span').textContent = i18n.TimeUtilities.preciseMillisToString(value, 1);
     } else {
-      cell.setAttribute('title', i18n.ByteUtilities.bytesToString(value));
+      cell.setAttribute('title', i18n.ByteUtilities.formatBytesToKb(value));
       textDiv = cell.createChild('div');
-      textDiv.createChild('span').textContent = i18n.ByteUtilities.bytesToString(value);
+      textDiv.createChild('span').textContent = i18n.ByteUtilities.formatBytesToKb(value);
     }
 
     if (showPercents && this.treeView.exposePercentages()) {
diff --git a/front_end/panels/timeline/components/insights/ThirdParties.ts b/front_end/panels/timeline/components/insights/ThirdParties.ts
index fe96549..aa521b5 100644
--- a/front_end/panels/timeline/components/insights/ThirdParties.ts
+++ b/front_end/panels/timeline/components/insights/ThirdParties.ts
@@ -71,14 +71,14 @@
 
   #transferSizeAggregator: RowLimitAggregator<Trace.Extras.ThirdParties.Summary> = {
     mapToRow: summary => ({
-      values: [summary.entity.name, i18n.ByteUtilities.bytesToString(summary.transferSize)],
+      values: [summary.entity.name, i18n.ByteUtilities.formatBytesToKb(summary.transferSize)],
       overlays: this.#createOverlaysForSummary(summary),
     }),
     createAggregatedTableRow:
         remaining => {
           const totalBytes = remaining.reduce((acc, summary) => acc + summary.transferSize, 0);
           return {
-            values: [renderOthersLabel(remaining.length), i18n.ByteUtilities.bytesToString(totalBytes)],
+            values: [renderOthersLabel(remaining.length), i18n.ByteUtilities.formatBytesToKb(totalBytes)],
             overlays: remaining.flatMap(summary => this.#createOverlaysForSummary(summary) ?? []),
           };
         },