diff --git a/packages/trace-viewer/src/index.tsx b/packages/trace-viewer/src/index.tsx
index a737d9017f..671a2235ae 100644
--- a/packages/trace-viewer/src/index.tsx
+++ b/packages/trace-viewer/src/index.tsx
@@ -19,11 +19,14 @@ import { applyTheme } from '@web/theme';
import '@web/third_party/vscode/codicon.css';
import * as ReactDOM from 'react-dom/client';
import { WorkbenchLoader } from './ui/workbenchLoader';
+import { LiveWorkbenchLoader } from './ui/liveWorkbenchLoader';
(async () => {
+ const queryParams = new URLSearchParams(window.location.search);
+
applyTheme();
if (window.location.protocol !== 'file:') {
- if (window.location.href.includes('isUnderTest=true'))
+ if (queryParams.get('isUnderTest') === 'true')
await new Promise(f => setTimeout(f, 1000));
if (!navigator.serviceWorker)
throw new Error(`Service workers are not supported.\nMake sure to serve the Trace Viewer (${window.location}) via HTTPS or localhost.`);
@@ -38,5 +41,8 @@ import { WorkbenchLoader } from './ui/workbenchLoader';
setInterval(function() { fetch('ping'); }, 10000);
}
- ReactDOM.createRoot(document.querySelector('#root')!).render();
+ const trace = queryParams.get('trace');
+ const traceIsLive = trace?.endsWith('.json');
+ const workbench = traceIsLive ? : ;
+ ReactDOM.createRoot(document.querySelector('#root')!).render(workbench);
})();
diff --git a/packages/trace-viewer/src/ui/liveWorkbenchLoader.tsx b/packages/trace-viewer/src/ui/liveWorkbenchLoader.tsx
new file mode 100644
index 0000000000..ba44a66c30
--- /dev/null
+++ b/packages/trace-viewer/src/ui/liveWorkbenchLoader.tsx
@@ -0,0 +1,61 @@
+/*
+ Copyright (c) Microsoft Corporation.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+import * as React from 'react';
+import { MultiTraceModel } from './modelUtil';
+import './workbenchLoader.css';
+import { Workbench } from './workbench';
+
+import type { ContextEntry } from '../types/entries';
+
+export const LiveWorkbenchLoader: React.FC<{ traceJson: string }> = ({ traceJson }) => {
+ const [model, setModel] = React.useState(undefined);
+ const [counter, setCounter] = React.useState(0);
+ const pollTimer = React.useRef(null);
+
+ React.useEffect(() => {
+ if (pollTimer.current)
+ clearTimeout(pollTimer.current);
+
+ // Start polling running test.
+ pollTimer.current = setTimeout(async () => {
+ try {
+ const model = await loadSingleTraceFile(traceJson);
+ setModel(model);
+ } catch {
+ const model = new MultiTraceModel([]);
+ setModel(model);
+ } finally {
+ setCounter(counter + 1);
+ }
+ }, 500);
+ return () => {
+ if (pollTimer.current)
+ clearTimeout(pollTimer.current);
+ };
+ }, [traceJson, counter]);
+
+ return ;
+};
+
+async function loadSingleTraceFile(traceJson: string): Promise {
+ const params = new URLSearchParams();
+ params.set('trace', traceJson);
+ params.set('limit', '1');
+ const response = await fetch(`contexts?${params.toString()}`);
+ const contextEntries = await response.json() as ContextEntry[];
+ return new MultiTraceModel(contextEntries);
+}