diff --git a/addon/web/client/public/index.html b/addon/web/client/public/index.html index 87bcef7..755d464 100644 --- a/addon/web/client/public/index.html +++ b/addon/web/client/public/index.html @@ -29,7 +29,7 @@ - +
diff --git a/addon/web/client/src/App.css b/addon/web/client/src/App.css index 91d4c84..a88a705 100644 --- a/addon/web/client/src/App.css +++ b/addon/web/client/src/App.css @@ -8,9 +8,17 @@ white-space: nowrap; } +/* https://css-tricks.com/position-sticky-and-table-headers/ */ +.main-table-wrap table th { + background-color: white; + position: sticky; + top: -1px; +} + .top-control { display: flex; align-items: center; + margin: 10px; } .top-control > div { @@ -40,10 +48,15 @@ overflow-y: auto; word-break: break-all; + border-left: 2px solid #dee2e6; } .flow-detail .header-tabs { display: flex; + position: sticky; + top: 0; + background-color: white; + padding: 5px 0; } .flow-detail .header-tabs span { diff --git a/addon/web/client/src/App.tsx b/addon/web/client/src/App.tsx index babc2cc..a8b94fe 100644 --- a/addon/web/client/src/App.tsx +++ b/addon/web/client/src/App.tsx @@ -207,8 +207,8 @@ class App extends React.Component {

{ - !(isTextBody(request)) ? 'Not text' : - new TextDecoder().decode(request.body) + !(flow.isTextRequest()) ? Not text : + flow.requestBody() }

@@ -220,10 +220,10 @@ class App extends React.Component { { !(flowTab === 'Response') ? null : - !(response.body && response.body.byteLength) ?
No response
: - !(isTextBody(response)) ?
Not text response
: + !(response.body && response.body.byteLength) ?
No response
: + !(flow.isTextResponse()) ?
Not text response
:
- {new TextDecoder().decode(response.body)} + {flow.responseBody()}
} @@ -264,9 +264,9 @@ class App extends React.Component { No - Host - Path Method + Host + Path Status Size Time diff --git a/addon/web/client/src/components/FlowPreview.tsx b/addon/web/client/src/components/FlowPreview.tsx index 778cf1f..c743ea7 100644 --- a/addon/web/client/src/components/FlowPreview.tsx +++ b/addon/web/client/src/components/FlowPreview.tsx @@ -30,9 +30,9 @@ class FlowPreview extends React.Component { }} > {fp.no} + {fp.method} {fp.host} {fp.path} - {fp.method} {fp.statusCode} {fp.size} {fp.costTime} diff --git a/addon/web/client/src/message.ts b/addon/web/client/src/message.ts index 3d790db..18bdb22 100644 --- a/addon/web/client/src/message.ts +++ b/addon/web/client/src/message.ts @@ -1,4 +1,4 @@ -import { getSize } from './utils' +import { getSize, isTextBody } from './utils' export enum MessageType { REQUEST = 1, @@ -61,6 +61,13 @@ export class Flow { public static curNo = 0 + private status: MessageType = MessageType.REQUEST + + private _isTextRequest: boolean | null + private _isTextResponse: boolean | null + private _requestBody: string | null + private _responseBody: string | null + constructor(msg: IMessage) { this.no = ++Flow.curNo this.id = msg.id @@ -69,15 +76,22 @@ export class Flow { this.url = new URL(this.request.url) this.path = this.url.pathname + this.url.search + + this._isTextRequest = null + this._isTextResponse = null + this._requestBody = null + this._responseBody = null } public addRequestBody(msg: IMessage): Flow { + this.status = MessageType.REQUEST_BODY this.waitIntercept = msg.waitIntercept this.request.body = msg.content as ArrayBuffer return this } public addResponse(msg: IMessage): Flow { + this.status = MessageType.RESPONSE this.waitIntercept = msg.waitIntercept this.response = msg.content as IResponse @@ -91,6 +105,7 @@ export class Flow { } public addResponseBody(msg: IMessage): Flow { + this.status = MessageType.RESPONSE_BODY this.waitIntercept = msg.waitIntercept if (this.response) this.response.body = msg.content as ArrayBuffer this.endTime = Date.now() @@ -116,6 +131,42 @@ export class Flow { costTime: this.costTime, } } + + public isTextRequest(): boolean { + if (this._isTextRequest !== null) return this._isTextRequest + this._isTextRequest = isTextBody(this.request) + return this._isTextRequest + } + + public requestBody(): string { + if (this._requestBody !== null) return this._requestBody + if (!this.isTextRequest()) { + this._requestBody = '' + return this._requestBody + } + if (this.status < MessageType.REQUEST_BODY) return '' + this._requestBody = new TextDecoder().decode(this.request.body) + return this._requestBody + } + + public isTextResponse(): boolean | null { + if (this.status < MessageType.RESPONSE) return null + if (this._isTextResponse !== null) return this._isTextResponse + this._isTextResponse = isTextBody(this.response as IResponse) + return this._isTextResponse + } + + public responseBody(): string { + if (this._responseBody !== null) return this._responseBody + if (this.status < MessageType.RESPONSE) return '' + if (!this.isTextResponse()) { + this._responseBody = '' + return this._responseBody + } + if (this.status < MessageType.RESPONSE_BODY) return '' + this._responseBody = new TextDecoder().decode(this.response?.body) + return this._responseBody + } } const allMessageBytes = [ diff --git a/addon/web/client/src/utils.ts b/addon/web/client/src/utils.ts index 8983056..813b008 100644 --- a/addon/web/client/src/utils.ts +++ b/addon/web/client/src/utils.ts @@ -5,7 +5,7 @@ export const isTextBody = (payload: IRequest | IResponse) => { if (!payload.header) return false if (!payload.header['Content-Type']) return false - return /text|javascript|json/.test(payload.header['Content-Type'].join('')) + return /text|javascript|json|x-www-form-urlencoded/.test(payload.header['Content-Type'].join('')) } export const getSize = (len: number) => {