diff --git a/.storybook/main.js b/.storybook/main.js index 29b99c383c..f421c92473 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -1,6 +1,7 @@ module.exports = { "stories": [ - "../src/cli/traceViewer/web/ui/*.stories.tsx", + "../src/web/traceViewer/ui/*.stories.tsx", + "../src/web/components/*.stories.tsx", ], "addons": [ "@storybook/addon-links", diff --git a/.storybook/preview.js b/.storybook/preview.js index f94984aa88..62e070a21c 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -1,16 +1,14 @@ import { addDecorator } from '@storybook/react'; -import { GlobalStyles } from '../src/cli/traceViewer/web/styles'; -import { applyTheme } from '../src/cli/traceViewer/web/theme'; +import '../src/web/common.css'; +import { applyTheme } from '../src/web/theme'; export const parameters = { actions: { argTypesRegex: "^on[A-Z].*" }, } - addDecorator(storyFn => { applyTheme(); return
- {storyFn()}
}); diff --git a/src/cli/traceViewer/traceViewer.ts b/src/cli/traceViewer/traceViewer.ts index b3a168c62b..5b6fcd75f8 100644 --- a/src/cli/traceViewer/traceViewer.ts +++ b/src/cli/traceViewer/traceViewer.ts @@ -81,13 +81,13 @@ class TraceViewer { async show() { const browser = await playwright.chromium.launch({ headless: false }); const server = await SnapshotServer.create( - path.join(__dirname, 'web'), + path.join(__dirname, '..', '..', 'web'), this._document ? this._document.resourcesDir : undefined, this._document ? this._document.model : emptyModel, this._document ? new ScreenshotGenerator(this._document.resourcesDir, this._document.model) : undefined); const uiPage = await browser.newPage({ viewport: null }); uiPage.on('close', () => process.exit(0)); - await uiPage.goto(server.traceViewerUrl('index.html')); + await uiPage.goto(server.traceViewerUrl('traceViewer/index.html')); } } diff --git a/src/cli/traceViewer/web/styles.tsx b/src/web/common.css similarity index 85% rename from src/cli/traceViewer/web/styles.tsx rename to src/web/common.css index dcc0aa488c..eb8ba18809 100644 --- a/src/cli/traceViewer/web/styles.tsx +++ b/src/web/common.css @@ -14,9 +14,6 @@ limitations under the License. */ -import * as React from 'react'; - -export const GlobalStyles = () => ; diff --git a/src/web/components/source.css b/src/web/components/source.css new file mode 100644 index 0000000000..eed5a34625 --- /dev/null +++ b/src/web/components/source.css @@ -0,0 +1,36 @@ +/* + 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. +*/ + +.pw-source { + white-space: pre; + overflow: auto; + font-family: var(--monospace-font); + font-size: 11px; + line-height: 16px; + background: white; +} + +.pw-source-line { + display: flex; +} + +.pw-source-line-number { + padding: 0 8px; + width: 30px; + text-align: right; + background: #edebe9; + user-select: none; +} diff --git a/src/web/components/source.stories.tsx b/src/web/components/source.stories.tsx new file mode 100644 index 0000000000..4d723bcb28 --- /dev/null +++ b/src/web/components/source.stories.tsx @@ -0,0 +1,100 @@ +/* + 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 { Story, Meta } from '@storybook/react/types-6-0'; +import React from 'react'; +import { Source, SourceProps } from './source'; + +export default { + title: 'Components/Source', + component: Source, +} as Meta; + +const Template: Story = args => ; + +export const Primary = Template.bind({}); +Primary.args = { + text: `const { chromium, devices } = require('.'); + +(async () => { + const browser = await chromium.launch({ + headless: false + }); + const context = await browser.newContext({ + // ...devices['iPhone 11'] + }); + + // Open new page + const page = await context.newPage(); + + // Go to https://github.com/microsoft + await page.goto('https://github.com/microsoft'); + await page._pause(); + + // Click input[aria-label="Find a repository…"] + await page.click('input[aria-label="Find a repository…"]'); + + // Fill input[aria-label="Find a repository…"] + await Promise.all([ + page.waitForNavigation(/*{ url: 'https://github.com/microsoft?q=playwright&type=&language=' }*/), + page.fill('input[aria-label="Find a repository…"]', 'playwright') + ]); + + // Click //a[normalize-space(.)='playwright'] + await page.click('//a[normalize-space(.)=\'playwright\']'); + // assert.equal(page.url(), 'https://github.com/microsoft/playwright'); + + // Click text="Issues" + await Promise.all([ + page.waitForNavigation(/*{ url: 'https://github.com/microsoft/playwright/issues' }*/), + page.click('text="Issues"') + ]); + + // Click text="triaging" + await Promise.all([ + page.waitForNavigation(/*{ url: 'https://github.com/microsoft/playwright/issues?q=is:issue+is:open+label:triaging' }*/), + page.click('text="triaging"') + ]); + + // Click text=/.*\[BUG\]\[Electron\] page\.waitForSe.*/ + await Promise.all([ + page.waitForNavigation(/*{ url: 'https://github.com/microsoft/playwright/issues/4961' }*/), + page.click('text=/.*\\\[BUG\\\]\\\[Electron\\\] page\.waitForSe.*/') + ]); + await page._pause(); + + // Click div[id="partial-users-participants"] img[alt="@pavelfeldman"] + await page.click('div[id="partial-users-participants"] img[alt="@pavelfeldman"]'); + // assert.equal(page.url(), 'https://github.com/pavelfeldman'); + await page._pause(); + + // Click text=/.*Repositories.*/ + await Promise.all([ + page.waitForNavigation(/*{ url: 'https://github.com/pavelfeldman?tab=repositories' }*/), + page.click('text=/.*Repositories.*/') + ]); + await page._pause(); + + // Click text=/.*playwright.*/ + await page.click('text=/.*playwright.*/'); + // assert.equal(page.url(), 'https://github.com/pavelfeldman/playwright'); + await page._pause(); + + // --------------------- + await context.close(); + await browser.close(); +})();` +}; diff --git a/src/web/components/source.tsx b/src/web/components/source.tsx new file mode 100644 index 0000000000..9f2ec8b518 --- /dev/null +++ b/src/web/components/source.tsx @@ -0,0 +1,46 @@ +/* + 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 './source.css'; +import * as React from 'react'; +import highlightjs from '../../third_party/highlightjs/highlightjs'; +import '../../third_party/highlightjs/highlightjs/tomorrow.css'; + +export interface SourceProps { + text: string, + targetLine: number +} + +export const Source: React.FC = ({ + text = '', +}) => { + const result = []; + let continuation: any; + for (const line of text.split('\n')) { + const highlighted = highlightjs.highlight('javascript', line, true, continuation); + continuation = highlighted.top; + result.push(highlighted.value); + } + + return
{ + result.map((markup, index) => { + return
+
{index + 1}
+
+
; + }) + }
+}; diff --git a/src/web/components/toolbar.css b/src/web/components/toolbar.css new file mode 100644 index 0000000000..b3143b10df --- /dev/null +++ b/src/web/components/toolbar.css @@ -0,0 +1,23 @@ +/* + 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. +*/ + +.pw-toolbar { + box-shadow: rgba(0, 0, 0, 0.1) 0px -1px 0px 0px inset; + background: rgb(255, 255, 255); + height: 40px; + align-items: center; + padding-right: 10px; +} diff --git a/src/web/components/toolbar.stories.tsx b/src/web/components/toolbar.stories.tsx new file mode 100644 index 0000000000..6c5ca3918f --- /dev/null +++ b/src/web/components/toolbar.stories.tsx @@ -0,0 +1,458 @@ +/* + 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 { Story, Meta } from '@storybook/react/types-6-0'; +import React from 'react'; +import { Toolbar, ToolbarProps } from './toolbar'; + +export default { + title: 'Components/Toolbar', + component: Toolbar, +} as Meta; + +const Template: Story = args => ; + +export const Primary = Template.bind({}); +Primary.args = { + buttons: [ + { title: 'Copy', icon: 'clone', onClick: () => {} }, + { title: 'Erase', icon: 'trashcan', onClick: () => {} }, + { title: 'Close', icon: 'close', onClick: () => {} }, + ] +}; + +export const All = Template.bind({}); +All.args = { + buttons: [ + { title: 'Close', icon: 'add', onClose: () => {} }, + { title: 'Close', icon: 'plus', onClose: () => {} }, + { title: 'Close', icon: 'gist-new', onClose: () => {} }, + { title: 'Close', icon: 'repo-create', onClose: () => {} }, + { title: 'Close', icon: 'lightbulb', onClose: () => {} }, + { title: 'Close', icon: 'light-bulb', onClose: () => {} }, + { title: 'Close', icon: 'repo', onClose: () => {} }, + { title: 'Close', icon: 'repo-delete', onClose: () => {} }, + { title: 'Close', icon: 'gist-fork', onClose: () => {} }, + { title: 'Close', icon: 'repo-forked', onClose: () => {} }, + { title: 'Close', icon: 'git-pull-request', onClose: () => {} }, + { title: 'Close', icon: 'git-pull-request-abandoned', onClose: () => {} }, + { title: 'Close', icon: 'record-keys', onClose: () => {} }, + { title: 'Close', icon: 'keyboard', onClose: () => {} }, + { title: 'Close', icon: 'tag', onClose: () => {} }, + { title: 'Close', icon: 'tag-add', onClose: () => {} }, + { title: 'Close', icon: 'tag-remove', onClose: () => {} }, + { title: 'Close', icon: 'person', onClose: () => {} }, + { title: 'Close', icon: 'person-add', onClose: () => {} }, + { title: 'Close', icon: 'person-follow', onClose: () => {} }, + { title: 'Close', icon: 'person-outline', onClose: () => {} }, + { title: 'Close', icon: 'person-filled', onClose: () => {} }, + { title: 'Close', icon: 'git-branch', onClose: () => {} }, + { title: 'Close', icon: 'git-branch-create', onClose: () => {} }, + { title: 'Close', icon: 'git-branch-delete', onClose: () => {} }, + { title: 'Close', icon: 'source-control', onClose: () => {} }, + { title: 'Close', icon: 'mirror', onClose: () => {} }, + { title: 'Close', icon: 'mirror-public', onClose: () => {} }, + { title: 'Close', icon: 'star', onClose: () => {} }, + { title: 'Close', icon: 'star-add', onClose: () => {} }, + { title: 'Close', icon: 'star-delete', onClose: () => {} }, + { title: 'Close', icon: 'star-empty', onClose: () => {} }, + { title: 'Close', icon: 'comment', onClose: () => {} }, + { title: 'Close', icon: 'comment-add', onClose: () => {} }, + { title: 'Close', icon: 'alert', onClose: () => {} }, + { title: 'Close', icon: 'warning', onClose: () => {} }, + { title: 'Close', icon: 'search', onClose: () => {} }, + { title: 'Close', icon: 'search-save', onClose: () => {} }, + { title: 'Close', icon: 'log-out', onClose: () => {} }, + { title: 'Close', icon: 'sign-out', onClose: () => {} }, + { title: 'Close', icon: 'log-in', onClose: () => {} }, + { title: 'Close', icon: 'sign-in', onClose: () => {} }, + { title: 'Close', icon: 'eye', onClose: () => {} }, + { title: 'Close', icon: 'eye-unwatch', onClose: () => {} }, + { title: 'Close', icon: 'eye-watch', onClose: () => {} }, + { title: 'Close', icon: 'circle-filled', onClose: () => {} }, + { title: 'Close', icon: 'primitive-dot', onClose: () => {} }, + { title: 'Close', icon: 'close-dirty', onClose: () => {} }, + { title: 'Close', icon: 'debug-breakpoint', onClose: () => {} }, + { title: 'Close', icon: 'debug-breakpoint-disabled', onClose: () => {} }, + { title: 'Close', icon: 'debug-hint', onClose: () => {} }, + { title: 'Close', icon: 'primitive-square', onClose: () => {} }, + { title: 'Close', icon: 'edit', onClose: () => {} }, + { title: 'Close', icon: 'pencil', onClose: () => {} }, + { title: 'Close', icon: 'info', onClose: () => {} }, + { title: 'Close', icon: 'issue-opened', onClose: () => {} }, + { title: 'Close', icon: 'gist-private', onClose: () => {} }, + { title: 'Close', icon: 'git-fork-private', onClose: () => {} }, + { title: 'Close', icon: 'lock', onClose: () => {} }, + { title: 'Close', icon: 'mirror-private', onClose: () => {} }, + { title: 'Close', icon: 'close', onClose: () => {} }, + { title: 'Close', icon: 'remove-close', onClose: () => {} }, + { title: 'Close', icon: 'x', onClose: () => {} }, + { title: 'Close', icon: 'repo-sync', onClose: () => {} }, + { title: 'Close', icon: 'sync', onClose: () => {} }, + { title: 'Close', icon: 'clone', onClose: () => {} }, + { title: 'Close', icon: 'desktop-download', onClose: () => {} }, + { title: 'Close', icon: 'beaker', onClose: () => {} }, + { title: 'Close', icon: 'microscope', onClose: () => {} }, + { title: 'Close', icon: 'vm', onClose: () => {} }, + { title: 'Close', icon: 'device-desktop', onClose: () => {} }, + { title: 'Close', icon: 'file', onClose: () => {} }, + { title: 'Close', icon: 'file-text', onClose: () => {} }, + { title: 'Close', icon: 'more', onClose: () => {} }, + { title: 'Close', icon: 'ellipsis', onClose: () => {} }, + { title: 'Close', icon: 'kebab-horizontal', onClose: () => {} }, + { title: 'Close', icon: 'mail-reply', onClose: () => {} }, + { title: 'Close', icon: 'reply', onClose: () => {} }, + { title: 'Close', icon: 'organization', onClose: () => {} }, + { title: 'Close', icon: 'organization-filled', onClose: () => {} }, + { title: 'Close', icon: 'organization-outline', onClose: () => {} }, + { title: 'Close', icon: 'new-file', onClose: () => {} }, + { title: 'Close', icon: 'file-add', onClose: () => {} }, + { title: 'Close', icon: 'new-folder', onClose: () => {} }, + { title: 'Close', icon: 'file-directory-create', onClose: () => {} }, + { title: 'Close', icon: 'trash', onClose: () => {} }, + { title: 'Close', icon: 'trashcan', onClose: () => {} }, + { title: 'Close', icon: 'history', onClose: () => {} }, + { title: 'Close', icon: 'clock', onClose: () => {} }, + { title: 'Close', icon: 'folder', onClose: () => {} }, + { title: 'Close', icon: 'file-directory', onClose: () => {} }, + { title: 'Close', icon: 'symbol-folder', onClose: () => {} }, + { title: 'Close', icon: 'logo-github', onClose: () => {} }, + { title: 'Close', icon: 'mark-github', onClose: () => {} }, + { title: 'Close', icon: 'github', onClose: () => {} }, + { title: 'Close', icon: 'terminal', onClose: () => {} }, + { title: 'Close', icon: 'console', onClose: () => {} }, + { title: 'Close', icon: 'repl', onClose: () => {} }, + { title: 'Close', icon: 'zap', onClose: () => {} }, + { title: 'Close', icon: 'symbol-event', onClose: () => {} }, + { title: 'Close', icon: 'error', onClose: () => {} }, + { title: 'Close', icon: 'stop', onClose: () => {} }, + { title: 'Close', icon: 'variable', onClose: () => {} }, + { title: 'Close', icon: 'symbol-variable', onClose: () => {} }, + { title: 'Close', icon: 'array', onClose: () => {} }, + { title: 'Close', icon: 'symbol-array', onClose: () => {} }, + { title: 'Close', icon: 'symbol-module', onClose: () => {} }, + { title: 'Close', icon: 'symbol-package', onClose: () => {} }, + { title: 'Close', icon: 'symbol-namespace', onClose: () => {} }, + { title: 'Close', icon: 'symbol-object', onClose: () => {} }, + { title: 'Close', icon: 'symbol-method', onClose: () => {} }, + { title: 'Close', icon: 'symbol-function', onClose: () => {} }, + { title: 'Close', icon: 'symbol-constructor', onClose: () => {} }, + { title: 'Close', icon: 'symbol-boolean', onClose: () => {} }, + { title: 'Close', icon: 'symbol-null', onClose: () => {} }, + { title: 'Close', icon: 'symbol-numeric', onClose: () => {} }, + { title: 'Close', icon: 'symbol-number', onClose: () => {} }, + { title: 'Close', icon: 'symbol-structure', onClose: () => {} }, + { title: 'Close', icon: 'symbol-struct', onClose: () => {} }, + { title: 'Close', icon: 'symbol-parameter', onClose: () => {} }, + { title: 'Close', icon: 'symbol-type-parameter', onClose: () => {} }, + { title: 'Close', icon: 'symbol-key', onClose: () => {} }, + { title: 'Close', icon: 'symbol-text', onClose: () => {} }, + { title: 'Close', icon: 'symbol-reference', onClose: () => {} }, + { title: 'Close', icon: 'go-to-file', onClose: () => {} }, + { title: 'Close', icon: 'symbol-enum', onClose: () => {} }, + { title: 'Close', icon: 'symbol-value', onClose: () => {} }, + { title: 'Close', icon: 'symbol-ruler', onClose: () => {} }, + { title: 'Close', icon: 'symbol-unit', onClose: () => {} }, + { title: 'Close', icon: 'activate-breakpoints', onClose: () => {} }, + { title: 'Close', icon: 'archive', onClose: () => {} }, + { title: 'Close', icon: 'arrow-both', onClose: () => {} }, + { title: 'Close', icon: 'arrow-down', onClose: () => {} }, + { title: 'Close', icon: 'arrow-left', onClose: () => {} }, + { title: 'Close', icon: 'arrow-right', onClose: () => {} }, + { title: 'Close', icon: 'arrow-small-down', onClose: () => {} }, + { title: 'Close', icon: 'arrow-small-left', onClose: () => {} }, + { title: 'Close', icon: 'arrow-small-right', onClose: () => {} }, + { title: 'Close', icon: 'arrow-small-up', onClose: () => {} }, + { title: 'Close', icon: 'arrow-up', onClose: () => {} }, + { title: 'Close', icon: 'bell', onClose: () => {} }, + { title: 'Close', icon: 'bold', onClose: () => {} }, + { title: 'Close', icon: 'book', onClose: () => {} }, + { title: 'Close', icon: 'bookmark', onClose: () => {} }, + { title: 'Close', icon: 'debug-breakpoint-conditional-unverified', onClose: () => {} }, + { title: 'Close', icon: 'debug-breakpoint-conditional', onClose: () => {} }, + { title: 'Close', icon: 'debug-breakpoint-conditional-disabled', onClose: () => {} }, + { title: 'Close', icon: 'debug-breakpoint-data-unverified', onClose: () => {} }, + { title: 'Close', icon: 'debug-breakpoint-data', onClose: () => {} }, + { title: 'Close', icon: 'debug-breakpoint-data-disabled', onClose: () => {} }, + { title: 'Close', icon: 'debug-breakpoint-log-unverified', onClose: () => {} }, + { title: 'Close', icon: 'debug-breakpoint-log', onClose: () => {} }, + { title: 'Close', icon: 'debug-breakpoint-log-disabled', onClose: () => {} }, + { title: 'Close', icon: 'briefcase', onClose: () => {} }, + { title: 'Close', icon: 'broadcast', onClose: () => {} }, + { title: 'Close', icon: 'browser', onClose: () => {} }, + { title: 'Close', icon: 'bug', onClose: () => {} }, + { title: 'Close', icon: 'calendar', onClose: () => {} }, + { title: 'Close', icon: 'case-sensitive', onClose: () => {} }, + { title: 'Close', icon: 'check', onClose: () => {} }, + { title: 'Close', icon: 'checklist', onClose: () => {} }, + { title: 'Close', icon: 'chevron-down', onClose: () => {} }, + { title: 'Close', icon: 'chevron-left', onClose: () => {} }, + { title: 'Close', icon: 'chevron-right', onClose: () => {} }, + { title: 'Close', icon: 'chevron-up', onClose: () => {} }, + { title: 'Close', icon: 'chrome-close', onClose: () => {} }, + { title: 'Close', icon: 'chrome-maximize', onClose: () => {} }, + { title: 'Close', icon: 'chrome-minimize', onClose: () => {} }, + { title: 'Close', icon: 'chrome-restore', onClose: () => {} }, + { title: 'Close', icon: 'circle-outline', onClose: () => {} }, + { title: 'Close', icon: 'debug-breakpoint-unverified', onClose: () => {} }, + { title: 'Close', icon: 'circle-slash', onClose: () => {} }, + { title: 'Close', icon: 'circuit-board', onClose: () => {} }, + { title: 'Close', icon: 'clear-all', onClose: () => {} }, + { title: 'Close', icon: 'clippy', onClose: () => {} }, + { title: 'Close', icon: 'close-all', onClose: () => {} }, + { title: 'Close', icon: 'cloud-download', onClose: () => {} }, + { title: 'Close', icon: 'cloud-upload', onClose: () => {} }, + { title: 'Close', icon: 'code', onClose: () => {} }, + { title: 'Close', icon: 'collapse-all', onClose: () => {} }, + { title: 'Close', icon: 'color-mode', onClose: () => {} }, + { title: 'Close', icon: 'comment-discussion', onClose: () => {} }, + { title: 'Close', icon: 'compare-changes', onClose: () => {} }, + { title: 'Close', icon: 'credit-card', onClose: () => {} }, + { title: 'Close', icon: 'dash', onClose: () => {} }, + { title: 'Close', icon: 'dashboard', onClose: () => {} }, + { title: 'Close', icon: 'database', onClose: () => {} }, + { title: 'Close', icon: 'debug-continue', onClose: () => {} }, + { title: 'Close', icon: 'debug-disconnect', onClose: () => {} }, + { title: 'Close', icon: 'debug-pause', onClose: () => {} }, + { title: 'Close', icon: 'debug-restart', onClose: () => {} }, + { title: 'Close', icon: 'debug-start', onClose: () => {} }, + { title: 'Close', icon: 'debug-step-into', onClose: () => {} }, + { title: 'Close', icon: 'debug-step-out', onClose: () => {} }, + { title: 'Close', icon: 'debug-step-over', onClose: () => {} }, + { title: 'Close', icon: 'debug-stop', onClose: () => {} }, + { title: 'Close', icon: 'debug', onClose: () => {} }, + { title: 'Close', icon: 'device-camera-video', onClose: () => {} }, + { title: 'Close', icon: 'device-camera', onClose: () => {} }, + { title: 'Close', icon: 'device-mobile', onClose: () => {} }, + { title: 'Close', icon: 'diff-added', onClose: () => {} }, + { title: 'Close', icon: 'diff-ignored', onClose: () => {} }, + { title: 'Close', icon: 'diff-modified', onClose: () => {} }, + { title: 'Close', icon: 'diff-removed', onClose: () => {} }, + { title: 'Close', icon: 'diff-renamed', onClose: () => {} }, + { title: 'Close', icon: 'diff', onClose: () => {} }, + { title: 'Close', icon: 'discard', onClose: () => {} }, + { title: 'Close', icon: 'editor-layout', onClose: () => {} }, + { title: 'Close', icon: 'empty-window', onClose: () => {} }, + { title: 'Close', icon: 'exclude', onClose: () => {} }, + { title: 'Close', icon: 'extensions', onClose: () => {} }, + { title: 'Close', icon: 'eye-closed', onClose: () => {} }, + { title: 'Close', icon: 'file-binary', onClose: () => {} }, + { title: 'Close', icon: 'file-code', onClose: () => {} }, + { title: 'Close', icon: 'file-media', onClose: () => {} }, + { title: 'Close', icon: 'file-pdf', onClose: () => {} }, + { title: 'Close', icon: 'file-submodule', onClose: () => {} }, + { title: 'Close', icon: 'file-symlink-directory', onClose: () => {} }, + { title: 'Close', icon: 'file-symlink-file', onClose: () => {} }, + { title: 'Close', icon: 'file-zip', onClose: () => {} }, + { title: 'Close', icon: 'files', onClose: () => {} }, + { title: 'Close', icon: 'filter', onClose: () => {} }, + { title: 'Close', icon: 'flame', onClose: () => {} }, + { title: 'Close', icon: 'fold-down', onClose: () => {} }, + { title: 'Close', icon: 'fold-up', onClose: () => {} }, + { title: 'Close', icon: 'fold', onClose: () => {} }, + { title: 'Close', icon: 'folder-active', onClose: () => {} }, + { title: 'Close', icon: 'folder-opened', onClose: () => {} }, + { title: 'Close', icon: 'gear', onClose: () => {} }, + { title: 'Close', icon: 'gift', onClose: () => {} }, + { title: 'Close', icon: 'gist-secret', onClose: () => {} }, + { title: 'Close', icon: 'gist', onClose: () => {} }, + { title: 'Close', icon: 'git-commit', onClose: () => {} }, + { title: 'Close', icon: 'git-compare', onClose: () => {} }, + { title: 'Close', icon: 'git-merge', onClose: () => {} }, + { title: 'Close', icon: 'github-action', onClose: () => {} }, + { title: 'Close', icon: 'github-alt', onClose: () => {} }, + { title: 'Close', icon: 'globe', onClose: () => {} }, + { title: 'Close', icon: 'grabber', onClose: () => {} }, + { title: 'Close', icon: 'graph', onClose: () => {} }, + { title: 'Close', icon: 'gripper', onClose: () => {} }, + { title: 'Close', icon: 'heart', onClose: () => {} }, + { title: 'Close', icon: 'home', onClose: () => {} }, + { title: 'Close', icon: 'horizontal-rule', onClose: () => {} }, + { title: 'Close', icon: 'hubot', onClose: () => {} }, + { title: 'Close', icon: 'inbox', onClose: () => {} }, + { title: 'Close', icon: 'issue-closed', onClose: () => {} }, + { title: 'Close', icon: 'issue-reopened', onClose: () => {} }, + { title: 'Close', icon: 'issues', onClose: () => {} }, + { title: 'Close', icon: 'italic', onClose: () => {} }, + { title: 'Close', icon: 'jersey', onClose: () => {} }, + { title: 'Close', icon: 'json', onClose: () => {} }, + { title: 'Close', icon: 'kebab-vertical', onClose: () => {} }, + { title: 'Close', icon: 'key', onClose: () => {} }, + { title: 'Close', icon: 'law', onClose: () => {} }, + { title: 'Close', icon: 'lightbulb-autofix', onClose: () => {} }, + { title: 'Close', icon: 'link-external', onClose: () => {} }, + { title: 'Close', icon: 'link', onClose: () => {} }, + { title: 'Close', icon: 'list-ordered', onClose: () => {} }, + { title: 'Close', icon: 'list-unordered', onClose: () => {} }, + { title: 'Close', icon: 'live-share', onClose: () => {} }, + { title: 'Close', icon: 'loading', onClose: () => {} }, + { title: 'Close', icon: 'location', onClose: () => {} }, + { title: 'Close', icon: 'mail-read', onClose: () => {} }, + { title: 'Close', icon: 'mail', onClose: () => {} }, + { title: 'Close', icon: 'markdown', onClose: () => {} }, + { title: 'Close', icon: 'megaphone', onClose: () => {} }, + { title: 'Close', icon: 'mention', onClose: () => {} }, + { title: 'Close', icon: 'milestone', onClose: () => {} }, + { title: 'Close', icon: 'mortar-board', onClose: () => {} }, + { title: 'Close', icon: 'move', onClose: () => {} }, + { title: 'Close', icon: 'multiple-windows', onClose: () => {} }, + { title: 'Close', icon: 'mute', onClose: () => {} }, + { title: 'Close', icon: 'no-newline', onClose: () => {} }, + { title: 'Close', icon: 'note', onClose: () => {} }, + { title: 'Close', icon: 'octoface', onClose: () => {} }, + { title: 'Close', icon: 'open-preview', onClose: () => {} }, + { title: 'Close', icon: 'package', onClose: () => {} }, + { title: 'Close', icon: 'paintcan', onClose: () => {} }, + { title: 'Close', icon: 'pin', onClose: () => {} }, + { title: 'Close', icon: 'play', onClose: () => {} }, + { title: 'Close', icon: 'run', onClose: () => {} }, + { title: 'Close', icon: 'plug', onClose: () => {} }, + { title: 'Close', icon: 'preserve-case', onClose: () => {} }, + { title: 'Close', icon: 'preview', onClose: () => {} }, + { title: 'Close', icon: 'project', onClose: () => {} }, + { title: 'Close', icon: 'pulse', onClose: () => {} }, + { title: 'Close', icon: 'question', onClose: () => {} }, + { title: 'Close', icon: 'quote', onClose: () => {} }, + { title: 'Close', icon: 'radio-tower', onClose: () => {} }, + { title: 'Close', icon: 'reactions', onClose: () => {} }, + { title: 'Close', icon: 'references', onClose: () => {} }, + { title: 'Close', icon: 'refresh', onClose: () => {} }, + { title: 'Close', icon: 'regex', onClose: () => {} }, + { title: 'Close', icon: 'remote-explorer', onClose: () => {} }, + { title: 'Close', icon: 'remote', onClose: () => {} }, + { title: 'Close', icon: 'remove', onClose: () => {} }, + { title: 'Close', icon: 'replace-all', onClose: () => {} }, + { title: 'Close', icon: 'replace', onClose: () => {} }, + { title: 'Close', icon: 'repo-clone', onClose: () => {} }, + { title: 'Close', icon: 'repo-force-push', onClose: () => {} }, + { title: 'Close', icon: 'repo-pull', onClose: () => {} }, + { title: 'Close', icon: 'repo-push', onClose: () => {} }, + { title: 'Close', icon: 'report', onClose: () => {} }, + { title: 'Close', icon: 'request-changes', onClose: () => {} }, + { title: 'Close', icon: 'rocket', onClose: () => {} }, + { title: 'Close', icon: 'root-folder-opened', onClose: () => {} }, + { title: 'Close', icon: 'root-folder', onClose: () => {} }, + { title: 'Close', icon: 'rss', onClose: () => {} }, + { title: 'Close', icon: 'ruby', onClose: () => {} }, + { title: 'Close', icon: 'save-all', onClose: () => {} }, + { title: 'Close', icon: 'save-as', onClose: () => {} }, + { title: 'Close', icon: 'save', onClose: () => {} }, + { title: 'Close', icon: 'screen-full', onClose: () => {} }, + { title: 'Close', icon: 'screen-normal', onClose: () => {} }, + { title: 'Close', icon: 'search-stop', onClose: () => {} }, + { title: 'Close', icon: 'server', onClose: () => {} }, + { title: 'Close', icon: 'settings-gear', onClose: () => {} }, + { title: 'Close', icon: 'settings', onClose: () => {} }, + { title: 'Close', icon: 'shield', onClose: () => {} }, + { title: 'Close', icon: 'smiley', onClose: () => {} }, + { title: 'Close', icon: 'sort-precedence', onClose: () => {} }, + { title: 'Close', icon: 'split-horizontal', onClose: () => {} }, + { title: 'Close', icon: 'split-vertical', onClose: () => {} }, + { title: 'Close', icon: 'squirrel', onClose: () => {} }, + { title: 'Close', icon: 'star-full', onClose: () => {} }, + { title: 'Close', icon: 'star-half', onClose: () => {} }, + { title: 'Close', icon: 'symbol-class', onClose: () => {} }, + { title: 'Close', icon: 'symbol-color', onClose: () => {} }, + { title: 'Close', icon: 'symbol-constant', onClose: () => {} }, + { title: 'Close', icon: 'symbol-enum-member', onClose: () => {} }, + { title: 'Close', icon: 'symbol-field', onClose: () => {} }, + { title: 'Close', icon: 'symbol-file', onClose: () => {} }, + { title: 'Close', icon: 'symbol-interface', onClose: () => {} }, + { title: 'Close', icon: 'symbol-keyword', onClose: () => {} }, + { title: 'Close', icon: 'symbol-misc', onClose: () => {} }, + { title: 'Close', icon: 'symbol-operator', onClose: () => {} }, + { title: 'Close', icon: 'symbol-property', onClose: () => {} }, + { title: 'Close', icon: 'wrench', onClose: () => {} }, + { title: 'Close', icon: 'wrench-subaction', onClose: () => {} }, + { title: 'Close', icon: 'symbol-snippet', onClose: () => {} }, + { title: 'Close', icon: 'tasklist', onClose: () => {} }, + { title: 'Close', icon: 'telescope', onClose: () => {} }, + { title: 'Close', icon: 'text-size', onClose: () => {} }, + { title: 'Close', icon: 'three-bars', onClose: () => {} }, + { title: 'Close', icon: 'thumbsdown', onClose: () => {} }, + { title: 'Close', icon: 'thumbsup', onClose: () => {} }, + { title: 'Close', icon: 'tools', onClose: () => {} }, + { title: 'Close', icon: 'triangle-down', onClose: () => {} }, + { title: 'Close', icon: 'triangle-left', onClose: () => {} }, + { title: 'Close', icon: 'triangle-right', onClose: () => {} }, + { title: 'Close', icon: 'triangle-up', onClose: () => {} }, + { title: 'Close', icon: 'twitter', onClose: () => {} }, + { title: 'Close', icon: 'unfold', onClose: () => {} }, + { title: 'Close', icon: 'unlock', onClose: () => {} }, + { title: 'Close', icon: 'unmute', onClose: () => {} }, + { title: 'Close', icon: 'unverified', onClose: () => {} }, + { title: 'Close', icon: 'verified', onClose: () => {} }, + { title: 'Close', icon: 'versions', onClose: () => {} }, + { title: 'Close', icon: 'vm-active', onClose: () => {} }, + { title: 'Close', icon: 'vm-outline', onClose: () => {} }, + { title: 'Close', icon: 'vm-running', onClose: () => {} }, + { title: 'Close', icon: 'watch', onClose: () => {} }, + { title: 'Close', icon: 'whitespace', onClose: () => {} }, + { title: 'Close', icon: 'whole-word', onClose: () => {} }, + { title: 'Close', icon: 'window', onClose: () => {} }, + { title: 'Close', icon: 'word-wrap', onClose: () => {} }, + { title: 'Close', icon: 'zoom-in', onClose: () => {} }, + { title: 'Close', icon: 'zoom-out', onClose: () => {} }, + { title: 'Close', icon: 'list-filter', onClose: () => {} }, + { title: 'Close', icon: 'list-flat', onClose: () => {} }, + { title: 'Close', icon: 'list-selection', onClose: () => {} }, + { title: 'Close', icon: 'selection', onClose: () => {} }, + { title: 'Close', icon: 'list-tree', onClose: () => {} }, + { title: 'Close', icon: 'debug-breakpoint-function-unverified', onClose: () => {} }, + { title: 'Close', icon: 'debug-breakpoint-function', onClose: () => {} }, + { title: 'Close', icon: 'debug-breakpoint-function-disabled', onClose: () => {} }, + { title: 'Close', icon: 'debug-stackframe-active', onClose: () => {} }, + { title: 'Close', icon: 'debug-stackframe-dot', onClose: () => {} }, + { title: 'Close', icon: 'debug-stackframe', onClose: () => {} }, + { title: 'Close', icon: 'debug-stackframe-focused', onClose: () => {} }, + { title: 'Close', icon: 'debug-breakpoint-unsupported', onClose: () => {} }, + { title: 'Close', icon: 'symbol-string', onClose: () => {} }, + { title: 'Close', icon: 'debug-reverse-continue', onClose: () => {} }, + { title: 'Close', icon: 'debug-step-back', onClose: () => {} }, + { title: 'Close', icon: 'debug-restart-frame', onClose: () => {} }, + { title: 'Close', icon: 'call-incoming', onClose: () => {} }, + { title: 'Close', icon: 'call-outgoing', onClose: () => {} }, + { title: 'Close', icon: 'menu', onClose: () => {} }, + { title: 'Close', icon: 'expand-all', onClose: () => {} }, + { title: 'Close', icon: 'feedback', onClose: () => {} }, + { title: 'Close', icon: 'group-by-ref-type', onClose: () => {} }, + { title: 'Close', icon: 'ungroup-by-ref-type', onClose: () => {} }, + { title: 'Close', icon: 'account', onClose: () => {} }, + { title: 'Close', icon: 'bell-dot', onClose: () => {} }, + { title: 'Close', icon: 'debug-console', onClose: () => {} }, + { title: 'Close', icon: 'library', onClose: () => {} }, + { title: 'Close', icon: 'output', onClose: () => {} }, + { title: 'Close', icon: 'run-all', onClose: () => {} }, + { title: 'Close', icon: 'sync-ignored', onClose: () => {} }, + { title: 'Close', icon: 'pinned', onClose: () => {} }, + { title: 'Close', icon: 'github-inverted', onClose: () => {} }, + { title: 'Close', icon: 'debug-alt', onClose: () => {} }, + { title: 'Close', icon: 'server-process', onClose: () => {} }, + { title: 'Close', icon: 'server-environment', onClose: () => {} }, + { title: 'Close', icon: 'pass', onClose: () => {} }, + { title: 'Close', icon: 'stop-circle', onClose: () => {} }, + { title: 'Close', icon: 'play-circle', onClose: () => {} }, + { title: 'Close', icon: 'record', onClose: () => {} }, + { title: 'Close', icon: 'debug-alt-small', onClose: () => {} }, + { title: 'Close', icon: 'vm-connect', onClose: () => {} }, + { title: 'Close', icon: 'cloud', onClose: () => {} }, + { title: 'Close', icon: 'merge', onClose: () => {} }, + { title: 'Close', icon: 'export', onClose: () => {} }, + { title: 'Close', icon: 'graph-left', onClose: () => {} }, + { title: 'Close', icon: 'magnet', onClose: () => {} }, + + ] +}; diff --git a/src/web/components/toolbar.tsx b/src/web/components/toolbar.tsx new file mode 100644 index 0000000000..520d3ade6b --- /dev/null +++ b/src/web/components/toolbar.tsx @@ -0,0 +1,31 @@ +/* + 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 './toolbar.css'; +import * as React from 'react'; +import { ToolbarButton, ToolbarButtonProps } from './toolbarButton'; + +export interface ToolbarProps { + buttons: ToolbarButtonProps[], + icon: string, + onClick: () => void +} + +export const Toolbar: React.FC = ({ + buttons = [], +}) => { + return
{buttons.map(props => )}
; +}; diff --git a/src/web/components/toolbarButton.css b/src/web/components/toolbarButton.css new file mode 100644 index 0000000000..9ca70ce279 --- /dev/null +++ b/src/web/components/toolbarButton.css @@ -0,0 +1,30 @@ +/* + 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. +*/ + +.pw-toolbar-button { + border: none; + outline: none; + color: #999; + background: transparent; + padding: 0; + margin-left: 10px; + height: 40px; + cursor: pointer; +} + +.pw-toolbar-button:hover { + color: #1ea7fd; +} diff --git a/src/web/components/toolbarButton.stories.tsx b/src/web/components/toolbarButton.stories.tsx new file mode 100644 index 0000000000..dd2dd22f88 --- /dev/null +++ b/src/web/components/toolbarButton.stories.tsx @@ -0,0 +1,33 @@ +/* + 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 { Story, Meta } from '@storybook/react/types-6-0'; +import React from 'react'; +import { ToolbarButton, ToolbarButtonProps } from './toolbarButton'; + +export default { + title: 'Components/ToolbarButton', + component: ToolbarButton, +} as Meta; + +const Template: Story = args => ; + +export const Primary = Template.bind({}); +Primary.args = { + title: 'Close', + icon: 'close', + onClick: () => {} +}; diff --git a/src/web/components/toolbarButton.tsx b/src/web/components/toolbarButton.tsx new file mode 100644 index 0000000000..c80515363a --- /dev/null +++ b/src/web/components/toolbarButton.tsx @@ -0,0 +1,34 @@ +/* + 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 './toolbarButton.css'; +import '../third_party/vscode/codicon.css'; +import * as React from 'react'; + +export interface ToolbarButtonProps { + title: string, + icon: string, + onClick: () => void +} + +export const ToolbarButton: React.FC = ({ + title = '', + icon = '', + onClick = () => {}, +}) => { + const className = `pw-toolbar-button codicon codicon-${icon}`; + return ; +}; diff --git a/src/web/recorder/index.html b/src/web/recorder/index.html new file mode 100644 index 0000000000..f49a3eaab2 --- /dev/null +++ b/src/web/recorder/index.html @@ -0,0 +1,27 @@ + + + + + + + + Playwright Recorder + + +
+ + diff --git a/src/web/recorder/index.tsx b/src/web/recorder/index.tsx new file mode 100644 index 0000000000..1d7379a97e --- /dev/null +++ b/src/web/recorder/index.tsx @@ -0,0 +1,32 @@ +/** + * 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 '../third_party/vscode/codicon.css'; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { applyTheme } from '../theme'; +import '../common.css'; + +declare global { + interface Window { + } +} + +(async () => { + applyTheme(); + ReactDOM.render(
+
, document.querySelector('#root')); +})(); diff --git a/src/web/recorder/webpack.config.js b/src/web/recorder/webpack.config.js new file mode 100644 index 0000000000..89a35bc76a --- /dev/null +++ b/src/web/recorder/webpack.config.js @@ -0,0 +1,41 @@ +const path = require('path'); +const HtmlWebPackPlugin = require('html-webpack-plugin'); + +module.exports = { + mode: process.env.NODE_ENV === 'production' ? 'production' : 'development', + entry: { + app: path.join(__dirname, 'index.tsx'), + }, + resolve: { + extensions: ['.ts', '.js', '.tsx', '.jsx'] + }, + devtool: 'source-map', + output: { + globalObject: 'self', + filename: '[name].bundle.js', + path: path.resolve(__dirname, '../../../lib/web/recorder') + }, + module: { + rules: [ + { + test: /\.(j|t)sx?$/, + use: 'ts-loader', + exclude: /node_modules/ + }, + { + test: /\.css$/, + use: ['style-loader', 'css-loader'] + }, + { + test: /\.ttf$/, + use: ['file-loader'] + } + ] + }, + plugins: [ + new HtmlWebPackPlugin({ + title: 'Playwright Recorder', + template: path.join(__dirname, 'index.html'), + }) + ] +}; diff --git a/src/cli/traceViewer/web/theme.ts b/src/web/theme.ts similarity index 74% rename from src/cli/traceViewer/web/theme.ts rename to src/web/theme.ts index c7677d3f1c..9a1537e950 100644 --- a/src/cli/traceViewer/web/theme.ts +++ b/src/web/theme.ts @@ -14,16 +14,6 @@ * limitations under the License. */ -function platformName(): string { - if (window.navigator.userAgent.includes('Linux')) - return 'platform-linux'; - if (window.navigator.userAgent.includes('Windows')) - return 'platform-windows'; - if (window.navigator.userAgent.includes('Mac')) - return 'platform-mac'; - return 'platform-generic'; -} - export function applyTheme() { if ((document as any).playwrightThemeInitialized) return; @@ -35,5 +25,4 @@ export function applyTheme() { document!.defaultView!.addEventListener('blur', event => { document.body.classList.add('inactive'); }, false); - document.documentElement.classList.add(platformName()); } diff --git a/src/cli/traceViewer/web/third_party/vscode/LICENSE.txt b/src/web/third_party/vscode/LICENSE.txt similarity index 100% rename from src/cli/traceViewer/web/third_party/vscode/LICENSE.txt rename to src/web/third_party/vscode/LICENSE.txt diff --git a/src/cli/traceViewer/web/third_party/vscode/codicon.css b/src/web/third_party/vscode/codicon.css similarity index 100% rename from src/cli/traceViewer/web/third_party/vscode/codicon.css rename to src/web/third_party/vscode/codicon.css diff --git a/src/cli/traceViewer/web/third_party/vscode/codicon.ttf b/src/web/third_party/vscode/codicon.ttf similarity index 74% rename from src/cli/traceViewer/web/third_party/vscode/codicon.ttf rename to src/web/third_party/vscode/codicon.ttf index 82acc8995b..533199b827 100644 Binary files a/src/cli/traceViewer/web/third_party/vscode/codicon.ttf and b/src/web/third_party/vscode/codicon.ttf differ diff --git a/src/cli/traceViewer/web/geometry.ts b/src/web/traceViewer/geometry.ts similarity index 100% rename from src/cli/traceViewer/web/geometry.ts rename to src/web/traceViewer/geometry.ts diff --git a/src/cli/traceViewer/web/index.html b/src/web/traceViewer/index.html similarity index 100% rename from src/cli/traceViewer/web/index.html rename to src/web/traceViewer/index.html diff --git a/src/cli/traceViewer/web/index.tsx b/src/web/traceViewer/index.tsx similarity index 91% rename from src/cli/traceViewer/web/index.tsx rename to src/web/traceViewer/index.tsx index c2c7ccf418..240171b10e 100644 --- a/src/cli/traceViewer/web/index.tsx +++ b/src/web/traceViewer/index.tsx @@ -14,11 +14,12 @@ * limitations under the License. */ -import './third_party/vscode/codicon.css'; +import '../third_party/vscode/codicon.css'; import { Workbench } from './ui/workbench'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; -import { applyTheme } from './theme'; +import { applyTheme } from '../theme'; +import '../common.css'; (async () => { navigator.serviceWorker.register('/service-worker.js'); diff --git a/src/cli/traceViewer/web/ui/actionList.css b/src/web/traceViewer/ui/actionList.css similarity index 100% rename from src/cli/traceViewer/web/ui/actionList.css rename to src/web/traceViewer/ui/actionList.css diff --git a/src/cli/traceViewer/web/ui/actionList.stories.tsx b/src/web/traceViewer/ui/actionList.stories.tsx similarity index 100% rename from src/cli/traceViewer/web/ui/actionList.stories.tsx rename to src/web/traceViewer/ui/actionList.stories.tsx diff --git a/src/cli/traceViewer/web/ui/actionList.tsx b/src/web/traceViewer/ui/actionList.tsx similarity index 97% rename from src/cli/traceViewer/web/ui/actionList.tsx rename to src/web/traceViewer/ui/actionList.tsx index c4c756e73d..17b6fd5a57 100644 --- a/src/cli/traceViewer/web/ui/actionList.tsx +++ b/src/web/traceViewer/ui/actionList.tsx @@ -14,7 +14,7 @@ limitations under the License. */ -import { ActionEntry } from '../../traceModel'; +import { ActionEntry } from '../../../cli/traceViewer/traceModel'; import './actionList.css'; import * as React from 'react'; diff --git a/src/cli/traceViewer/web/ui/assets/action-thumbnail-click.png b/src/web/traceViewer/ui/assets/action-thumbnail-click.png similarity index 100% rename from src/cli/traceViewer/web/ui/assets/action-thumbnail-click.png rename to src/web/traceViewer/ui/assets/action-thumbnail-click.png diff --git a/src/cli/traceViewer/web/ui/assets/action-thumbnail-goto.png b/src/web/traceViewer/ui/assets/action-thumbnail-goto.png similarity index 100% rename from src/cli/traceViewer/web/ui/assets/action-thumbnail-goto.png rename to src/web/traceViewer/ui/assets/action-thumbnail-goto.png diff --git a/src/cli/traceViewer/web/ui/contextSelector.css b/src/web/traceViewer/ui/contextSelector.css similarity index 100% rename from src/cli/traceViewer/web/ui/contextSelector.css rename to src/web/traceViewer/ui/contextSelector.css diff --git a/src/cli/traceViewer/web/ui/contextSelector.tsx b/src/web/traceViewer/ui/contextSelector.tsx similarity index 95% rename from src/cli/traceViewer/web/ui/contextSelector.tsx rename to src/web/traceViewer/ui/contextSelector.tsx index cf83feb526..eaf81c89ac 100644 --- a/src/cli/traceViewer/web/ui/contextSelector.tsx +++ b/src/web/traceViewer/ui/contextSelector.tsx @@ -15,7 +15,7 @@ */ import * as React from 'react'; -import { ContextEntry } from '../../traceModel'; +import { ContextEntry } from '../../../cli/traceViewer/traceModel'; import './contextSelector.css'; export const ContextSelector: React.FunctionComponent<{ diff --git a/src/cli/traceViewer/web/ui/helpers.tsx b/src/web/traceViewer/ui/helpers.tsx similarity index 100% rename from src/cli/traceViewer/web/ui/helpers.tsx rename to src/web/traceViewer/ui/helpers.tsx diff --git a/src/cli/traceViewer/web/ui/logsTab.css b/src/web/traceViewer/ui/logsTab.css similarity index 100% rename from src/cli/traceViewer/web/ui/logsTab.css rename to src/web/traceViewer/ui/logsTab.css diff --git a/src/cli/traceViewer/web/ui/logsTab.tsx b/src/web/traceViewer/ui/logsTab.tsx similarity index 94% rename from src/cli/traceViewer/web/ui/logsTab.tsx rename to src/web/traceViewer/ui/logsTab.tsx index 2385d810b5..0c74cf67f8 100644 --- a/src/cli/traceViewer/web/ui/logsTab.tsx +++ b/src/web/traceViewer/ui/logsTab.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { ActionEntry } from '../../traceModel'; +import { ActionEntry } from '../../../cli/traceViewer/traceModel'; import * as React from 'react'; import './logsTab.css'; diff --git a/src/cli/traceViewer/web/ui/networkResourceDetails.css b/src/web/traceViewer/ui/networkResourceDetails.css similarity index 100% rename from src/cli/traceViewer/web/ui/networkResourceDetails.css rename to src/web/traceViewer/ui/networkResourceDetails.css diff --git a/src/cli/traceViewer/web/ui/networkResourceDetails.tsx b/src/web/traceViewer/ui/networkResourceDetails.tsx similarity index 98% rename from src/cli/traceViewer/web/ui/networkResourceDetails.tsx rename to src/web/traceViewer/ui/networkResourceDetails.tsx index 1e9f28c882..2e444fed59 100644 --- a/src/cli/traceViewer/web/ui/networkResourceDetails.tsx +++ b/src/web/traceViewer/ui/networkResourceDetails.tsx @@ -17,7 +17,7 @@ import './networkResourceDetails.css'; import * as React from 'react'; import { Expandable } from './helpers'; -import { NetworkResourceTraceEvent } from '../../../../trace/traceTypes'; +import { NetworkResourceTraceEvent } from '../../../trace/traceTypes'; export const NetworkResourceDetails: React.FunctionComponent<{ diff --git a/src/cli/traceViewer/web/ui/networkTab.css b/src/web/traceViewer/ui/networkTab.css similarity index 100% rename from src/cli/traceViewer/web/ui/networkTab.css rename to src/web/traceViewer/ui/networkTab.css diff --git a/src/cli/traceViewer/web/ui/networkTab.tsx b/src/web/traceViewer/ui/networkTab.tsx similarity index 94% rename from src/cli/traceViewer/web/ui/networkTab.tsx rename to src/web/traceViewer/ui/networkTab.tsx index 5462ab2ed3..2d41c69e22 100644 --- a/src/cli/traceViewer/web/ui/networkTab.tsx +++ b/src/web/traceViewer/ui/networkTab.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { ActionEntry } from '../../traceModel'; +import { ActionEntry } from '../../../cli/traceViewer/traceModel'; import './networkTab.css'; import * as React from 'react'; import { NetworkResourceDetails } from './networkResourceDetails'; diff --git a/src/cli/traceViewer/web/ui/propertiesTabbedPane.css b/src/web/traceViewer/ui/propertiesTabbedPane.css similarity index 100% rename from src/cli/traceViewer/web/ui/propertiesTabbedPane.css rename to src/web/traceViewer/ui/propertiesTabbedPane.css diff --git a/src/cli/traceViewer/web/ui/propertiesTabbedPane.tsx b/src/web/traceViewer/ui/propertiesTabbedPane.tsx similarity index 98% rename from src/cli/traceViewer/web/ui/propertiesTabbedPane.tsx rename to src/web/traceViewer/ui/propertiesTabbedPane.tsx index f5846c2e2c..48f4110fa3 100644 --- a/src/cli/traceViewer/web/ui/propertiesTabbedPane.tsx +++ b/src/web/traceViewer/ui/propertiesTabbedPane.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { ActionEntry } from '../../traceModel'; +import { ActionEntry } from '../../../cli/traceViewer/traceModel'; import { Boundaries, Size } from '../geometry'; import { NetworkTab } from './networkTab'; import { SourceTab } from './sourceTab'; diff --git a/src/cli/traceViewer/web/ui/sourceTab.css b/src/web/traceViewer/ui/sourceTab.css similarity index 100% rename from src/cli/traceViewer/web/ui/sourceTab.css rename to src/web/traceViewer/ui/sourceTab.css diff --git a/src/cli/traceViewer/web/ui/sourceTab.tsx b/src/web/traceViewer/ui/sourceTab.tsx similarity index 96% rename from src/cli/traceViewer/web/ui/sourceTab.tsx rename to src/web/traceViewer/ui/sourceTab.tsx index 4f8a28bf5d..0f47f90b04 100644 --- a/src/cli/traceViewer/web/ui/sourceTab.tsx +++ b/src/web/traceViewer/ui/sourceTab.tsx @@ -14,12 +14,12 @@ * limitations under the License. */ -import { ActionEntry } from '../../traceModel'; +import { ActionEntry } from '../../../cli/traceViewer/traceModel'; import * as React from 'react'; import { useAsyncMemo } from './helpers'; import './sourceTab.css'; -import '../../../../third_party/highlightjs/highlightjs/tomorrow.css'; -import * as highlightjs from '../../../../third_party/highlightjs/highlightjs'; +import '../../../third_party/highlightjs/highlightjs/tomorrow.css'; +import * as highlightjs from '../../../third_party/highlightjs/highlightjs'; type StackInfo = string | { frames: { diff --git a/src/cli/traceViewer/web/ui/timeline.css b/src/web/traceViewer/ui/timeline.css similarity index 100% rename from src/cli/traceViewer/web/ui/timeline.css rename to src/web/traceViewer/ui/timeline.css diff --git a/src/cli/traceViewer/web/ui/timeline.tsx b/src/web/traceViewer/ui/timeline.tsx similarity index 99% rename from src/cli/traceViewer/web/ui/timeline.tsx rename to src/web/traceViewer/ui/timeline.tsx index 90a2d3d63d..5abccf5f63 100644 --- a/src/cli/traceViewer/web/ui/timeline.tsx +++ b/src/web/traceViewer/ui/timeline.tsx @@ -15,7 +15,7 @@ limitations under the License. */ -import { ContextEntry, InterestingPageEvent, ActionEntry, trace } from '../../traceModel'; +import { ContextEntry, InterestingPageEvent, ActionEntry, trace } from '../../../cli/traceViewer/traceModel'; import './timeline.css'; import { Boundaries } from '../geometry'; import * as React from 'react'; diff --git a/src/cli/traceViewer/web/ui/workbench.css b/src/web/traceViewer/ui/workbench.css similarity index 100% rename from src/cli/traceViewer/web/ui/workbench.css rename to src/web/traceViewer/ui/workbench.css diff --git a/src/cli/traceViewer/web/ui/workbench.tsx b/src/web/traceViewer/ui/workbench.tsx similarity index 96% rename from src/cli/traceViewer/web/ui/workbench.tsx rename to src/web/traceViewer/ui/workbench.tsx index bf7ddf4877..a489831a40 100644 --- a/src/cli/traceViewer/web/ui/workbench.tsx +++ b/src/web/traceViewer/ui/workbench.tsx @@ -14,14 +14,13 @@ limitations under the License. */ -import { ActionEntry, TraceModel } from '../../traceModel'; +import { ActionEntry, TraceModel } from '../../../cli/traceViewer/traceModel'; import { ActionList } from './actionList'; import { PropertiesTabbedPane } from './propertiesTabbedPane'; import { Timeline } from './timeline'; import './workbench.css'; import * as React from 'react'; import { ContextSelector } from './contextSelector'; -import { GlobalStyles } from '../styles'; export const Workbench: React.FunctionComponent<{ traceModel: TraceModel, @@ -42,7 +41,6 @@ export const Workbench: React.FunctionComponent<{ const boundaries = { minimum: context.startTime, maximum: context.endTime }; return
-
🎭
Playwright
diff --git a/src/cli/traceViewer/web/web.webpack.config.js b/src/web/traceViewer/webpack.config.js similarity index 92% rename from src/cli/traceViewer/web/web.webpack.config.js rename to src/web/traceViewer/webpack.config.js index 1707c02f55..9220f51aad 100644 --- a/src/cli/traceViewer/web/web.webpack.config.js +++ b/src/web/traceViewer/webpack.config.js @@ -13,7 +13,7 @@ module.exports = { output: { globalObject: 'self', filename: '[name].bundle.js', - path: path.resolve(__dirname, '../../../../lib/cli/traceViewer/web') + path: path.resolve(__dirname, '../../../lib/web/traceViewer') }, module: { rules: [ diff --git a/src/cli/traceViewer/web/types.d.ts b/src/web/types.d.ts similarity index 100% rename from src/cli/traceViewer/web/types.d.ts rename to src/web/types.d.ts diff --git a/utils/build/build.js b/utils/build/build.js index 5a38d8a49b..6d772ddb4a 100644 --- a/utils/build/build.js +++ b/utils/build/build.js @@ -70,7 +70,8 @@ const webPackFiles = [ 'src/server/injected/utilityScript.webpack.config.js', 'src/server/supplements/injected/consoleApi.webpack.config.js', 'src/server/supplements/injected/recorder.webpack.config.js', - 'src/cli/traceViewer/web/web.webpack.config.js', + 'src/web/traceViewer/webpack.config.js', + 'src/web/recorder/webpack.config.js', ]; for (const file of webPackFiles) { steps.push({ diff --git a/utils/check_deps.js b/utils/check_deps.js index 52836d051a..235b0d21e9 100644 --- a/utils/check_deps.js +++ b/utils/check_deps.js @@ -143,7 +143,10 @@ DEPS['src/cli/driver.ts'] = DEPS['src/inprocess.ts'] = DEPS['src/browserServerIm // Tracing is a client/server plugin, nothing should depend on it. DEPS['src/trace/'] = ['src/utils/', 'src/client/**', 'src/server/**']; - +DEPS['src/web/'] = []; +DEPS['src/web/recorder/'] = ['src/web/']; +DEPS['src/web/traceViewer/'] = ['src/web/', 'src/cli/traceViewer/']; +DEPS['src/web/traceViewer/ui/'] = ['src/web/traceViewer/', 'src/web/', 'src/cli/traceViewer/', 'src/trace/']; // The service is a cross-cutting feature, and so it depends on a bunch of things. DEPS['src/remote/'] = ['src/client/', 'src/debug/', 'src/dispatchers/', 'src/server/', 'src/server/supplements/', 'src/server/electron/', 'src/trace/']; DEPS['src/service.ts'] = ['src/remote/'];