feat(ui): more recorder uis (#5208)

This commit is contained in:
Pavel Feldman 2021-01-28 14:25:10 -08:00 committed by GitHub
parent f8fbfe28fa
commit 79e00e4911
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 338 additions and 535 deletions

View File

@ -1,7 +1,6 @@
module.exports = { module.exports = {
"stories": [ "stories": [
"../src/web/traceViewer/ui/*.stories.tsx", "../src/web/**/*.stories.tsx",
"../src/web/components/*.stories.tsx",
], ],
"addons": [ "addons": [
"@storybook/addon-links", "@storybook/addon-links",

View File

@ -4,11 +4,30 @@ import { applyTheme } from '../src/web/theme';
export const parameters = { export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" }, actions: { argTypesRegex: "^on[A-Z].*" },
viewport: {
viewports: {
recorder: {
name: 'recorder',
styles: {
width: '800px',
height: '600px',
},
},
traceViewer: {
name: 'traceViewer',
styles: {
width: '1024px',
height: '768px',
},
},
},
defaultViewport: 'desktop'
}
} }
addDecorator(storyFn => { addDecorator(storyFn => {
applyTheme(); applyTheme();
return <div style={{backgroundColor: 'var(--background)'}}> return <div style={{backgroundColor: 'var(--background)', display: 'flex'}}>
{storyFn()} {storyFn()}
</div> </div>
}); });

View File

@ -0,0 +1,88 @@
/*
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.
*/
export function exampleText() {
return `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();
})();`;
}

View File

@ -14,7 +14,10 @@
limitations under the License. limitations under the License.
*/ */
.pw-source { .source {
display: flex;
flex: auto;
flex-direction: column;
white-space: pre; white-space: pre;
overflow: auto; overflow: auto;
font-family: var(--monospace-font); font-family: var(--monospace-font);
@ -23,14 +26,20 @@
background: white; background: white;
} }
.pw-source-line { .source-line {
display: flex; display: flex;
flex: none;
} }
.pw-source-line-number { .source-line-number {
color: #555;
padding: 0 8px; padding: 0 8px;
width: 30px; width: 30px;
text-align: right; text-align: right;
background: #edebe9; background: #edebe9;
user-select: none; user-select: none;
} }
.source-line-highlighted {
background-color: #ffc0cb7f;
}

View File

@ -17,84 +17,27 @@
import { Story, Meta } from '@storybook/react/types-6-0'; import { Story, Meta } from '@storybook/react/types-6-0';
import React from 'react'; import React from 'react';
import { Source, SourceProps } from './source'; import { Source, SourceProps } from './source';
import { exampleText } from './exampleText';
export default { export default {
title: 'Components/Source', title: 'Components/Source',
component: Source, component: Source,
parameters: {
viewport: {
defaultViewport: 'recorder'
}
}
} as Meta; } as Meta;
const Template: Story<SourceProps> = args => <Source {...args} />; const Template: Story<SourceProps> = args => <Source {...args} />;
export const Primary = Template.bind({}); export const Primary = Template.bind({});
Primary.args = { Primary.args = {
text: `const { chromium, devices } = require('.'); text: exampleText()
};
(async () => {
const browser = await chromium.launch({ export const HighlightLine = Template.bind({});
headless: false HighlightLine.args = {
}); text: exampleText(),
const context = await browser.newContext({ highlightedLine: 11
// ...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();
})();`
}; };

View File

@ -16,30 +16,43 @@
import './source.css'; import './source.css';
import * as React from 'react'; import * as React from 'react';
import highlightjs from '../../third_party/highlightjs/highlightjs'; import * as highlightjs from '../../third_party/highlightjs/highlightjs';
import '../../third_party/highlightjs/highlightjs/tomorrow.css'; import '../../third_party/highlightjs/highlightjs/tomorrow.css';
export interface SourceProps { export interface SourceProps {
text: string, text: string,
targetLine: number highlightedLine?: number
} }
export const Source: React.FC<SourceProps> = ({ export const Source: React.FC<SourceProps> = ({
text = '', text = '',
highlightedLine = -1
}) => { }) => {
const result = []; const lines = React.useMemo<string[]>(() => {
let continuation: any; const result = [];
for (const line of text.split('\n')) { let continuation: any;
const highlighted = highlightjs.highlight('javascript', line, true, continuation); for (const line of text.split('\n')) {
continuation = highlighted.top; const highlighted = highlightjs.highlight('javascript', line, true, continuation);
result.push(highlighted.value); continuation = highlighted.top;
} result.push(highlighted.value);
}
return result;
}, [text]);
return <div className='pw-source'>{
result.map((markup, index) => { const highlightedLineRef = React.createRef<HTMLDivElement>();
return <div key={index} className='pw-source-line'> React.useLayoutEffect(() => {
<div className='pw-source-line-number'>{index + 1}</div> if (highlightedLine && highlightedLineRef.current)
<div className='pw-source-code' dangerouslySetInnerHTML={{ __html: markup }}></div> highlightedLineRef.current.scrollIntoView({ block: 'center', inline: 'nearest' });
}, [highlightedLineRef]);
return <div className='source'>{
lines.map((markup, index) => {
const isHighlighted = index === highlightedLine;
const className = isHighlighted ? 'source-line source-line-highlighted' : 'source-line';
return <div key={index} className={className} ref={isHighlighted ? highlightedLineRef : null}>
<div className='source-line-number'>{index + 1}</div>
<div className='source-code' dangerouslySetInnerHTML={{ __html: markup }}></div>
</div>; </div>;
}) })
}</div> }</div>

View File

@ -14,10 +14,17 @@
limitations under the License. limitations under the License.
*/ */
.pw-toolbar { .toolbar {
display: flex;
box-shadow: rgba(0, 0, 0, 0.1) 0px -1px 0px 0px inset; box-shadow: rgba(0, 0, 0, 0.1) 0px -1px 0px 0px inset;
background: rgb(255, 255, 255); background: rgb(255, 255, 255);
height: 40px; height: 40px;
align-items: center; align-items: center;
padding-right: 10px; padding-right: 10px;
flex: none;
}
.toolbar-linewrap {
display: block;
flex: auto;
} }

View File

@ -17,442 +17,71 @@
import { Story, Meta } from '@storybook/react/types-6-0'; import { Story, Meta } from '@storybook/react/types-6-0';
import React from 'react'; import React from 'react';
import { Toolbar, ToolbarProps } from './toolbar'; import { Toolbar, ToolbarProps } from './toolbar';
import { ToolbarButton } from './toolbarButton';
export default { export default {
title: 'Components/Toolbar', title: 'Components/Toolbar',
component: Toolbar, component: Toolbar,
} as Meta; } as Meta;
const Template: Story<ToolbarProps> = args => <Toolbar {...args} />; const Template: Story<ToolbarProps> = () => <Toolbar>
<ToolbarButton icon="clone" title="Copy" onClick={() => {}}></ToolbarButton>
<ToolbarButton icon="trashcan" title="Erase" onClick={() => {}}></ToolbarButton>
<ToolbarButton icon="close" title="Close" onClick={() => {}}></ToolbarButton>
</Toolbar>;
export const Primary = Template.bind({}); 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({}); const AllTemplate: Story = () => <Toolbar lineWrap={true}>
All.args = { {[
buttons: [ 'add', 'plus', 'gist-new', 'repo-create', 'lightbulb', 'light-bulb', 'repo', 'repo-delete', 'gist-fork', 'repo-forked',
{ title: 'Close', icon: 'add', onClose: () => {} }, 'git-pull-request', 'git-pull-request-abandoned', 'record-keys', 'keyboard', 'tag', 'tag-add', 'tag-remove', 'person',
{ title: 'Close', icon: 'plus', onClose: () => {} }, 'person-add', 'person-follow', 'person-outline', 'person-filled', 'git-branch', 'git-branch-create',
{ title: 'Close', icon: 'gist-new', onClose: () => {} }, 'git-branch-delete', 'source-control', 'mirror', 'mirror-public', 'star', 'star-add', 'star-delete', 'star-empty',
{ title: 'Close', icon: 'repo-create', onClose: () => {} }, 'comment', 'comment-add', 'alert', 'warning', 'search', 'search-save', 'log-out', 'sign-out', 'log-in', 'sign-in',
{ title: 'Close', icon: 'lightbulb', onClose: () => {} }, 'eye', 'eye-unwatch', 'eye-watch', 'circle-filled', 'primitive-dot', 'close-dirty', 'debug-breakpoint',
{ title: 'Close', icon: 'light-bulb', onClose: () => {} }, 'debug-breakpoint-disabled', 'debug-hint', 'primitive-square', 'edit', 'pencil', 'info', 'issue-opened',
{ title: 'Close', icon: 'repo', onClose: () => {} }, 'gist-private', 'git-fork-private', 'lock', 'mirror-private', 'close', 'remove-close', 'x', 'repo-sync',
{ title: 'Close', icon: 'repo-delete', onClose: () => {} }, 'sync', 'clone', 'desktop-download', 'beaker', 'microscope', 'vm', 'device-desktop', 'file', 'file-text', 'more',
{ title: 'Close', icon: 'gist-fork', onClose: () => {} }, 'ellipsis', 'kebab-horizontal', 'mail-reply', 'reply', 'organization', 'organization-filled', 'organization-outline',
{ title: 'Close', icon: 'repo-forked', onClose: () => {} }, 'new-file', 'file-add', 'new-folder', 'file-directory-create', 'trash', 'trashcan', 'history', 'clock', 'folder',
{ title: 'Close', icon: 'git-pull-request', onClose: () => {} }, 'file-directory', 'symbol-folder', 'logo-github', 'mark-github', 'github', 'terminal', 'console', 'repl', 'zap',
{ title: 'Close', icon: 'git-pull-request-abandoned', onClose: () => {} }, 'symbol-event', 'error', 'stop', 'variable', 'symbol-variable', 'array', 'symbol-array', 'symbol-module',
{ title: 'Close', icon: 'record-keys', onClose: () => {} }, 'symbol-package', 'symbol-namespace', 'symbol-object', 'symbol-method', 'symbol-function', 'symbol-constructor',
{ title: 'Close', icon: 'keyboard', onClose: () => {} }, 'symbol-boolean', 'symbol-null', 'symbol-numeric', 'symbol-number', 'symbol-structure', 'symbol-struct', 'symbol-parameter',
{ title: 'Close', icon: 'tag', onClose: () => {} }, 'symbol-type-parameter', 'symbol-key', 'symbol-text', 'symbol-reference', 'go-to-file', 'symbol-enum', 'symbol-value', 'symbol-ruler',
{ title: 'Close', icon: 'tag-add', onClose: () => {} }, 'symbol-unit', 'activate-breakpoints', 'archive', 'arrow-both', 'arrow-down', 'arrow-left', 'arrow-right', 'arrow-small-down', 'arrow-small-left',
{ title: 'Close', icon: 'tag-remove', onClose: () => {} }, 'arrow-small-right', 'arrow-small-up', 'arrow-up', 'bell', 'bold', 'book', 'bookmark', 'debug-breakpoint-conditional-unverified',
{ title: 'Close', icon: 'person', onClose: () => {} }, 'debug-breakpoint-conditional', 'debug-breakpoint-conditional-disabled', 'debug-breakpoint-data-unverified', 'debug-breakpoint-data',
{ title: 'Close', icon: 'person-add', onClose: () => {} }, 'debug-breakpoint-data-disabled', 'debug-breakpoint-log-unverified', 'debug-breakpoint-log', 'debug-breakpoint-log-disabled', 'briefcase',
{ title: 'Close', icon: 'person-follow', onClose: () => {} }, 'broadcast', 'browser', 'bug', 'calendar', 'case-sensitive', 'check', 'checklist', 'chevron-down', 'chevron-left', 'chevron-right', 'chevron-up',
{ title: 'Close', icon: 'person-outline', onClose: () => {} }, 'chrome-close', 'chrome-maximize', 'chrome-minimize', 'chrome-restore', 'circle-outline', 'debug-breakpoint-unverified', 'circle-slash',
{ title: 'Close', icon: 'person-filled', onClose: () => {} }, 'circuit-board', 'clear-all', 'clippy', 'close-all', 'cloud-download', 'cloud-upload', 'code', 'collapse-all', 'color-mode', 'comment-discussion',
{ title: 'Close', icon: 'git-branch', onClose: () => {} }, 'compare-changes', 'credit-card', 'dash', 'dashboard', 'database', 'debug-continue', 'debug-disconnect', 'debug-pause', 'debug-restart',
{ title: 'Close', icon: 'git-branch-create', onClose: () => {} }, 'debug-start', 'debug-step-into', 'debug-step-out', 'debug-step-over', 'debug-stop', 'debug', 'device-camera-video', 'device-camera',
{ title: 'Close', icon: 'git-branch-delete', onClose: () => {} }, 'device-mobile', 'diff-added', 'diff-ignored', 'diff-modified', 'diff-removed', 'diff-renamed', 'diff', 'discard', 'editor-layout',
{ title: 'Close', icon: 'source-control', onClose: () => {} }, 'empty-window', 'exclude', 'extensions', 'eye-closed', 'file-binary', 'file-code', 'file-media', 'file-pdf', 'file-submodule',
{ title: 'Close', icon: 'mirror', onClose: () => {} }, 'file-symlink-directory', 'file-symlink-file', 'file-zip', 'files', 'filter', 'flame', 'fold-down', 'fold-up', 'fold', 'folder-active',
{ title: 'Close', icon: 'mirror-public', onClose: () => {} }, 'folder-opened', 'gear', 'gift', 'gist-secret', 'gist', 'git-commit', 'git-compare', 'git-merge', 'github-action', 'github-alt', 'globe',
{ title: 'Close', icon: 'star', onClose: () => {} }, 'grabber', 'graph', 'gripper', 'heart', 'home', 'horizontal-rule', 'hubot', 'inbox', 'issue-closed', 'issue-reopened', 'issues', 'italic',
{ title: 'Close', icon: 'star-add', onClose: () => {} }, 'jersey', 'json', 'kebab-vertical', 'key', 'law', 'lightbulb-autofix', 'link-external', 'link', 'list-ordered', 'list-unordered', 'live-share',
{ title: 'Close', icon: 'star-delete', onClose: () => {} }, 'loading', 'location', 'mail-read', 'mail', 'markdown', 'megaphone', 'mention', 'milestone', 'mortar-board', 'move', 'multiple-windows', 'mute',
{ title: 'Close', icon: 'star-empty', onClose: () => {} }, 'no-newline', 'note', 'octoface', 'open-preview', 'package', 'paintcan', 'pin', 'play', 'run', 'plug', 'preserve-case', 'preview', 'project',
{ title: 'Close', icon: 'comment', onClose: () => {} }, 'pulse', 'question', 'quote', 'radio-tower', 'reactions', 'references', 'refresh', 'regex', 'remote-explorer', 'remote', 'remove', 'replace-all',
{ title: 'Close', icon: 'comment-add', onClose: () => {} }, 'replace', 'repo-clone', 'repo-force-push', 'repo-pull', 'repo-push', 'report', 'request-changes', 'rocket', 'root-folder-opened', 'root-folder',
{ title: 'Close', icon: 'alert', onClose: () => {} }, 'rss', 'ruby', 'save-all', 'save-as', 'save', 'screen-full', 'screen-normal', 'search-stop', 'server', 'settings-gear', 'settings', 'shield',
{ title: 'Close', icon: 'warning', onClose: () => {} }, 'smiley', 'sort-precedence', 'split-horizontal', 'split-vertical', 'squirrel', 'star-full', 'star-half', 'symbol-class', 'symbol-color',
{ title: 'Close', icon: 'search', onClose: () => {} }, 'symbol-constant', 'symbol-enum-member', 'symbol-field', 'symbol-file', 'symbol-interface', 'symbol-keyword', 'symbol-misc', 'symbol-operator',
{ title: 'Close', icon: 'search-save', onClose: () => {} }, 'symbol-property', 'wrench', 'wrench-subaction', 'symbol-snippet', 'tasklist', 'telescope', 'text-size', 'three-bars', 'thumbsdown', 'thumbsup',
{ title: 'Close', icon: 'log-out', onClose: () => {} }, 'tools', 'triangle-down', 'triangle-left', 'triangle-right', 'triangle-up', 'twitter', 'unfold', 'unlock', 'unmute', 'unverified', 'verified',
{ title: 'Close', icon: 'sign-out', onClose: () => {} }, 'versions', 'vm-active', 'vm-outline', 'vm-running', 'watch', 'whitespace', 'whole-word', 'window', 'word-wrap', 'zoom-in', 'zoom-out',
{ title: 'Close', icon: 'log-in', onClose: () => {} }, 'list-filter', 'list-flat', 'list-selection', 'selection', 'list-tree', 'debug-breakpoint-function-unverified', 'debug-breakpoint-function',
{ title: 'Close', icon: 'sign-in', onClose: () => {} }, 'debug-breakpoint-function-disabled', 'debug-stackframe-active', 'debug-stackframe-dot', 'debug-stackframe', 'debug-stackframe-focused',
{ title: 'Close', icon: 'eye', onClose: () => {} }, 'debug-breakpoint-unsupported', 'symbol-string', 'debug-reverse-continue', 'debug-step-back', 'debug-restart-frame', 'call-incoming',
{ title: 'Close', icon: 'eye-unwatch', onClose: () => {} }, 'call-outgoing', 'menu', 'expand-all', 'feedback', 'group-by-ref-type', 'ungroup-by-ref-type', 'account', 'bell-dot', 'debug-console', 'library',
{ title: 'Close', icon: 'eye-watch', onClose: () => {} }, 'output', 'run-all', 'sync-ignored', 'pinned', 'github-inverted', 'debug-alt', 'server-process', 'server-environment', 'pass', 'stop-circle',
{ title: 'Close', icon: 'circle-filled', onClose: () => {} }, 'play-circle', 'record', 'debug-alt-small', 'vm-connect', 'cloud', 'merge', 'export', 'graph-left', 'magnet',
{ title: 'Close', icon: 'primitive-dot', onClose: () => {} }, ].map(icon => <ToolbarButton icon={icon} title={icon} onClick={() => {}}></ToolbarButton>)}
{ title: 'Close', icon: 'close-dirty', onClose: () => {} }, </Toolbar>;
{ 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: () => {} },
] export const AllButtons = AllTemplate.bind({});
};

View File

@ -1,7 +1,7 @@
/* /*
Copyright (c) Microsoft Corporation. Copyright (c) Microsoft Corporation.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the 'License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -16,16 +16,15 @@
import './toolbar.css'; import './toolbar.css';
import * as React from 'react'; import * as React from 'react';
import { ToolbarButton, ToolbarButtonProps } from './toolbarButton';
export interface ToolbarProps { export interface ToolbarProps {
buttons: ToolbarButtonProps[], lineWrap?: boolean
icon: string,
onClick: () => void
} }
export const Toolbar: React.FC<ToolbarProps> = ({ export const Toolbar: React.FC<ToolbarProps> = ({
buttons = [], lineWrap = false,
children
}) => { }) => {
return <div className="pw-toolbar">{buttons.map(props => <ToolbarButton key={props.title} {...props}></ToolbarButton>)}</div>; const className = lineWrap ? 'toolbar toolbar-linewrap' : 'toolbar';
return <div className={className}>{children}</div>;
}; };

View File

@ -14,7 +14,7 @@
limitations under the License. limitations under the License.
*/ */
.pw-toolbar-button { .toolbar-button {
border: none; border: none;
outline: none; outline: none;
color: #999; color: #999;
@ -25,6 +25,6 @@
cursor: pointer; cursor: pointer;
} }
.pw-toolbar-button:hover { .toolbar-button:hover {
color: #1ea7fd; color: #1ea7fd;
} }

View File

@ -29,6 +29,6 @@ export const ToolbarButton: React.FC<ToolbarButtonProps> = ({
icon = '', icon = '',
onClick = () => {}, onClick = () => {},
}) => { }) => {
const className = `pw-toolbar-button codicon codicon-${icon}`; const className = `toolbar-button codicon codicon-${icon}`;
return <button className={className} onClick={onClick} title={title}></button>; return <button className={className} onClick={onClick} title={title}></button>;
}; };

View File

@ -19,6 +19,7 @@ import * as React from 'react';
import * as ReactDOM from 'react-dom'; import * as ReactDOM from 'react-dom';
import { applyTheme } from '../theme'; import { applyTheme } from '../theme';
import '../common.css'; import '../common.css';
import { Recorder } from './recorder';
declare global { declare global {
interface Window { interface Window {
@ -27,6 +28,5 @@ declare global {
(async () => { (async () => {
applyTheme(); applyTheme();
ReactDOM.render(<div> ReactDOM.render(<Recorder text=""/>, document.querySelector('#root'));
</div>, document.querySelector('#root'));
})(); })();

View File

@ -0,0 +1,21 @@
/*
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.
*/
.recorder {
display: flex;
flex-direction: column;
flex: auto;
}

View File

@ -0,0 +1,37 @@
/*
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 { Recorder, RecorderProps } from './recorder';
import { exampleText } from '../components/exampleText';
export default {
title: 'Recorder/Recorder',
component: Recorder,
parameters: {
viewport: {
defaultViewport: 'recorder'
}
}
} as Meta;
const Template: Story<RecorderProps> = args => <Recorder {...args} />;
export const Primary = Template.bind({});
Primary.args = {
text: exampleText()
};

View File

@ -0,0 +1,39 @@
/*
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 './recorder.css';
import * as React from 'react';
import { Toolbar } from '../components/toolbar';
import { ToolbarButton } from '../components/toolbarButton';
import { Source } from '../components/source';
export interface RecorderProps {
text: string
}
export const Recorder: React.FC<RecorderProps> = ({
text
}) => {
return <div className="recorder">
<Toolbar>
<ToolbarButton icon="clone" title="Copy" onClick={() => {}}></ToolbarButton>
<ToolbarButton icon="trashcan" title="Erase" onClick={() => {}}></ToolbarButton>
<div style={{flex: "auto"}}></div>
<ToolbarButton icon="close" title="Close" onClick={() => {}}></ToolbarButton>
</Toolbar>
<Source text={text}></Source>
</div>;
};

View File

@ -144,7 +144,7 @@ DEPS['src/cli/driver.ts'] = DEPS['src/inprocess.ts'] = DEPS['src/browserServerIm
// Tracing is a client/server plugin, nothing should depend on it. // Tracing is a client/server plugin, nothing should depend on it.
DEPS['src/trace/'] = ['src/utils/', 'src/client/**', 'src/server/**']; DEPS['src/trace/'] = ['src/utils/', 'src/client/**', 'src/server/**'];
DEPS['src/web/'] = []; DEPS['src/web/'] = [];
DEPS['src/web/recorder/'] = ['src/web/']; DEPS['src/web/recorder/'] = ['src/web/', 'src/web/components/'];
DEPS['src/web/traceViewer/'] = ['src/web/', 'src/cli/traceViewer/']; DEPS['src/web/traceViewer/'] = ['src/web/', 'src/cli/traceViewer/'];
DEPS['src/web/traceViewer/ui/'] = ['src/web/traceViewer/', 'src/web/', 'src/cli/traceViewer/', 'src/trace/']; 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. // The service is a cross-cutting feature, and so it depends on a bunch of things.