From 5fdf97658ef080c1e10c45ba529c309f93ad4914 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Thu, 1 Aug 2024 11:53:04 -0700 Subject: [PATCH] cherry-pick(#31945): feat(ui-mode): add annotations tab (#31968) image --- packages/html-reporter/src/links.tsx | 2 +- packages/html-reporter/src/testCaseView.tsx | 2 +- .../trace-viewer/src/ui/annotationsTab.css | 28 +++++++++++++ .../trace-viewer/src/ui/annotationsTab.tsx | 39 +++++++++++++++++++ .../trace-viewer/src/ui/uiModeTraceView.tsx | 1 + packages/trace-viewer/src/ui/workbench.tsx | 15 ++++++- .../src/renderUtils.tsx | 0 7 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 packages/trace-viewer/src/ui/annotationsTab.css create mode 100644 packages/trace-viewer/src/ui/annotationsTab.tsx rename packages/{html-reporter => web}/src/renderUtils.tsx (100%) diff --git a/packages/html-reporter/src/links.tsx b/packages/html-reporter/src/links.tsx index 42b9f9b5b9..a4d86da294 100644 --- a/packages/html-reporter/src/links.tsx +++ b/packages/html-reporter/src/links.tsx @@ -20,7 +20,7 @@ import * as icons from './icons'; import { TreeItem } from './treeItem'; import { CopyToClipboard } from './copyToClipboard'; import './links.css'; -import { linkifyText } from './renderUtils'; +import { linkifyText } from '@web/renderUtils'; export function navigate(href: string) { window.history.pushState({}, '', href); diff --git a/packages/html-reporter/src/testCaseView.tsx b/packages/html-reporter/src/testCaseView.tsx index f4d76653cf..a020572717 100644 --- a/packages/html-reporter/src/testCaseView.tsx +++ b/packages/html-reporter/src/testCaseView.tsx @@ -23,7 +23,7 @@ import { ProjectLink } from './links'; import { statusIcon } from './statusIcon'; import './testCaseView.css'; import { TestResultView } from './testResultView'; -import { linkifyText } from './renderUtils'; +import { linkifyText } from '@web/renderUtils'; import { hashStringToInt, msToString } from './utils'; export const TestCaseView: React.FC<{ diff --git a/packages/trace-viewer/src/ui/annotationsTab.css b/packages/trace-viewer/src/ui/annotationsTab.css new file mode 100644 index 0000000000..c32cc6f63b --- /dev/null +++ b/packages/trace-viewer/src/ui/annotationsTab.css @@ -0,0 +1,28 @@ +/* + 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. +*/ + +.annotations-tab { + flex: auto; + line-height: 24px; + white-space: pre; + overflow: auto; + user-select: text; +} + +.annotation-item { + margin: 4px 8px; + text-wrap: wrap; +} diff --git a/packages/trace-viewer/src/ui/annotationsTab.tsx b/packages/trace-viewer/src/ui/annotationsTab.tsx new file mode 100644 index 0000000000..5a2a34c9f1 --- /dev/null +++ b/packages/trace-viewer/src/ui/annotationsTab.tsx @@ -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 * as React from 'react'; +import './annotationsTab.css'; +import { PlaceholderPanel } from './placeholderPanel'; +import { linkifyText } from '@web/renderUtils'; + +type Annotation = { type: string; description?: string; }; + +export const AnnotationsTab: React.FunctionComponent<{ + annotations: Annotation[], +}> = ({ annotations }) => { + + if (!annotations.length) + return ; + + return
+ {annotations.map((annotation, i) => { + return
+ {annotation.type} + {annotation.description && : {linkifyText(annotation.description)}} +
; + })} +
; +}; diff --git a/packages/trace-viewer/src/ui/uiModeTraceView.tsx b/packages/trace-viewer/src/ui/uiModeTraceView.tsx index a652904683..8cfa39a203 100644 --- a/packages/trace-viewer/src/ui/uiModeTraceView.tsx +++ b/packages/trace-viewer/src/ui/uiModeTraceView.tsx @@ -100,6 +100,7 @@ export const TraceView: React.FC<{ fallbackLocation={item.testFile} isLive={model?.isLive} status={item.treeItem?.status} + annotations={item.testCase?.annotations || []} onOpenExternally={onOpenExternally} revealSource={revealSource} />; diff --git a/packages/trace-viewer/src/ui/workbench.tsx b/packages/trace-viewer/src/ui/workbench.tsx index 6f53cb76c6..6be68b8755 100644 --- a/packages/trace-viewer/src/ui/workbench.tsx +++ b/packages/trace-viewer/src/ui/workbench.tsx @@ -33,6 +33,7 @@ import type { TabbedPaneTabModel } from '@web/components/tabbedPane'; import { Timeline } from './timeline'; import { MetadataView } from './metadataView'; import { AttachmentsTab } from './attachmentsTab'; +import { AnnotationsTab } from './annotationsTab'; import type { Boundaries } from '../geometry'; import { InspectorTab } from './inspectorTab'; import { ToolbarButton } from '@web/components/toolbarButton'; @@ -52,12 +53,13 @@ export const Workbench: React.FunctionComponent<{ onSelectionChanged?: (action: modelUtil.ActionTraceEventInContext) => void, isLive?: boolean, status?: UITestStatus, + annotations?: { type: string; description?: string; }[]; inert?: boolean, showRouteActionsSetting?: Setting, openPage?: (url: string, target?: string) => Window | any, onOpenExternally?: (location: modelUtil.SourceLocation) => void, revealSource?: boolean, -}> = ({ showRouteActionsSetting, model, showSourcesFirst, rootDir, fallbackLocation, initialSelection, onSelectionChanged, isLive, status, inert, openPage, onOpenExternally, revealSource }) => { +}> = ({ showRouteActionsSetting, model, showSourcesFirst, rootDir, fallbackLocation, initialSelection, onSelectionChanged, isLive, status, annotations, inert, openPage, onOpenExternally, revealSource }) => { const [selectedAction, setSelectedActionImpl] = React.useState(undefined); const [revealedStack, setRevealedStack] = React.useState(undefined); const [highlightedAction, setHighlightedAction] = React.useState(); @@ -227,6 +229,17 @@ export const Workbench: React.FunctionComponent<{ sourceTab, attachmentsTab, ]; + + if (annotations !== undefined) { + const annotationsTab: TabbedPaneTabModel = { + id: 'annotations', + title: 'Annotations', + count: annotations.length, + render: () => + }; + tabs.push(annotationsTab); + } + if (showSourcesFirst) { const sourceTabIndex = tabs.indexOf(sourceTab); tabs.splice(sourceTabIndex, 1); diff --git a/packages/html-reporter/src/renderUtils.tsx b/packages/web/src/renderUtils.tsx similarity index 100% rename from packages/html-reporter/src/renderUtils.tsx rename to packages/web/src/renderUtils.tsx