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) => {