Skip to content

Commit

Permalink
feature(trace-viewer): embedded mode support PoC
Browse files Browse the repository at this point in the history
  • Loading branch information
ruifigueira committed May 18, 2024
1 parent 9188ff7 commit f4181da
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 19 deletions.
15 changes: 12 additions & 3 deletions packages/playwright-core/src/cli/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import type { Command } from '../utilsBundle';
import { program } from '../utilsBundle';
export { program } from '../utilsBundle';
import { runDriver, runServer, printApiJson, launchBrowserServer } from './driver';
import { runTraceInBrowser, runTraceViewerApp } from '../server/trace/viewer/traceViewer';
import { runTraceInBrowser, runTraceViewerApp, runTraceViewerServer } from '../server/trace/viewer/traceViewer';
import type { TraceViewerServerOptions } from '../server/trace/viewer/traceViewer';
import * as playwright from '../..';
import type { BrowserContext } from '../client/browserContext';
Expand Down Expand Up @@ -296,6 +296,8 @@ program
.option('-h, --host <host>', 'Host to serve trace on; specifying this option opens trace in a browser tab')
.option('-p, --port <port>', 'Port to serve trace on, 0 for any free port; specifying this option opens trace in a browser tab')
.option('--stdin', 'Accept trace URLs over stdin to update the viewer')
.option('--server-only', 'Run server only')
.option('--theme <theme>', 'light or dark theme')
.description('show trace viewer')
.action(function(traces, options) {
if (options.browser === 'cr')
Expand All @@ -309,12 +311,19 @@ program
host: options.host,
port: +options.port,
isServer: !!options.stdin,
embedded: !!options.stdin && options.serverOnly,
theme: options.theme,
};

if (options.port !== undefined || options.host !== undefined)
if (openOptions.embedded) {
runTraceViewerServer(traces, openOptions).then(server => {
process.stdout.write(server.urlPrefix('precise') + '\n');
}).catch(logErrorAndExit);
} else if (options.port !== undefined || options.host !== undefined) {
runTraceInBrowser(traces, openOptions).catch(logErrorAndExit);
else
} else {
runTraceViewerApp(traces, options.browser, openOptions, true).catch(logErrorAndExit);
}
}).addHelpText('afterAll', `
Examples:
Expand Down
19 changes: 15 additions & 4 deletions packages/playwright-core/src/server/trace/viewer/traceViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export type TraceViewerServerOptions = {
port?: number;
isServer?: boolean;
transport?: Transport;
embedded?: boolean;
theme?: 'light' | 'dark';
};

export type TraceViewerRedirectOptions = {
Expand All @@ -46,6 +48,8 @@ export type TraceViewerRedirectOptions = {
reporter?: string[];
webApp?: string;
isServer?: boolean;
embedded?: boolean;
theme?: 'light' | 'dark';
};

export type TraceViewerAppOptions = {
Expand Down Expand Up @@ -131,6 +135,10 @@ export async function installRootRedirect(server: HttpServer, traceUrls: string[
params.append('headed', '');
for (const reporter of options.reporter || [])
params.append('reporter', reporter);
if (options.theme)
params.append('theme', options.theme);
if (options.embedded)
params.append('embedded', '');

const urlPath = `/trace/${options.webApp || 'index.html'}?${params.toString()}`;
server.routePath('/', (_, response) => {
Expand All @@ -141,20 +149,23 @@ export async function installRootRedirect(server: HttpServer, traceUrls: string[
});
}

export async function runTraceViewerApp(traceUrls: string[], browserName: string, options: TraceViewerServerOptions & { headless?: boolean }, exitOnClose?: boolean) {
export async function runTraceViewerServer(traceUrls: string[], options: TraceViewerServerOptions & { headless?: boolean }, exitOnClose?: boolean) {
validateTraceUrls(traceUrls);
const server = await startTraceViewerServer(options);
await installRootRedirect(server, traceUrls, options);
return server;
}

export async function runTraceViewerApp(traceUrls: string[], browserName: string, options: TraceViewerServerOptions & { headless?: boolean }, exitOnClose?: boolean) {
const server = await runTraceViewerServer(traceUrls, options);
const page = await openTraceViewerApp(server.urlPrefix('precise'), browserName, options);
if (exitOnClose)
page.on('close', () => gracefullyProcessExitDoNotHang(0));
return page;
}

export async function runTraceInBrowser(traceUrls: string[], options: TraceViewerServerOptions) {
validateTraceUrls(traceUrls);
const server = await startTraceViewerServer(options);
await installRootRedirect(server, traceUrls, options);
const server = await runTraceViewerServer(traceUrls, options);
await openTraceInBrowser(server.urlPrefix('human-readable'));
}

Expand Down
9 changes: 6 additions & 3 deletions packages/trace-viewer/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,19 @@
*/

import '@web/common.css';
import { applyTheme } from '@web/theme';
import { type Theme, applyTheme } from '@web/theme';
import '@web/third_party/vscode/codicon.css';
import React from 'react';
import * as ReactDOM from 'react-dom';
import { WorkbenchLoader } from './ui/workbenchLoader';

(async () => {
applyTheme();
const params = new URL(window.location.href).searchParams;
const theme = params.has('theme') ? `${params.get('theme')}-mode` as Theme : undefined;

applyTheme(theme);
if (window.location.protocol !== 'file:') {
if (window.location.href.includes('isUnderTest=true'))
if (params.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.`);
Expand Down
7 changes: 4 additions & 3 deletions packages/trace-viewer/src/ui/workbenchLoader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const WorkbenchLoader: React.FunctionComponent<{
const [dragOver, setDragOver] = React.useState<boolean>(false);
const [processingErrorMessage, setProcessingErrorMessage] = React.useState<string | null>(null);
const [fileForLocalModeError, setFileForLocalModeError] = React.useState<string | null>(null);
const [embedded, setEmbedded] = React.useState<boolean>(false);

const processTraceFiles = React.useCallback((files: FileList) => {
const blobUrls = [];
Expand Down Expand Up @@ -74,7 +75,7 @@ export const WorkbenchLoader: React.FunctionComponent<{
const params = new URL(window.location.href).searchParams;
const newTraceURLs = params.getAll('trace');
setIsServer(params.has('isServer'));

setEmbedded(params.has('embedded'));
// Don't accept file:// URLs - this means we re opened locally.
for (const url of newTraceURLs) {
if (url.startsWith('file:')) {
Expand Down Expand Up @@ -138,15 +139,15 @@ export const WorkbenchLoader: React.FunctionComponent<{
const showFileUploadDropArea = !!(!isServer && !dragOver && !fileForLocalModeError && (!traceURLs.length || processingErrorMessage));

return <div className='vbox workbench-loader' onDragOver={event => { event.preventDefault(); setDragOver(true); }}>
<div className='hbox header' {...(showFileUploadDropArea ? { inert: 'true' } : {})}>
{!embedded && <div className='hbox header' {...(showFileUploadDropArea ? { inert: 'true' } : {})}>
<div className='logo'>
<img src='playwright-logo.svg' alt='Playwright logo' />
</div>
<div className='product'>Playwright</div>
{model.title && <div className='title'>{model.title}</div>}
<div className='spacer'></div>
<ToolbarButton icon='color-mode' title='Toggle color mode' toggled={false} onClick={() => toggleTheme()}></ToolbarButton>
</div>
</div>}
<div className='progress'>
<div className='inner-progress' style={{ width: progress.total ? (100 * progress.done / progress.total) + '%' : 0 }}></div>
</div>
Expand Down
12 changes: 6 additions & 6 deletions packages/web/src/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

import { settings } from './uiUtils';

export function applyTheme() {
export type Theme = 'dark-mode' | 'light-mode';

export function applyTheme(theme?: Theme) {
if ((document as any).playwrightThemeInitialized)
return;
(document as any).playwrightThemeInitialized = true;
Expand All @@ -28,14 +30,12 @@ export function applyTheme() {
document.body.classList.add('inactive');
}, false);

const currentTheme = settings.getString('theme', 'light-mode');
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)');
if (currentTheme === 'dark-mode' || prefersDarkScheme.matches)
const defaultTheme = window.matchMedia('(prefers-color-scheme: dark)') ? 'dark-mode' : 'light-mode';
const currentTheme = theme ?? settings.getString('theme', defaultTheme);
if (currentTheme === 'dark-mode')
document.body.classList.add('dark-mode');
}

type Theme = 'dark-mode' | 'light-mode';

const listeners = new Set<(theme: Theme) => void>();
export function toggleTheme() {
const oldTheme = settings.getString('theme', 'light-mode');
Expand Down

0 comments on commit f4181da

Please sign in to comment.