diff --git a/.vscode/launch.json b/.vscode/launch.json index 06213438..eb724931 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,6 +5,7 @@ { "version": "0.2.0", "configurations": [ + { "name": "Run Extension", "type": "extensionHost", @@ -28,7 +29,8 @@ "outFiles": [ "${workspaceFolder}/out/test/**/*.js" ], - "preLaunchTask": "${defaultBuildTask}" + "preLaunchTask": "${defaultBuildTask}", + "debugWebviews": true } ] } diff --git a/src/panels/minecraft-diagnostics.ts b/src/panels/minecraft-diagnostics.ts index 07667059..6fd43f7f 100644 --- a/src/panels/minecraft-diagnostics.ts +++ b/src/panels/minecraft-diagnostics.ts @@ -5,7 +5,7 @@ import { EventEmitter } from 'stream'; import { getUri } from '../utilities/getUri'; import { getNonce } from '../utilities/getNonce'; import { DebuggerRequestHandler } from '../requests/debugger-request-handler'; -import { StatData, StatsListener, StatsProvider } from '../stats/stats-provider'; +import { DiagnosticsTabDescriptor, StatData, StatsListener, StatsProvider } from '../stats/stats-provider'; export class MinecraftDiagnosticsPanel { private static activeDiagnosticsPanels: MinecraftDiagnosticsPanel[] = []; @@ -116,6 +116,13 @@ export class MinecraftDiagnosticsPanel { onNotification: (message: string) => { window.showInformationMessage(message); }, + onSchemaReceived: (schema: DiagnosticsTabDescriptor[]) => { + const message = { + type: 'diagnostics-schema', + schema: schema, + }; + this._panel.webview.postMessage(message); + } }; this._statsTracker.addStatListener(this._statsCallback); diff --git a/src/protocol-events.ts b/src/protocol-events.ts index 8ca3fefa..8a1d1133 100644 --- a/src/protocol-events.ts +++ b/src/protocol-events.ts @@ -2,7 +2,7 @@ import { LogLevel } from '@vscode/debugadapter/lib/logger'; import { DebugProtocol } from '@vscode/debugprotocol'; -import { StatMessageModel } from './stats/stats-provider'; +import { DiagnosticsTabDescriptor, StatMessageModel } from './stats/stats-provider'; // protocol version history // 1 - initial version @@ -13,6 +13,7 @@ import { StatMessageModel } from './stats/stats-provider'; // 6 - breakpoints as request, MC can reject // 7 - support for debugger requests, MC can reject or respond with args // 8 - New serialization tech (use Cereal) +// 9 - Added support for MC C++/native driven stat descriptors/schemas for UI display export enum ProtocolVersion { _Unknown = 0, @@ -24,9 +25,10 @@ export enum ProtocolVersion { SupportBreakpointsAsRequest = 6, SupportDebuggerRequests = 7, SupportCerealSerialization = 8, + SupportNativeDescriptors = 9, } -export const DEBUGGER_PROTOCOL_VERSION = ProtocolVersion.SupportCerealSerialization; +export const DEBUGGER_PROTOCOL_VERSION = ProtocolVersion.SupportNativeDescriptors; // ------------------------------------------------------------------------- // Interfaces for event message payloads (received from the debugee) @@ -38,9 +40,9 @@ export enum IncomingEventType { Notification = 'NotificationEvent', Protocol = 'ProtocolEvent', Stat2 = 'StatEvent2', - Schema = 'SchemaEvent', ProfilerCapture = 'ProfilerCapture', DebuggeeResponse = 'debuggee-response', + DiagnosticsDescriptor = 'SchemaEvent', } export interface PluginDetails { @@ -97,6 +99,11 @@ export type StatEventMessage = StatMessageModel & { type: IncomingEventType.Stat2; }; +export interface DiagnosticsDescriptorMessage { + type: IncomingEventType.DiagnosticsDescriptor; + descriptors: DiagnosticsTabDescriptor[]; +} + export type IncomingDebuggeeMessage = | ProtocolCapabilities | ProfilerCapture @@ -105,7 +112,8 @@ export type IncomingDebuggeeMessage = | PrintEventMessage | NotificationEventMessage | StatEventMessage - | DebuggeeResponseEnvelope; + | DebuggeeResponseEnvelope + | DiagnosticsDescriptorMessage; // ------------------------------------------------------------------------- @@ -252,6 +260,7 @@ export class DebuggeeEventRegistry { handler(eventMessage); return true; } + console.warn(`No handler found for incoming event type: ${eventMessage.type}`); return false; } } diff --git a/src/session.ts b/src/session.ts index dcc56834..9812c0f2 100644 --- a/src/session.ts +++ b/src/session.ts @@ -58,7 +58,8 @@ import { StoppedEventMessage, ThreadEventMessage, DebuggeeResponseEnvelope, - RequestLegacyMessage + RequestLegacyMessage, + DiagnosticsDescriptorMessage, } from './protocol-events'; import { SourceMaps } from './source-maps'; import { StatMessageModel, StatsProvider } from './stats/stats-provider'; @@ -202,6 +203,9 @@ export class Session extends DebugSession implements IDebuggeeMessageSender { this._eventRegistry.register(IncomingEventType.ProfilerCapture, (msg: ProfilerCapture) => { this.handleProfilerCapture(msg); }); + this._eventRegistry.register(IncomingEventType.DiagnosticsDescriptor, (msg: DiagnosticsDescriptorMessage) => { + this._statsProvider.setSchema(msg.descriptors); + }); } public dispose(): void { diff --git a/src/stats/stats-provider.ts b/src/stats/stats-provider.ts index 48c53f80..613f862d 100644 --- a/src/stats/stats-provider.ts +++ b/src/stats/stats-provider.ts @@ -26,16 +26,45 @@ export interface StatMessageModel { stats: StatDataModel[]; } +export type DiagnosticsDataSource = 'server' | 'client' | 'server_script'; + +export type DiagnosticsDisplayType = + | 'line_chart' + | 'stacked_line_chart' + | 'stacked_bar_chart' + | 'table' + | 'multi_column_table' + | 'dynamic_properties_table'; + +// Mirrors ScriptDiagnosticsDescriptor from C++. Sent once on connect via SchemaEvent. +export interface DiagnosticsTabDescriptor { + name: string; + stat_group_id: string; + data_source: DiagnosticsDataSource; + display_type: DiagnosticsDisplayType; + title?: string; + y_label?: string; + tick_range?: number; + value_scalar?: number; + target_value?: number; + key_label?: string; + value_labels?: string[]; + statistic_id?: string; + statistic_ids?: string[]; +} + export interface StatsListener { onStatUpdated?: (stat: StatData) => void; onSpeedUpdated?: (speed: number) => void; onPauseUpdated?: (paused: boolean) => void; onStopped?: () => void; onNotification?: (message: string) => void; + onSchemaReceived?: (schema: DiagnosticsTabDescriptor[]) => void; } export class StatsProvider { protected _statListeners: StatsListener[]; + private _cachedSchema: DiagnosticsTabDescriptor[] | undefined; constructor(public readonly name: string, public readonly uniqueId: string) { this._statListeners = []; @@ -47,6 +76,13 @@ export class StatsProvider { } } + public setSchema(schema: DiagnosticsTabDescriptor[]): void { + this._cachedSchema = schema; + this._statListeners.forEach((listener: StatsListener) => { + listener.onSchemaReceived?.(schema); + }); + } + public start(): void { throw new Error('Method not implemented.'); } @@ -74,6 +110,12 @@ export class StatsProvider { public addStatListener(listener: StatsListener): void { this._statListeners.push(listener); + + // If we have a cached schema from diagnostics previously sent when the page was no active, + // send it to the new listener immediately + if (this._cachedSchema !== undefined) { + listener.onSchemaReceived?.(this._cachedSchema); + } } public removeStatListener(listener: StatsListener): void { diff --git a/webview-ui/src/diagnostics_panel/App.tsx b/webview-ui/src/diagnostics_panel/App.tsx index 548125c7..127bed99 100644 --- a/webview-ui/src/diagnostics_panel/App.tsx +++ b/webview-ui/src/diagnostics_panel/App.tsx @@ -1,7 +1,7 @@ // Copyright (C) Microsoft Corporation. All rights reserved. import { StatGroupSelectionBox } from './controls/StatGroupSelectionBox'; -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import ReplayControls from './controls/ReplayControls'; import { Icons } from './Icons'; import './App.css'; @@ -9,6 +9,8 @@ import tabPrefabs from './prefabs'; import { TabPrefab, TabPrefabDataSource, TabPrefabParams } from './prefabs/TabPrefab'; import { handleDebuggerRequestResult } from './utilities/useDebuggerRequests'; import { vscode } from './utilities/vscode'; +import { DiagnosticsTabDescriptor } from './DiagnosticsSchema'; +import DynamicTab from './DynamicTab'; // Wraps each tab's content() as a proper React component so that any hooks // inside the content function are correctly isolated and not called conditionally @@ -17,6 +19,13 @@ function TabView({ tabPrefab, params }: { tabPrefab: TabPrefab; params: TabPrefa return <>{tabPrefab.content(params)}; } +const sortedTabPrefabs = [...tabPrefabs].sort((a, b) => a.name.localeCompare(b.name)); + +// A tab entry is either a hardcoded prefab or a dynamic descriptor received from the game. +type MergedTab = + | { kind: 'prefab'; name: string; tab: TabPrefab } + | { kind: 'dynamic'; name: string; descriptor: DiagnosticsTabDescriptor }; + declare global { interface Window { initialParams: any; @@ -52,12 +61,13 @@ const CLIENT_SELECTION_HELP_TOOLTIP = 'Please enable "Creator > Script Diagnostics Settings > Enable Client Diagnostics" from within the game settings.'; function App() { - const sortedTabPrefabs = [...tabPrefabs].sort((a, b) => a.name.localeCompare(b.name)); const [selectedPlugin, setSelectedPlugin] = useState(''); const [selectedClient, setSelectedClient] = useState(''); const [currentTab, setCurrentTab] = useState('tab-0'); const [paused, setPaused] = useState(true); const [speed, setSpeed] = useState(''); + // Dynamic schema received from the game on connect. Merged into the prefab tab list. + const [schema, setSchema] = useState([]); const handlePluginSelection = useCallback((pluginSelectionId: string) => { setSelectedPlugin(() => pluginSelectionId); @@ -76,6 +86,8 @@ function App() { setPaused(message.paused); } else if (message.type === 'debugger-request-result') { handleDebuggerRequestResult(message); + } else if (message.type === 'diagnostics-schema') { + setSchema(message.schema as DiagnosticsTabDescriptor[]); } }; window.addEventListener('message', handleMessage); @@ -84,6 +96,26 @@ function App() { }; }, [handleDebuggerRequestResult]); + // Merge schema tabs into the prefab list. Schema tabs whose name matches a prefab replace it; + // new names are appended. Falls back to all prefabs when no schema has arrived yet. + const mergedTabs: MergedTab[] = useMemo(() => { + const merged: MergedTab[] = sortedTabPrefabs.map(tab => ({ + kind: 'prefab' as const, + name: tab.name, + tab, + })); + for (const descriptor of schema) { + const existingIndex = merged.findIndex(t => t.name === descriptor.name); + if (existingIndex !== -1) { + merged[existingIndex] = { kind: 'dynamic' as const, name: descriptor.name, descriptor }; + } else { + merged.push({ kind: 'dynamic' as const, name: descriptor.name, descriptor }); + } + } + merged.sort((a, b) => a.name.localeCompare(b.name)); + return merged; + }, [schema]); + return (
{window.initialParams.showReplayControls && ( @@ -100,18 +132,18 @@ function App() { )}
- {sortedTabPrefabs.map((tabPrefab, index) => ( + {mergedTabs.map((tab, index) => ( ))}
- {sortedTabPrefabs.map((tabPrefab, index) => ( + {mergedTabs.map((tab, index) => (
- {tabPrefab.dataSource === TabPrefabDataSource.Client ? ( - - ) : ( -
- )} - {tabPrefab.dataSource === TabPrefabDataSource.ServerScript ? ( - + {tab.kind === 'prefab' ? ( + <> + {tab.tab.dataSource === TabPrefabDataSource.Client ? ( + + ) : ( +
+ )} + {tab.tab.dataSource === TabPrefabDataSource.ServerScript ? ( + + ) : ( +
+ )} + + ) : ( -
+ <> + {tab.descriptor.data_source === 'client' && ( + + )} + {tab.descriptor.data_source === 'server_script' && ( + + )} + + )} -
))}
diff --git a/webview-ui/src/diagnostics_panel/DiagnosticsSchema.ts b/webview-ui/src/diagnostics_panel/DiagnosticsSchema.ts new file mode 100644 index 00000000..45811aa7 --- /dev/null +++ b/webview-ui/src/diagnostics_panel/DiagnosticsSchema.ts @@ -0,0 +1,29 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// TypeScript mirror of ScriptDiagnosticsDescriptor (C++) and its Cereal based wire format. + +export type DiagnosticsDataSource = 'server' | 'client' | 'server_script'; + +export type DiagnosticsDisplayType = + | 'line_chart' + | 'stacked_line_chart' + | 'stacked_bar_chart' + | 'table' + | 'multi_column_table' + | 'dynamic_properties_table'; + +// One-to-one with ScriptDiagnosticsDescriptor fields (snake_case matches cereal wire names). +export interface DiagnosticsTabDescriptor { + name: string; + stat_group_id: string; + data_source: DiagnosticsDataSource; + display_type: DiagnosticsDisplayType; + title?: string; + y_label?: string; + tick_range?: number; + value_scalar?: number; + target_value?: number; + key_label?: string; + value_labels?: string[]; + statistic_id?: string; + statistic_ids?: string[]; +} diff --git a/webview-ui/src/diagnostics_panel/DynamicTab.tsx b/webview-ui/src/diagnostics_panel/DynamicTab.tsx new file mode 100644 index 00000000..3f3bfec2 --- /dev/null +++ b/webview-ui/src/diagnostics_panel/DynamicTab.tsx @@ -0,0 +1,166 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. + +// Generic tab renderer driven by a DiagnosticsTabDescriptor from the C++ schema registry. +// Derives the appropriate StatisticProvider and StatisticResolver from the descriptor fields +// and renders the matching control — no new tab files needed for new diagnostics. + +import { useMemo } from 'react'; +import { DiagnosticsTabDescriptor } from './DiagnosticsSchema'; +import { + SimpleStatisticProvider, + MultipleStatisticProvider, + StatisticProvider, +} from './StatisticProvider'; +import { StatisticType, YAxisType, createStatResolver, StatisticResolver } from './StatisticResolver'; +import MinecraftStatisticLineChart from './controls/MinecraftStatisticLineChart'; +import MinecraftStatisticStackedLineChart from './controls/MinecraftStatisticStackedLineChart'; +import MinecraftStatisticStackedBarChart from './controls/MinecraftStatisticStackedBarChart'; +import MinecraftStatisticTable from './controls/MinecraftStatisticTable'; +import MinecraftMultiColumnStatisticTable from './controls/MinecraftMultiColumnStatisticTable'; +import { MinecraftDynamicPropertiesTable } from './controls/MinecraftDynamicPropertiesTable'; + +type DynamicTabProps = { + descriptor: DiagnosticsTabDescriptor; + selectedClient: string; + selectedPlugin: string; +}; + +// Build a StatisticProvider from descriptor fields. +// Client-source tabs use a regex to match the per-player stat group prefix. +function buildProvider( + descriptor: DiagnosticsTabDescriptor, + selectedClient: string, + _selectedPlugin: string +): StatisticProvider { + const { data_source, display_type, stat_group_id, statistic_id, statistic_ids } = descriptor; + + // DynamicPropertiesTable has its own fixed provider shape + if (display_type === 'dynamic_properties_table') { + return new SimpleStatisticProvider({ + statisticId: 'consolidated_data', + statisticParentId: new RegExp(`${stat_group_id}.*`), + }); + } + + // LineChart uses SimpleStatisticProvider (single stat series) + if (display_type === 'line_chart') { + const effectiveStatId = statistic_id ?? stat_group_id; + const parentId: string | RegExp = + data_source === 'client' + ? new RegExp(`.*${selectedClient}_${stat_group_id}`) + : stat_group_id; + return new SimpleStatisticProvider({ + statisticId: effectiveStatId, + statisticParentId: parentId, + }); + } + + // All other chart/table types use MultipleStatisticProvider + const parentId: string | RegExp = + data_source === 'client' + ? new RegExp(`.*${selectedClient}_${stat_group_id}`) + : stat_group_id; + + return new MultipleStatisticProvider({ + statisticParentId: parentId, + statisticIds: statistic_ids, + }); +} + +function buildResolver(descriptor: DiagnosticsTabDescriptor): StatisticResolver { + return createStatResolver({ + type: StatisticType.Absolute, + yAxisType: YAxisType.Absolute, + tickRange: descriptor.tick_range ?? 20 * 10, + valueScalar: descriptor.value_scalar, + }); +} + +export default function DynamicTab({ descriptor, selectedClient, selectedPlugin }: DynamicTabProps) { + const title = descriptor.title ?? descriptor.name; + const yLabel = descriptor.y_label ?? ''; + const tickRange = descriptor.tick_range ?? 20 * 10; + + // Memoize provider and resolver so controls' useEffect deps remain stable across renders. + const provider = useMemo( + () => buildProvider(descriptor, selectedClient, selectedPlugin), + // re-create only when the identity of the tab or the selected client/plugin changes + [descriptor.stat_group_id, descriptor.data_source, descriptor.display_type, + descriptor.statistic_id, descriptor.statistic_ids?.join(','), selectedClient, selectedPlugin] + ); + + const resolver = useMemo( + () => buildResolver(descriptor), + [descriptor.tick_range, descriptor.value_scalar] + ); + + switch (descriptor.display_type) { + case 'line_chart': + return ( + + ); + + case 'stacked_line_chart': + return ( + + ); + + case 'stacked_bar_chart': + return ( + + ); + + case 'table': + return ( + + ); + + case 'multi_column_table': + return ( + + ); + + case 'dynamic_properties_table': + return ( + + ); + + default: + return
Unsupported display type: {descriptor.display_type}
; + } +} \ No newline at end of file diff --git a/webview-ui/src/diagnostics_panel/StatisticResolver.tsx b/webview-ui/src/diagnostics_panel/StatisticResolver.tsx index 369bff13..4b48161a 100644 --- a/webview-ui/src/diagnostics_panel/StatisticResolver.tsx +++ b/webview-ui/src/diagnostics_panel/StatisticResolver.tsx @@ -79,7 +79,7 @@ function DifferenceStatResolver( let result = [...previousValues]; for (let i = 0; i < msg.values.length; i++) { - let value = msg.values[i]; + const value = msg.values[i]; let newValue = 0; let absoluteValue = value; if (result.length !== 0) { diff --git a/webview-ui/src/diagnostics_panel/controls/LineChart/LineChart.tsx b/webview-ui/src/diagnostics_panel/controls/LineChart/LineChart.tsx index 91586a7a..594d7051 100644 --- a/webview-ui/src/diagnostics_panel/controls/LineChart/LineChart.tsx +++ b/webview-ui/src/diagnostics_panel/controls/LineChart/LineChart.tsx @@ -8,6 +8,9 @@ import * as Plot from '@observablehq/plot'; import { StatisticProvider, StatisticUpdatedMessage } from '../../StatisticProvider'; import { removeAllStyleElements } from '../../../util/CSPUtilities'; +// Set to true to generate fake data with sine wave pattern for testing without a data source +const GenerateTestData = false; + type LineChartProps = { title: string; yLabel: string; @@ -21,13 +24,55 @@ type PlotResult = ((SVGSVGElement | HTMLElement) & Plot.Plot) | undefined; function formatYAxisTick(d: d3.NumberValue): string { const n = d.valueOf(); - if (n === 0) return '0'; + if (n === 0) { + return '0'; + } const abs = Math.abs(n); - if (abs >= 1000) return `${Math.round(n)}`; - if (abs >= 1) return `${parseFloat(n.toPrecision(4))}`; + if (abs >= 1000) { + return `${Math.round(n)}`; + } + if (abs >= 1) { + return `${parseFloat(n.toPrecision(4))}`; + } return `${parseFloat(n.toPrecision(3))}`; } +function formatRelativeTime(latestTime: number, tick: number): string { + const diff = latestTime - tick; + if (diff < 20) { + return 'now'; + } + return `${Math.floor(diff / 20)}s ago`; +} + +const SharedTipDisplayOptions = { + fillOpacity: 0.5, + fill: 'black', + stroke: 'white', + style: { + color: 'var(--vscode-editorHoverWidget-foreground)', + background: 'var(--vscode-editorHoverWidget-background)', + }, +}; + +function createInitialChartData(pointCount = 40): TrackedStat[] { +if(!GenerateTestData) { + return []; + } + const seed: TrackedStat[] = []; + for (let i = 0; i < pointCount; i++) { + const time = i + 1; + const value = 35 + Math.sin(i / 4) * 10 + i * 0.2; + seed.push({ + time, + value, + absoluteValue: value, + category: 'sample', + }); + } + return seed; +} + //chart component export function LineChart({ title, @@ -36,9 +81,9 @@ export function LineChart({ statisticOptions, statisticDataProvider, yAxisStyle, -}: LineChartProps) { +}: LineChartProps): JSX.Element { // state - const [data, setData] = useState([]); + const [data, setData] = useState(() => createInitialChartData()); // refs const containerRef = useRef(null); @@ -86,13 +131,11 @@ export function LineChart({ x: { //domain: [0, _maxDataPoints - 1], grid: true, - tickFormat: function (d: d3.NumberValue, i: number) { + tickFormat: function (d: d3.NumberValue, _i: number) { const tickDifference = latestTime - d.valueOf(); - if (tickDifference < 20) { return 'now'; } - // Assume 20 ticks per second return Math.floor(tickDifference / 20) + 's'; }, @@ -109,40 +152,40 @@ export function LineChart({ // TODO: Clean up with factory? enableFilledChart ? Plot.areaY(data, { - x: 'time', - y: d => Math.max(yDomain[0], d.value), - fillOpacity: 0.3, - y1: yDomain[0], - }) + x: 'time', + y: d => Math.max(yDomain[0], d.value), + fillOpacity: 0.3, + y1: yDomain[0], + }) : undefined, Plot.lineY(data, { x: 'time', y: 'value' }), enableFilledChart ? Plot.ruleY([0]) : undefined, - Plot.crosshairX(data, { x: 'time', y: 'value' }), + Plot.tip( + data, + Plot.pointerX({ + x: 'time', + y: 'value', + title: (d: TrackedStat) => + `${xLabel}: ${formatRelativeTime(latestTime, d.time)}\n${yLabel}: ${formatYAxisTick(d.value)}`, + ...SharedTipDisplayOptions, + }) + ), ], }); }; const generateDifferenceChart = (): PlotResult => { - return Plot.differenceY(data, { - x: 'time', - y: 'value', - //positiveFill: "red", - //negativeFill: "blue", - tip: true, - }).plot({ + return Plot.plot({ className: 'difference-chart', title: title, marginLeft: 50, // Y Axis labels were getting cut off x: { grid: true, - tickFormat: function (d: d3.NumberValue, i: number) { + tickFormat: function (d: d3.NumberValue) { const tickDifference = latestTime - d.valueOf(); - if (tickDifference < 20) { return 'now'; } - - // Assume 20 ticks per second return Math.floor(tickDifference / 20) + 's'; }, label: xLabel, @@ -154,6 +197,19 @@ export function LineChart({ label: yLabel, tickFormat: formatYAxisTick, }, + marks: [ + Plot.differenceY(data, { x: 'time', y: 'value' }), + Plot.tip( + data, + Plot.pointerX({ + x: 'time', + y: 'value', + title: (d: TrackedStat) => + `${xLabel}: ${formatRelativeTime(latestTime, d.time)}\n${yLabel}: ${formatYAxisTick(d.value)}`, + ...SharedTipDisplayOptions, + }) + ), + ], }); }; diff --git a/webview-ui/src/diagnostics_panel/controls/MinecraftStatisticLineChart.tsx b/webview-ui/src/diagnostics_panel/controls/MinecraftStatisticLineChart.tsx index e46c22ec..f2407252 100644 --- a/webview-ui/src/diagnostics_panel/controls/MinecraftStatisticLineChart.tsx +++ b/webview-ui/src/diagnostics_panel/controls/MinecraftStatisticLineChart.tsx @@ -22,7 +22,7 @@ export default function MinecraftStatisticLineChart({ xLabel = 'Time', yAxisStyle, statisticDataProvider, -}: MinecraftStatisticLineChartProps) { +}: MinecraftStatisticLineChartProps): JSX.Element { const [_statisticOptions, _setStatisticOptions] = useState(statisticOptions); const yAxisResolverChanged = useCallback((selectedType: YAxisType): void => { diff --git a/webview-ui/src/diagnostics_panel/index.tsx b/webview-ui/src/diagnostics_panel/index.tsx index 9551ae90..9b52539a 100644 --- a/webview-ui/src/diagnostics_panel/index.tsx +++ b/webview-ui/src/diagnostics_panel/index.tsx @@ -5,7 +5,7 @@ import { createRoot } from 'react-dom/client'; import App from './App'; const container = document.getElementById('root'); -const root = createRoot(container!); // createRoot(container!) if you use TypeScript +const root = createRoot(container!); root.render( diff --git a/webview-ui/src/diagnostics_panel/prefabs/TabPrefab.ts b/webview-ui/src/diagnostics_panel/prefabs/TabPrefab.ts index 298d1356..e8cd3c3a 100644 --- a/webview-ui/src/diagnostics_panel/prefabs/TabPrefab.ts +++ b/webview-ui/src/diagnostics_panel/prefabs/TabPrefab.ts @@ -1,5 +1,3 @@ -import { StatisticPrefab } from './StatisticPrefab'; - export type TabPrefabParams = { selectedClient: string; selectedPlugin: string; diff --git a/webview-ui/src/diagnostics_panel/prefabs/tabs/ServerMemory.tsx b/webview-ui/src/diagnostics_panel/prefabs/tabs/ServerMemory.tsx index 29bca47d..668c13cd 100644 --- a/webview-ui/src/diagnostics_panel/prefabs/tabs/ServerMemory.tsx +++ b/webview-ui/src/diagnostics_panel/prefabs/tabs/ServerMemory.tsx @@ -5,7 +5,7 @@ import { StatisticType, YAxisType } from '../../StatisticResolver'; import { TabPrefab, TabPrefabDataSource } from '../TabPrefab'; import { generateRowsFromStatsPrefabs } from '../utilities'; -const appMemoryUsage: StatisticPrefab = { +const AppMemoryUsage: StatisticPrefab = { name: 'App Memory Usage', reactNode: ( { return generateRowsFromStatsPrefabs([ - [appMemoryUsage, appMemoryFree], - [javaScriptMemoryAllocated, javaScriptMemoryFree], + [AppMemoryUsage, AppMemoryFree], + [JavaScriptMemoryAllocated, JavaScriptMemoryUsed], ]); }, }; -export default statsTab; +export default StatsTab; diff --git a/webview-ui/src/diagnostics_panel/prefabs/tabs/ServerTiming.tsx b/webview-ui/src/diagnostics_panel/prefabs/tabs/ServerTiming.tsx index 42aa416c..db5af90b 100644 --- a/webview-ui/src/diagnostics_panel/prefabs/tabs/ServerTiming.tsx +++ b/webview-ui/src/diagnostics_panel/prefabs/tabs/ServerTiming.tsx @@ -5,7 +5,7 @@ import { StatisticType, YAxisType, createStatResolver } from '../../StatisticRes import { TabPrefab, TabPrefabDataSource } from '../TabPrefab'; import { generateRowsFromStatsPrefabs } from '../utilities'; -const serverTickTimings: StatisticPrefab = { +const ServerTickTimings: StatisticPrefab = { name: 'Server Tick Timings', reactNode: ( { - return generateRowsFromStatsPrefabs([[serverTickTimings], [commandsRan]]); + return generateRowsFromStatsPrefabs([[ServerTickTimings], [CommandsRan]]); }, }; -export default statsTab; +export default StatsTab;