From b419fbf994e5deb687ad4714850692df4269439e Mon Sep 17 00:00:00 2001 From: Cody Ward Date: Mon, 15 Jun 2026 17:16:53 -0600 Subject: [PATCH 1/7] Fix text wrapping and column sizes on the grouped statistic view --- webview-ui/src/diagnostics_panel/App.css | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/webview-ui/src/diagnostics_panel/App.css b/webview-ui/src/diagnostics_panel/App.css index 9954cfd..5a23af3 100644 --- a/webview-ui/src/diagnostics_panel/App.css +++ b/webview-ui/src/diagnostics_panel/App.css @@ -439,6 +439,12 @@ main { padding: 6px 4px !important; } +.minecraft-grouped-statistic-table-grid-numeric { + text-align: right !important; + white-space: nowrap; + width: 120px; +} + .minecraft-grouped-statistic-table-grid-sparkline { width: 240px; min-width: 240px; @@ -470,13 +476,19 @@ main { display: inline-block; margin-right: 0; font-weight: 600; - white-space: nowrap; + white-space: normal; + overflow-wrap: anywhere; + max-width: 100%; + vertical-align: middle; } .minecraft-grouped-statistic-group-meta { display: block; margin-left: 0; color: var(--vscode-descriptionForeground); + white-space: normal; + overflow-wrap: anywhere; + max-width: 100%; } .minecraft-grouped-statistic-toggle { @@ -493,6 +505,11 @@ main { .minecraft-grouped-statistic-child-key { display: inline-block; padding-left: 18px; + white-space: normal; + overflow: hidden; + overflow-wrap: anywhere; + max-width: 100%; + vertical-align: middle; } .minecraft-grouped-statistic-row-pinned { From 1b556d79e7b4acf1cd93bc332066545a43e252d7 Mon Sep 17 00:00:00 2001 From: Cody Ward Date: Mon, 15 Jun 2026 17:17:12 -0600 Subject: [PATCH 2/7] Add median and std deviation to the sparkline cell labels --- .../controls/SparklineCell.tsx | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/webview-ui/src/diagnostics_panel/controls/SparklineCell.tsx b/webview-ui/src/diagnostics_panel/controls/SparklineCell.tsx index bbe2676..a299874 100644 --- a/webview-ui/src/diagnostics_panel/controls/SparklineCell.tsx +++ b/webview-ui/src/diagnostics_panel/controls/SparklineCell.tsx @@ -13,6 +13,30 @@ function formatSparklineLabelValue(value: number, formatValue?: (value: number) return formatValue ? formatValue(value) : value.toFixed(1); } +function calculateMedian(values: number[]): number { + if (values.length === 0) { + return 0; + } + + // For median, we need to sort the values and find the middle one (or average of two middle ones) + const sorted = [...values].sort((a, b) => a - b); + const mid = Math.floor(sorted.length / 2); + return sorted.length % 2 !== 0 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2; +} + +function calculateStandardDeviation(values: number[]): number { + if (values.length === 0) { + return 0; + } + + // Calculate the mean by summing all values and dividing by the count + const mean = values.reduce((acc, v) => acc + v, 0) / values.length; + // Calculate the variance by averaging the squared differences from the mean + const variance = values.reduce((acc, v) => acc + Math.pow(v - mean, 2), 0) / values.length; + // Finally, take the square root of the variance to get the standard deviation + return Math.sqrt(variance); +} + // A simple sparkline component that renders // a basic line chart of the provided values along with min and max labels. // Implemented using a dynamic SVG polyline. @@ -30,6 +54,9 @@ export function SparklineCell({ const rawMax = Math.max(...values); const rawMin = Math.min(...values); + const median = calculateMedian(values); + const stddev = calculateStandardDeviation(values); + const max = displayedMax ?? rawMax; const min = displayedMin ?? rawMin; const range = max - min || 1; @@ -44,6 +71,8 @@ export function SparklineCell({ const maxLabel = formatSparklineLabelValue(rawMax, formatValue); const minLabel = formatSparklineLabelValue(rawMin, formatValue); + const medianLabel = formatSparklineLabelValue(median, formatValue); + const stddevLabel = formatSparklineLabelValue(stddev, formatValue); return (
@@ -67,6 +96,14 @@ export function SparklineCell({ Min {minLabel}
+
+ + Median {medianLabel} + + + Std Dev {stddevLabel} + +
); } From 8592d91dda977d389b4ca55507408cb36b79b437 Mon Sep 17 00:00:00 2001 From: Cody Ward Date: Mon, 15 Jun 2026 17:17:30 -0600 Subject: [PATCH 3/7] Add a timing label to the Trend column header --- .../MinecraftGroupedStatisticTable.tsx | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/webview-ui/src/diagnostics_panel/controls/MinecraftGroupedStatisticTable.tsx b/webview-ui/src/diagnostics_panel/controls/MinecraftGroupedStatisticTable.tsx index 8852864..fa74688 100644 --- a/webview-ui/src/diagnostics_panel/controls/MinecraftGroupedStatisticTable.tsx +++ b/webview-ui/src/diagnostics_panel/controls/MinecraftGroupedStatisticTable.tsx @@ -116,6 +116,27 @@ const SPARKLINE_BOUNDS_EXPAND_LERP = 0.35; const SPARKLINE_BOUNDS_CONTRACT_LERP = 0.12; const SPARKLINE_HISTORY_RETENTION_TICKS = 8; +const TICKS_PER_SECOND = 20; +const TICKS_PER_SPARKLINE_UPDATE = 12; // TODO I don't know if this is accurate or not, but it gives us the right values for now + +function sparklineTickRangeToSeconds(updatePoints: number): string { + const totalTicks = updatePoints * TICKS_PER_SPARKLINE_UPDATE; + const seconds = totalTicks / TICKS_PER_SECOND; + + if (seconds <= 0) { + return '0s'; + } + + if (seconds >= 60) { + const minutes = Math.floor(seconds / 60); + const remainingSeconds = Math.round(seconds % 60); + + return remainingSeconds > 0 ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`; + } + + // For short ranges, show one decimal place for precision + return seconds < 10 ? `${seconds.toFixed(1)}s` : `${Math.round(seconds)}s`; +} function getRowSparklineSeriesKey(category: string): string { return `row:${category}`; } @@ -1363,7 +1384,9 @@ const MinecraftGroupedStatisticTable = forwardRef< ))} {sparklineColumnIndex !== undefined && ( - Trend + + Trend ({sparklineTickRangeToSeconds(sparklineTickRange)}) + )} {rowAction && ( From 44987d2813bffe583dfd1cfb3caaa72dbcadee9f Mon Sep 17 00:00:00 2001 From: Cody Ward Date: Tue, 16 Jun 2026 12:17:05 -0600 Subject: [PATCH 4/7] Reduce column sizes a bit further --- webview-ui/src/diagnostics_panel/App.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webview-ui/src/diagnostics_panel/App.css b/webview-ui/src/diagnostics_panel/App.css index 5a23af3..4ca7df3 100644 --- a/webview-ui/src/diagnostics_panel/App.css +++ b/webview-ui/src/diagnostics_panel/App.css @@ -429,7 +429,7 @@ main { .minecraft-grouped-statistic-table-grid-select { text-align: center !important; - width: 72px; + width: 50px; padding: 6px 4px !important; } @@ -442,7 +442,7 @@ main { .minecraft-grouped-statistic-table-grid-numeric { text-align: right !important; white-space: nowrap; - width: 120px; + width: 10%; } .minecraft-grouped-statistic-table-grid-sparkline { From b6647bdedf027ddf50380e4ca1262f8c6997598e Mon Sep 17 00:00:00 2001 From: Cody Ward Date: Tue, 16 Jun 2026 12:17:33 -0600 Subject: [PATCH 5/7] Format the system keys to remove the index from the visuals --- .../controls/MinecraftGroupedStatisticTable.tsx | 8 ++++++-- .../prefabs/tabs/ClientEntitySystems.tsx | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/webview-ui/src/diagnostics_panel/controls/MinecraftGroupedStatisticTable.tsx b/webview-ui/src/diagnostics_panel/controls/MinecraftGroupedStatisticTable.tsx index fa74688..6684014 100644 --- a/webview-ui/src/diagnostics_panel/controls/MinecraftGroupedStatisticTable.tsx +++ b/webview-ui/src/diagnostics_panel/controls/MinecraftGroupedStatisticTable.tsx @@ -91,6 +91,7 @@ type MinecraftGroupedStatisticTableProps = { rowAction?: GroupedStatisticTableRowAction; nonConsolidatedColumnResolver?: NonConsolidatedColumnResolver; valueFormatter?: (value: string | number, columnIndex: number) => string; + keyFormatter?: (key: string) => string; prettifyNames?: boolean; selectionEnabled?: boolean; selectionHeaderLabel?: string; @@ -421,6 +422,7 @@ const MinecraftGroupedStatisticTable = forwardRef< rowAction, nonConsolidatedColumnResolver, valueFormatter, + keyFormatter, prettifyNames = false, selectionEnabled = false, selectionHeaderLabel = 'Selected', @@ -1285,7 +1287,9 @@ const MinecraftGroupedStatisticTable = forwardRef< )} - {row.category} + + {keyFormatter ? keyFormatter(row.category) : row.category} + {row.values.map((value, valueIndex) => ( @@ -1457,7 +1461,7 @@ const MinecraftGroupedStatisticTable = forwardRef< {isExpanded ? '▾' : '▸'} - {group.key} + {keyFormatter ? keyFormatter(group.key) : group.key} diff --git a/webview-ui/src/diagnostics_panel/prefabs/tabs/ClientEntitySystems.tsx b/webview-ui/src/diagnostics_panel/prefabs/tabs/ClientEntitySystems.tsx index 0fd6935..5937c1e 100644 --- a/webview-ui/src/diagnostics_panel/prefabs/tabs/ClientEntitySystems.tsx +++ b/webview-ui/src/diagnostics_panel/prefabs/tabs/ClientEntitySystems.tsx @@ -104,6 +104,10 @@ function extractEntityId(entityCategory: string): string | undefined { return match?.[1]; } +function formatStatKey(key: string): string { + return key.split('(')[0].trim(); +} + function resolveSystemCategoryGroupKey(fullName: string, systemCategoryLegendMap: Map): string { // Example fullName: "System Name (4)" // Take anything before the first '(' @@ -539,6 +543,7 @@ const StatsTab: TabPrefab = { sparklineColumnIndex={0} sparklineTickRange={100} sparklineValueFormatter={value => formatTimingValue(value, systemTimingUnit)} + keyFormatter={formatStatKey} valueFormatter={(value, columnIndex) => { // Timing column if (columnIndex === 0) { From 5e04d601b77eb0174bb8faf4154df35ab81ef6ae Mon Sep 17 00:00:00 2001 From: Cody Ward Date: Tue, 16 Jun 2026 12:18:44 -0600 Subject: [PATCH 6/7] =?UTF-8?q?Reduce=20the=20size=20of=20the=20numeric=20?= =?UTF-8?q?column=20headers=20and=20swap=20from=20a=20u=20to=20the=20mew?= =?UTF-8?q?=20(=CE=BC)=20for=20microsecond=20displays?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../prefabs/tabs/ClientEntitySystems.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/webview-ui/src/diagnostics_panel/prefabs/tabs/ClientEntitySystems.tsx b/webview-ui/src/diagnostics_panel/prefabs/tabs/ClientEntitySystems.tsx index 5937c1e..4969a69 100644 --- a/webview-ui/src/diagnostics_panel/prefabs/tabs/ClientEntitySystems.tsx +++ b/webview-ui/src/diagnostics_panel/prefabs/tabs/ClientEntitySystems.tsx @@ -45,14 +45,14 @@ function ceilToDecimalPlace(value: number, decimalPlaces: number): string { function getTimingColumnLabel(unit: TimingUnit): string { if (unit === 'ms') { - return 'Time In Milliseconds'; + return 'Time (ms)'; } if (unit === 'us') { - return 'Time In Microseconds'; + return 'Time (µs)'; } - return 'Time In Nanoseconds'; + return 'Time (ns)'; } function formatTimingValue(value: number, unit: TimingUnit): string { @@ -65,7 +65,7 @@ function formatTimingValue(value: number, unit: TimingUnit): string { } if (unit === 'us') { - return `${ceilToDecimalPlace(value / 1_000, 1)} us`; + return `${ceilToDecimalPlace(value / 1_000, 1)} µs`; } return `${value} ns`; @@ -245,7 +245,7 @@ const StatsTab: TabPrefab = { [], ); - const entityValueLabels = [getTimingColumnLabel(entityTimingUnit), 'Percent Of Total']; + const entityValueLabels = [getTimingColumnLabel(entityTimingUnit), '% Of Total']; const filteredEntityLabel = (() => { if (selectionMode === 'single-entity') { @@ -506,7 +506,7 @@ const StatsTab: TabPrefab = { title="System Timings" showTitle={false} keyLabel="System" - valueLabels={[getTimingColumnLabel(systemTimingUnit), 'Percent Of Total']} + valueLabels={[getTimingColumnLabel(systemTimingUnit), '% Of Total']} displayMode={ systemViewMode === 'grouped' ? MinecraftGroupedStatisticTableDisplayMode.Grouped From 05d19496865049d9e6aed093013adac3faea032d Mon Sep 17 00:00:00 2001 From: Cody Ward Date: Mon, 22 Jun 2026 14:41:02 -0600 Subject: [PATCH 7/7] merge fix --- .../prefabs/tabs/ClientEntitySystems.tsx | 59 +------------------ 1 file changed, 2 insertions(+), 57 deletions(-) diff --git a/webview-ui/src/diagnostics_panel/prefabs/tabs/ClientEntitySystems.tsx b/webview-ui/src/diagnostics_panel/prefabs/tabs/ClientEntitySystems.tsx index bbd8dd9..054abce 100644 --- a/webview-ui/src/diagnostics_panel/prefabs/tabs/ClientEntitySystems.tsx +++ b/webview-ui/src/diagnostics_panel/prefabs/tabs/ClientEntitySystems.tsx @@ -608,7 +608,7 @@ const StatsTab: TabPrefab = { : undefined } keyLabel="System" - valueLabels={[getTimingColumnLabel(systemTimingUnit), 'Percent Of Total']} + valueLabels={[getTimingColumnLabel(systemTimingUnit), '% Of Total']} displayMode={ systemViewMode === 'grouped' ? MinecraftGroupedStatisticTableDisplayMode.Grouped @@ -645,6 +645,7 @@ const StatsTab: TabPrefab = { sparklineColumnIndex={0} sparklineTickRange={100} sparklineValueFormatter={value => formatTimingValue(value, systemTimingUnit)} + keyFormatter={formatStatKey} valueFormatter={(value, columnIndex) => { // Timing column if (columnIndex === 0) { @@ -660,62 +661,6 @@ const StatsTab: TabPrefab = { /> - - resolveSystemCategoryGroupKey(fullName, systemCategoryLegendMap) - } - groupCountLabel="systems" - defaultCollapsed={true} - groupColumnAggregations={[ - MinecraftGroupedStatisticTableColumnAggregation.Average, - MinecraftGroupedStatisticTableColumnAggregation.Sum, - ]} - statisticDataProvider={ - new MultipleStatisticProvider({ - statisticIds: ['time_in_ns', 'percent_of_total'], - statisticParentId: new RegExp(`${selectedClient}_client_ecs_systems`), - }) - } - statisticResolver={ParentNameStatResolver( - createStatResolver({ - type: StatisticType.Absolute, - tickRange: 20 * 10, - yAxisType: YAxisType.Absolute, - valueScalar: 1, - }), - )} - defaultSortColumn="value_1" - defaultSortOrder={MinecraftGroupedStatisticTableSortOrder.Descending} - defaultSortType={MinecraftGroupedStatisticTableSortType.Numerical} - prettifyNames={false} - nonConsolidatedColumnResolver={event => resolveEcsColumn(event.id)} - sparklineColumnIndex={0} - sparklineTickRange={100} - sparklineValueFormatter={value => formatTimingValue(value, systemTimingUnit)} - keyFormatter={formatStatKey} - valueFormatter={(value, columnIndex) => { - // Timing column - if (columnIndex === 0) { - return formatTimingValue(Number(value), systemTimingUnit); - } - // Percentage column - else if (columnIndex === 1) { - return formatPercentageValue(Number(value)); - } - - return String(value); - }} - /> )}