Skip to content

Commit 8456eec

Browse files
committed
Reuse the editor across response bodies via portals
1 parent 1c496d2 commit 8456eec

File tree

6 files changed

+49
-10
lines changed

6 files changed

+49
-10
lines changed

package-lock.json

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
"react-dom": "^16.6.3",
8888
"react-ga": "^2.5.6",
8989
"react-monaco-editor": "^0.22.0",
90+
"react-reverse-portal": "^1.0.1",
9091
"react-sortable-hoc": "^1.10.1",
9192
"react-split-pane": "^0.1.84",
9293
"react-virtualized": "^9.20.1",

src/components/editor/content-editor.tsx

+11-4
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,9 @@ export const Formatters: { [key in HtkContentType]?: Formatter } = {
107107
};
108108

109109
interface ContentEditorProps {
110-
children: Buffer;
110+
children: Buffer | string;
111111
schema?: SchemaObject;
112-
rawContentType: string | undefined;
112+
rawContentType?: string;
113113
contentType: HtkContentType;
114114
contentObservable?: IObservableValue<string | undefined>;
115115
}
@@ -130,10 +130,17 @@ export class ContentEditor extends React.Component<ContentEditorProps> {
130130
return Formatters[this.props.contentType] || Formatters.text!;
131131
}
132132

133+
@computed
134+
private get contentBuffer() {
135+
return _.isString(this.props.children)
136+
? Buffer.from(this.props.children)
137+
: this.props.children;
138+
}
139+
133140
@computed
134141
private get renderedContent() {
135142
if (isEditorFormatter(this.formatter)) {
136-
return this.formatter.render(this.props.children);
143+
return this.formatter.render(this.contentBuffer);
137144
}
138145
}
139146

@@ -167,7 +174,7 @@ export class ContentEditor extends React.Component<ContentEditorProps> {
167174
}
168175
} else {
169176
const Viewer = this.formatter;
170-
return <Viewer content={this.props.children} rawContentType={this.props.rawContentType} />;
177+
return <Viewer content={this.contentBuffer} rawContentType={this.props.rawContentType} />;
171178
}
172179
}
173180
}

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

+5-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as React from 'react';
33
import { observable, autorun, action } from 'mobx';
44
import { disposeOnUnmount, observer, inject } from 'mobx-react';
55
import { SchemaObject } from 'openapi-directory';
6+
import * as portals from 'react-reverse-portal';
67

78
import { ExchangeMessage } from '../../types';
89
import { styled } from '../../styles';
@@ -39,6 +40,7 @@ export class ExchangeBodyCard extends React.Component<{
3940
direction: 'left' | 'right',
4041
collapsed: boolean,
4142
onCollapseToggled: () => void,
43+
editorNode: portals.PortalNode
4244
}> {
4345

4446
@observable
@@ -112,14 +114,15 @@ export class ExchangeBodyCard extends React.Component<{
112114
<h1>{ title }</h1>
113115
</header>
114116
<EditorCardContent>
115-
<ContentEditor
117+
<portals.OutPortal<ContentEditor>
118+
node={this.props.editorNode}
116119
rawContentType={message.headers['content-type']}
117120
contentType={contentType}
118121
contentObservable={this.currentContent}
119122
schema={apiBodySchema}
120123
>
121124
{decodedBody}
122-
</ContentEditor>
125+
</portals.OutPortal>
123126
</EditorCardContent>
124127
</ExchangeCard>
125128
:

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

+6-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as React from 'react';
33
import { get } from 'typesafe-get';
44
import { action, observable } from 'mobx';
55
import { observer, inject } from 'mobx-react';
6+
import * as portals from 'react-reverse-portal';
67

78
import { HtkResponse, Omit } from '../../types';
89
import { styled } from '../../styles';
@@ -54,7 +55,9 @@ export class ExchangeDetailsPane extends React.Component<{
5455
exchange: HttpExchange,
5556
// Injected:
5657
uiStore?: UiStore,
57-
accountStore?: AccountStore
58+
accountStore?: AccountStore,
59+
requestEditor: portals.PortalNode,
60+
responseEditor: portals.PortalNode
5861
}> {
5962

6063
@observable
@@ -92,6 +95,7 @@ export class ExchangeDetailsPane extends React.Component<{
9295
title='Request Body'
9396
direction='right'
9497
message={request}
98+
editorNode={this.props.requestEditor}
9599
apiBodySchema={get(apiExchange, 'request', 'bodySchema')}
96100
{...this.cardProps.requestBody}
97101
/>);
@@ -121,6 +125,7 @@ export class ExchangeDetailsPane extends React.Component<{
121125
title='Response Body'
122126
direction='left'
123127
message={response}
128+
editorNode={this.props.responseEditor}
124129
apiBodySchema={get(apiExchange, 'response', 'bodySchema')}
125130
{...this.cardProps.responseBody}
126131
/>);

src/components/view/view-page.tsx

+21-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import * as React from 'react';
22
import * as _ from 'lodash';
3-
4-
import { observable, autorun, action, runInAction } from 'mobx';
3+
import { autorun, action, observable, runInAction } from 'mobx';
54
import { observer, disposeOnUnmount, inject } from 'mobx-react';
5+
import * as portals from 'react-reverse-portal';
66

77
import { WithInjected } from '../../types';
88
import { styled } from '../../styles';
@@ -15,6 +15,7 @@ import { EmptyState } from '../common/empty-state';
1515
import { ViewEventList, CollectedEvent } from './view-event-list';
1616
import { ExchangeDetailsPane } from './exchange-details-pane';
1717
import { TlsFailureDetailsPane } from './tls-failure-details-pane';
18+
import { ContentEditor } from '../editor/content-editor';
1819

1920
interface ViewPageProps {
2021
className?: string,
@@ -27,6 +28,9 @@ class ViewPage extends React.Component<ViewPageProps> {
2728

2829
@observable.ref selectedEvent: CollectedEvent | undefined = undefined;
2930

31+
requestEditor = portals.createPortalNode<ContentEditor>();
32+
responseEditor = portals.createPortalNode<ContentEditor>();
33+
3034
componentDidMount() {
3135
disposeOnUnmount(this, autorun(() => {
3236
if (!_.includes(this.props.interceptionStore.events, this.selectedEvent)) {
@@ -49,7 +53,11 @@ class ViewPage extends React.Component<ViewPageProps> {
4953
Select an exchange to see the full details.
5054
</EmptyState>;
5155
} else if ('request' in this.selectedEvent) {
52-
rightPane = <ExchangeDetailsPane exchange={this.selectedEvent} />;
56+
rightPane = <ExchangeDetailsPane
57+
exchange={this.selectedEvent}
58+
requestEditor={this.requestEditor}
59+
responseEditor={this.responseEditor}
60+
/>;
5361
} else {
5462
rightPane = <TlsFailureDetailsPane failure={this.selectedEvent} certPath={certPath} />;
5563
}
@@ -70,6 +78,16 @@ class ViewPage extends React.Component<ViewPageProps> {
7078
/>
7179
{ rightPane }
7280
</SplitPane>
81+
82+
{[this.requestEditor, this.responseEditor].map((editorNode, i) =>
83+
<portals.InPortal key={i} node={editorNode}>
84+
<ContentEditor
85+
contentType='text'
86+
rawContentType=''
87+
children=''
88+
/>
89+
</portals.InPortal>
90+
)}
7391
</div>;
7492
}
7593

0 commit comments

Comments
 (0)