2021-01-08 01:15:34 +01:00
|
|
|
/*
|
|
|
|
|
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.
|
|
|
|
|
*/
|
|
|
|
|
|
2022-03-25 22:12:00 +01:00
|
|
|
import { SplitView } from '@web/components/splitView';
|
|
|
|
|
import * as React from 'react';
|
2021-01-08 01:15:34 +01:00
|
|
|
import { ActionList } from './actionList';
|
2021-07-02 23:33:38 +02:00
|
|
|
import { CallTab } from './callTab';
|
2021-07-01 23:31:20 +02:00
|
|
|
import { ConsoleTab } from './consoleTab';
|
2023-07-10 21:56:56 +02:00
|
|
|
import type * as modelUtil from './modelUtil';
|
2023-05-20 00:18:18 +02:00
|
|
|
import type { ActionTraceEventInContext, MultiTraceModel } from './modelUtil';
|
2022-03-25 22:12:00 +01:00
|
|
|
import { NetworkTab } from './networkTab';
|
|
|
|
|
import { SnapshotTab } from './snapshotTab';
|
|
|
|
|
import { SourceTab } from './sourceTab';
|
2023-02-17 20:19:53 +01:00
|
|
|
import { TabbedPane } from '@web/components/tabbedPane';
|
2023-03-07 23:24:50 +01:00
|
|
|
import type { TabbedPaneTabModel } from '@web/components/tabbedPane';
|
2022-03-25 22:12:00 +01:00
|
|
|
import { Timeline } from './timeline';
|
2023-03-06 21:25:00 +01:00
|
|
|
import { MetadataView } from './metadataView';
|
2023-05-10 02:53:01 +02:00
|
|
|
import { AttachmentsTab } from './attachmentsTab';
|
2023-08-17 01:30:17 +02:00
|
|
|
import type { Boundaries } from '../geometry';
|
2021-01-08 01:15:34 +01:00
|
|
|
|
2023-02-16 16:59:21 +01:00
|
|
|
export const Workbench: React.FunctionComponent<{
|
2023-03-07 21:43:16 +01:00
|
|
|
model?: MultiTraceModel,
|
2023-03-11 07:52:31 +01:00
|
|
|
hideStackFrames?: boolean,
|
2023-03-11 20:43:33 +01:00
|
|
|
showSourcesFirst?: boolean,
|
2023-03-19 20:04:19 +01:00
|
|
|
rootDir?: string,
|
2023-05-09 03:51:27 +02:00
|
|
|
fallbackLocation?: modelUtil.SourceLocation,
|
2023-05-20 00:18:18 +02:00
|
|
|
initialSelection?: ActionTraceEventInContext,
|
|
|
|
|
onSelectionChanged?: (action: ActionTraceEventInContext) => void,
|
2023-05-19 00:52:44 +02:00
|
|
|
isLive?: boolean,
|
2023-06-02 00:49:48 +02:00
|
|
|
drawer?: 'bottom' | 'right',
|
2023-08-17 01:30:17 +02:00
|
|
|
}> = ({ model, hideStackFrames, showSourcesFirst, rootDir, fallbackLocation, initialSelection, onSelectionChanged, isLive, drawer }) => {
|
2023-05-20 00:18:18 +02:00
|
|
|
const [selectedAction, setSelectedAction] = React.useState<ActionTraceEventInContext | undefined>(undefined);
|
|
|
|
|
const [highlightedAction, setHighlightedAction] = React.useState<ActionTraceEventInContext | undefined>();
|
2023-02-16 16:59:21 +01:00
|
|
|
const [selectedNavigatorTab, setSelectedNavigatorTab] = React.useState<string>('actions');
|
2023-03-11 20:43:33 +01:00
|
|
|
const [selectedPropertiesTab, setSelectedPropertiesTab] = React.useState<string>(showSourcesFirst ? 'source' : 'call');
|
2023-03-07 21:43:16 +01:00
|
|
|
const activeAction = model ? highlightedAction || selectedAction : undefined;
|
2023-08-17 01:30:17 +02:00
|
|
|
const [selectedTime, setSelectedTime] = React.useState<Boundaries | undefined>();
|
2021-10-22 17:00:34 +02:00
|
|
|
|
2023-03-19 20:04:19 +01:00
|
|
|
const sources = React.useMemo(() => model?.sources || new Map(), [model]);
|
|
|
|
|
|
2023-03-11 02:01:30 +01:00
|
|
|
React.useEffect(() => {
|
2023-03-11 20:43:33 +01:00
|
|
|
if (selectedAction && model?.actions.includes(selectedAction))
|
2023-03-11 02:01:30 +01:00
|
|
|
return;
|
|
|
|
|
const failedAction = model?.actions.find(a => a.error);
|
2023-04-01 03:34:51 +02:00
|
|
|
if (initialSelection && model?.actions.includes(initialSelection))
|
|
|
|
|
setSelectedAction(initialSelection);
|
|
|
|
|
else if (failedAction)
|
2023-03-11 02:01:30 +01:00
|
|
|
setSelectedAction(failedAction);
|
2023-03-11 20:43:33 +01:00
|
|
|
else if (model?.actions.length)
|
|
|
|
|
setSelectedAction(model.actions[model.actions.length - 1]);
|
2023-04-01 03:34:51 +02:00
|
|
|
}, [model, selectedAction, setSelectedAction, setSelectedPropertiesTab, initialSelection]);
|
|
|
|
|
|
2023-05-20 00:18:18 +02:00
|
|
|
const onActionSelected = React.useCallback((action: ActionTraceEventInContext) => {
|
2023-04-01 03:34:51 +02:00
|
|
|
setSelectedAction(action);
|
|
|
|
|
onSelectionChanged?.(action);
|
|
|
|
|
}, [setSelectedAction, onSelectionChanged]);
|
2023-03-11 02:01:30 +01:00
|
|
|
|
2023-03-07 21:43:16 +01:00
|
|
|
const sdkLanguage = model?.sdkLanguage || 'javascript';
|
2021-07-02 05:46:56 +02:00
|
|
|
|
2023-03-11 20:43:33 +01:00
|
|
|
const callTab: TabbedPaneTabModel = {
|
|
|
|
|
id: 'call',
|
2023-05-13 04:15:31 +02:00
|
|
|
title: 'Call',
|
2023-03-11 20:43:33 +01:00
|
|
|
render: () => <CallTab action={activeAction} sdkLanguage={sdkLanguage} />
|
|
|
|
|
};
|
|
|
|
|
const sourceTab: TabbedPaneTabModel = {
|
|
|
|
|
id: 'source',
|
|
|
|
|
title: 'Source',
|
2023-03-19 20:04:19 +01:00
|
|
|
render: () => <SourceTab
|
|
|
|
|
action={activeAction}
|
|
|
|
|
sources={sources}
|
|
|
|
|
hideStackFrames={hideStackFrames}
|
|
|
|
|
rootDir={rootDir}
|
2023-05-09 03:51:27 +02:00
|
|
|
fallbackLocation={fallbackLocation} />
|
2023-03-11 20:43:33 +01:00
|
|
|
};
|
|
|
|
|
const consoleTab: TabbedPaneTabModel = {
|
|
|
|
|
id: 'console',
|
|
|
|
|
title: 'Console',
|
2023-08-17 01:30:17 +02:00
|
|
|
render: () => <ConsoleTab model={model} selectedTime={selectedTime} />
|
2023-03-11 20:43:33 +01:00
|
|
|
};
|
|
|
|
|
const networkTab: TabbedPaneTabModel = {
|
|
|
|
|
id: 'network',
|
|
|
|
|
title: 'Network',
|
2023-08-17 01:30:17 +02:00
|
|
|
render: () => <NetworkTab model={model} selectedTime={selectedTime} />
|
2023-03-11 20:43:33 +01:00
|
|
|
};
|
2023-05-10 02:53:01 +02:00
|
|
|
const attachmentsTab: TabbedPaneTabModel = {
|
|
|
|
|
id: 'attachments',
|
|
|
|
|
title: 'Attachments',
|
2023-07-10 21:56:56 +02:00
|
|
|
render: () => <AttachmentsTab model={model} />
|
2023-05-10 02:53:01 +02:00
|
|
|
};
|
2021-10-23 20:23:39 +02:00
|
|
|
|
2023-03-11 20:43:33 +01:00
|
|
|
const tabs: TabbedPaneTabModel[] = showSourcesFirst ? [
|
|
|
|
|
sourceTab,
|
|
|
|
|
consoleTab,
|
|
|
|
|
networkTab,
|
|
|
|
|
callTab,
|
2023-05-10 02:53:01 +02:00
|
|
|
attachmentsTab,
|
2023-03-11 20:43:33 +01:00
|
|
|
] : [
|
|
|
|
|
callTab,
|
|
|
|
|
consoleTab,
|
|
|
|
|
networkTab,
|
|
|
|
|
sourceTab,
|
2023-05-10 02:53:01 +02:00
|
|
|
attachmentsTab,
|
2023-03-11 20:43:33 +01:00
|
|
|
];
|
2021-10-23 20:23:39 +02:00
|
|
|
|
2023-08-17 01:30:17 +02:00
|
|
|
const { boundaries } = React.useMemo(() => {
|
|
|
|
|
const boundaries = { minimum: model?.startTime || 0, maximum: model?.endTime || 30000 };
|
|
|
|
|
if (boundaries.minimum > boundaries.maximum) {
|
|
|
|
|
boundaries.minimum = 0;
|
|
|
|
|
boundaries.maximum = 30000;
|
|
|
|
|
}
|
|
|
|
|
// Leave some nice free space on the right hand side.
|
|
|
|
|
boundaries.maximum += (boundaries.maximum - boundaries.minimum) / 20;
|
|
|
|
|
return { boundaries };
|
|
|
|
|
}, [model]);
|
|
|
|
|
|
|
|
|
|
return <div className='vbox workbench'>
|
2023-03-07 06:37:39 +01:00
|
|
|
<Timeline
|
|
|
|
|
model={model}
|
2023-08-17 01:30:17 +02:00
|
|
|
boundaries={boundaries}
|
2023-04-01 03:34:51 +02:00
|
|
|
onSelected={onActionSelected}
|
2023-06-16 17:56:11 +02:00
|
|
|
sdkLanguage={sdkLanguage}
|
2023-08-17 01:30:17 +02:00
|
|
|
selectedTime={selectedTime}
|
|
|
|
|
setSelectedTime={setSelectedTime}
|
2023-03-07 06:37:39 +01:00
|
|
|
/>
|
2023-08-17 01:30:17 +02:00
|
|
|
<SplitView sidebarSize={drawer === 'bottom' ? 250 : 400} orientation={drawer === 'bottom' ? 'vertical' : 'horizontal'}>
|
2023-03-07 23:24:50 +01:00
|
|
|
<SplitView sidebarSize={250} orientation='horizontal' sidebarIsFirst={true}>
|
2023-03-07 21:43:16 +01:00
|
|
|
<SnapshotTab action={activeAction} sdkLanguage={sdkLanguage} testIdAttributeName={model?.testIdAttributeName || 'data-testid'} />
|
2023-03-07 23:24:50 +01:00
|
|
|
<TabbedPane tabs={
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
id: 'actions',
|
|
|
|
|
title: 'Actions',
|
|
|
|
|
component: <ActionList
|
|
|
|
|
sdkLanguage={sdkLanguage}
|
|
|
|
|
actions={model?.actions || []}
|
|
|
|
|
selectedAction={model ? selectedAction : undefined}
|
2023-08-17 01:30:17 +02:00
|
|
|
selectedTime={selectedTime}
|
2023-04-01 03:34:51 +02:00
|
|
|
onSelected={onActionSelected}
|
|
|
|
|
onHighlighted={setHighlightedAction}
|
2023-03-07 23:24:50 +01:00
|
|
|
revealConsole={() => setSelectedPropertiesTab('console')}
|
2023-05-19 00:52:44 +02:00
|
|
|
isLive={isLive}
|
2023-03-07 23:24:50 +01:00
|
|
|
/>
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'metadata',
|
|
|
|
|
title: 'Metadata',
|
|
|
|
|
component: <MetadataView model={model}/>
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
} selectedTab={selectedNavigatorTab} setSelectedTab={setSelectedNavigatorTab}/>
|
2021-03-11 20:22:59 +01:00
|
|
|
</SplitView>
|
2023-03-11 20:43:33 +01:00
|
|
|
<TabbedPane tabs={tabs} selectedTab={selectedPropertiesTab} setSelectedTab={setSelectedPropertiesTab} />
|
2021-04-06 05:27:57 +02:00
|
|
|
</SplitView>
|
2021-01-08 01:15:34 +01:00
|
|
|
</div>;
|
|
|
|
|
};
|