Skip to content

Commit df761da

Browse files
committed
Expose transform perspectives in the UI
1 parent 7520b11 commit df761da

12 files changed

+300
-121
lines changed

src/components/common/pill.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import {
99
getBackgroundColor
1010
} from '../../util/colors';
1111

12-
function getNonTransparentBackground(baseColor: string, theme: Theme) {
12+
// Returns a non-transparent but transparency-like background color for
13+
// a pill shown on top of the main background.
14+
function getPillBackground(baseColor: string, theme: Theme) {
1315
return polished.mix(0.3, baseColor, theme.mainBackground);
1416
}
1517

@@ -51,7 +53,7 @@ export const PillButton = styled(UnstyledButton)`
5153
}
5254
`;
5355

54-
const Select = styled(Pill.withComponent('select'))`
56+
export const PillSelect = styled(Pill.withComponent('select'))`
5557
text-align: left;
5658
border: none;
5759
@@ -65,7 +67,7 @@ const Select = styled(Pill.withComponent('select'))`
6567
6668
* {
6769
background-color: ${(p: { color?: string, theme?: Theme }) =>
68-
getNonTransparentBackground(
70+
getPillBackground(
6971
p.color || p.theme!.pillDefaultColor,
7072
p.theme!
7173
)
@@ -86,7 +88,7 @@ export const PillSelector = <
8688
const asKey = props.keyFormatter || ((k: T) => k.toString() as K);
8789
const asName = props.nameFormatter || ((k: T) => k.toString());
8890

89-
return <Select
91+
return <PillSelect
9092
onChange={(e) => props.onChange(e.target.value as K)}
9193
value={asKey(props.value)}
9294
>
@@ -106,5 +108,5 @@ export const PillSelector = <
106108
}</optgroup>
107109
)
108110
}
109-
</Select>
111+
</PillSelect>
110112
};

src/components/view/http/http-body-card.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import * as portals from 'react-reverse-portal';
77

88
import { ExchangeMessage } from '../../../types';
99

10-
import { ErrorLike } from '../../../util/error';
1110
import { getHeaderValue } from '../../../util/headers';
1211

1312
import { ViewableContentType, getCompatibleTypes } from '../../../model/events/content-types';
@@ -38,6 +37,8 @@ export class HttpBodyCard extends React.Component<ExpandableCardProps & {
3837
url: string,
3938
message: ExchangeMessage,
4039
apiBodySchema?: SchemaObject,
40+
41+
editorKey: string,
4142
editorNode: portals.HtmlPortalNode<typeof SelfSizedEditor>
4243
}> {
4344

@@ -76,7 +77,9 @@ export class HttpBodyCard extends React.Component<ExpandableCardProps & {
7677
expanded,
7778
onCollapseToggled,
7879
onExpandToggled,
79-
ariaLabel
80+
ariaLabel,
81+
editorKey,
82+
editorNode
8083
} = this.props;
8184

8285
const compatibleContentTypes = getCompatibleTypes(
@@ -118,8 +121,8 @@ export class HttpBodyCard extends React.Component<ExpandableCardProps & {
118121
</header>
119122
<EditorCardContent showFullBorder={!expanded}>
120123
<ContentViewer
121-
contentId={`${message.id}-${direction}`}
122-
editorNode={this.props.editorNode}
124+
contentId={editorKey}
125+
editorNode={editorNode}
123126
headers={message.headers}
124127
contentType={decodedContentType}
125128
schema={apiBodySchema}

src/components/view/http/http-breakpoint-body-card.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,11 @@ export class HttpBreakpointBodyCard extends React.Component<ExpandableCardProps
3030
title: string,
3131
direction: 'left' | 'right',
3232

33-
exchangeId: string,
3433
body: EditableBody,
3534
rawHeaders: RawHeaders,
3635
onChange: (result: Buffer) => void,
36+
37+
editorKey: string,
3738
editorNode: portals.HtmlPortalNode<typeof SelfSizedEditor>;
3839
}> {
3940

@@ -71,13 +72,14 @@ export class HttpBreakpointBodyCard extends React.Component<ExpandableCardProps
7172
body,
7273
rawHeaders,
7374
title,
74-
exchangeId,
7575
direction,
7676
collapsed,
7777
expanded,
7878
onCollapseToggled,
7979
onExpandToggled,
80-
ariaLabel
80+
ariaLabel,
81+
editorNode,
82+
editorKey
8183
} = this.props;
8284

8385
const bodyString = bufferToString(body.decoded, this.textEncoding);
@@ -116,8 +118,8 @@ export class HttpBreakpointBodyCard extends React.Component<ExpandableCardProps
116118

117119
<EditorCardContent showFullBorder={!expanded}>
118120
<portals.OutPortal<typeof SelfSizedEditor>
119-
contentId={`bp-${exchangeId}-${direction}`}
120-
node={this.props.editorNode}
121+
contentId={`bp-${editorKey}`}
122+
node={editorNode}
121123
language={this.contentType}
122124
value={bodyString}
123125
onChange={this.onBodyChange}

src/components/view/http/http-details-pane.tsx

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { CollectedEvent, HtkResponse, HttpExchange, HttpExchangeView } from '../
88
import { styled } from '../../../styles';
99
import { logError } from '../../../errors';
1010

11-
import { ExpandableViewCardKey, UiStore } from '../../../model/ui/ui-store';
11+
import { ContentPerspective, ExpandableViewCardKey, UiStore } from '../../../model/ui/ui-store';
1212
import { RulesStore } from '../../../model/rules/rules-store';
1313
import { AccountStore } from '../../../model/account/account-store';
1414
import { ApiExchange } from '../../../model/api/api-interfaces';
@@ -37,6 +37,7 @@ import { HttpRequestBreakpointHeader, HttpResponseBreakpointHeader } from './htt
3737
import { HttpBreakpointRequestCard } from './http-breakpoint-request-card';
3838
import { HttpBreakpointResponseCard } from './http-breakpoint-response-card';
3939
import { HttpBreakpointBodyCard } from './http-breakpoint-body-card';
40+
import { TransformCard } from './transform-card';
4041

4142
// Used to push all cards below it to the bottom (when less than 100% height)
4243
const CardDivider = styled.div`
@@ -61,6 +62,7 @@ const makeFriendlyApiName = (rawName: string) => {
6162
@observer
6263
export class HttpDetailsPane extends React.Component<{
6364
exchange: HttpExchangeView,
65+
perspective: ContentPerspective,
6466

6567
requestEditor: portals.HtmlPortalNode<typeof SelfSizedEditor>,
6668
responseEditor: portals.HtmlPortalNode<typeof SelfSizedEditor>,
@@ -121,7 +123,7 @@ export class HttpDetailsPane extends React.Component<{
121123
}
122124

123125
const cards = (exchange.downstream.isBreakpointed)
124-
? this.renderBreakpointCards(exchange.downstream, apiName, apiExchange)
126+
? this.renderBreakpointCards(exchange, apiName, apiExchange)
125127
: this.renderNormalCards(exchange, apiName, apiExchange);
126128

127129
return <>
@@ -235,30 +237,38 @@ export class HttpDetailsPane extends React.Component<{
235237
}
236238

237239
private renderBreakpointCards(
238-
exchange: HttpExchange,
240+
exchange: HttpExchangeView,
239241
apiName: string | undefined,
240242
apiExchange: ApiExchange | undefined
241243
) {
242244
const { uiStore } = this.props;
243-
const { requestBreakpoint } = exchange;
245+
const { requestBreakpoint } = exchange.downstream;
244246

245247
const cards: Array<JSX.Element | null> = [];
246248

247249
if (requestBreakpoint) {
248250
cards.push(<HttpBreakpointRequestCard
249251
{...this.cardProps.request}
250-
exchange={exchange}
252+
exchange={exchange.downstream}
251253
onChange={requestBreakpoint.updateMetadata}
252254
/>);
253255

254256
cards.push(this.renderRequestBody(exchange, apiExchange));
255257
} else {
256-
const responseBreakpoint = exchange.responseBreakpoint!;
258+
const responseBreakpoint = exchange.downstream.responseBreakpoint!;
259+
const transformCard = this.renderTransformCard();
260+
if (transformCard) cards.push(transformCard);
257261

258262
cards.push(this.renderApiCard(apiName, apiExchange));
259263
cards.push(<HttpRequestCard
260264
{...this.cardProps.request}
261-
matchedRuleData={this.matchedRuleData}
265+
matchedRuleData={
266+
// Matched rule data is shown inline here only when there
267+
// was not any substantial proxy transformation.
268+
!transformCard
269+
? this.matchedRuleData
270+
: undefined
271+
}
262272
onRuleClicked={this.jumpToRule}
263273
exchange={exchange}
264274
/>);
@@ -269,7 +279,7 @@ export class HttpDetailsPane extends React.Component<{
269279

270280
cards.push(<HttpBreakpointResponseCard
271281
{...this.cardProps.response}
272-
exchange={exchange}
282+
exchange={exchange.downstream}
273283
onChange={responseBreakpoint.updateMetadata}
274284
theme={uiStore!.theme}
275285
/>);
@@ -290,11 +300,19 @@ export class HttpDetailsPane extends React.Component<{
290300

291301
const cards: Array<JSX.Element | null> = [];
292302

303+
const transformCard = this.renderTransformCard();
304+
if (transformCard) cards.push(transformCard);
293305
cards.push(this.renderApiCard(apiName, apiExchange));
294306

295307
cards.push(<HttpRequestCard
296308
{...this.cardProps.request}
297-
matchedRuleData={this.matchedRuleData}
309+
matchedRuleData={
310+
// Matched rule data is shown inline here only when there
311+
// was not any substantial proxy transformation.
312+
!transformCard
313+
? this.matchedRuleData
314+
: undefined
315+
}
298316
onRuleClicked={this.jumpToRule}
299317
exchange={exchange}
300318
/>);
@@ -377,14 +395,26 @@ export class HttpDetailsPane extends React.Component<{
377395
return cards;
378396
}
379397

398+
private renderTransformCard() {
399+
const { uiStore } = this.props;
400+
401+
if (!this.props.exchange.upstream?.wasTransformed) return false;
402+
403+
return <TransformCard
404+
key='transform'
405+
matchedRuleData={this.matchedRuleData}
406+
onRuleClicked={this.jumpToRule}
407+
uiStore={uiStore!}
408+
/>;
409+
}
410+
380411
private renderRequestBody(exchange: HttpExchangeView, apiExchange: ApiExchange | undefined) {
381412
const { request } = exchange;
382413
const { requestBreakpoint } = exchange.downstream;
383414

384415
return requestBreakpoint
385416
? <HttpBreakpointBodyCard
386417
{...this.requestBodyParams()}
387-
exchangeId={exchange.id}
388418
body={requestBreakpoint.inProgressResult.body}
389419
rawHeaders={requestBreakpoint.inProgressResult.rawHeaders}
390420
onChange={requestBreakpoint.updateBody}
@@ -405,7 +435,6 @@ export class HttpDetailsPane extends React.Component<{
405435
return responseBreakpoint
406436
? <HttpBreakpointBodyCard
407437
{...this.responseBodyParams()}
408-
exchangeId={exchange.id}
409438
body={responseBreakpoint.inProgressResult.body}
410439
rawHeaders={responseBreakpoint.inProgressResult.rawHeaders}
411440
onChange={responseBreakpoint.updateBody}
@@ -449,6 +478,7 @@ export class HttpDetailsPane extends React.Component<{
449478
...this.cardProps.requestBody,
450479
title: 'Request Body',
451480
direction: 'right' as const,
481+
editorKey: `${this.props.exchange.id}-${this.props.perspective}-request`,
452482
editorNode: this.props.requestEditor
453483
};
454484
}
@@ -459,6 +489,7 @@ export class HttpDetailsPane extends React.Component<{
459489
...this.cardProps.responseBody,
460490
title: 'Response Body',
461491
direction: 'left' as const,
492+
editorKey: `${this.props.exchange.id}-${this.props.perspective}-response`,
462493
editorNode: this.props.responseEditor
463494
};
464495
}

src/components/view/http/http-request-card.tsx

Lines changed: 4 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,17 @@
11
import * as React from 'react';
2-
import { inject, observer } from 'mobx-react';
2+
import { observer } from 'mobx-react';
33

44
import { HttpExchange, HtkRequest, HttpVersion, HttpExchangeView } from '../../../types';
5-
import { styled } from '../../../styles';
6-
import { PhosphorIcon } from '../../../icons';
75

8-
import { aOrAn, uppercaseFirst } from '../../../util/text';
9-
10-
import { UiStore } from '../../../model/ui/ui-store';
116
import { getSummaryColor } from '../../../model/events/categorization';
127
import { getMethodDocs } from '../../../model/http/http-docs';
13-
import { nameHandlerClass } from '../../../model/rules/rule-descriptions';
14-
import { HandlerClassKey } from '../../../model/rules/rules';
158

169
import {
1710
CollapsibleCardHeading,
1811
CollapsibleCard,
1912
CollapsibleCardProps
2013
} from '../../common/card';
21-
import { Pill, PillButton } from '../../common/pill';
14+
import { Pill } from '../../common/pill';
2215
import {
2316
CollapsibleSection,
2417
CollapsibleSectionSummary,
@@ -35,58 +28,8 @@ import { SourceIcon } from '../../common/source-icon';
3528
import { HttpVersionPill } from '../../common/http-version-pill';
3629
import { HeaderDetails } from './header-details';
3730
import { UrlBreakdown } from '../url-breakdown';
38-
39-
const MatchedRulePill = styled(inject('uiStore')((p: {
40-
className?: string,
41-
uiStore?: UiStore,
42-
ruleData: {
43-
stepTypes: HandlerClassKey[],
44-
status: 'unchanged' | 'modified-types' | 'deleted'
45-
},
46-
onClick: () => void
47-
}) => {
48-
const { stepTypes } = p.ruleData;
49-
const stepDescription = stepTypes.length !== 1
50-
? 'multi-step'
51-
: nameHandlerClass(stepTypes[0]);
52-
53-
return <PillButton
54-
color={getSummaryColor('mutative')} // Conceptually similar - we've modified traffic
55-
className={p.className}
56-
57-
// For now we show modified as unchanged, but we could highlight this later:
58-
disabled={p.ruleData.status === 'deleted'}
59-
onClick={p.ruleData.status !== 'deleted' ? p.onClick : undefined}
60-
61-
title={
62-
`This request was handled by ${
63-
aOrAn(stepDescription)
64-
} ${stepDescription} rule${
65-
p.ruleData.status === 'deleted'
66-
? ' which has since been deleted'
67-
: p.ruleData.status === 'modified-types'
68-
? ' (which has since been modified)'
69-
: ''
70-
}.${
71-
p.ruleData.status !== 'deleted'
72-
? '\nClick here to jump to the rule on the Modify page.'
73-
: ''
74-
}`
75-
}
76-
>
77-
<PhosphorIcon icon='Pencil' size='16px' />
78-
{ uppercaseFirst(stepDescription) }
79-
</PillButton>;
80-
}))`
81-
margin-right: auto;
82-
83-
text-decoration: none;
84-
word-spacing: 0;
85-
86-
> svg {
87-
margin: -1px 5px 0 -1px;
88-
}
89-
`;
31+
import { HandlerClassKey } from '../../../model/rules/rules';
32+
import { MatchedRulePill } from './matched-rule-pill';
9033

9134
const RawRequestDetails = (p: {
9235
request: HtkRequest,

0 commit comments

Comments
 (0)