aboutsummaryrefslogtreecommitdiffstats
path: root/src/components
diff options
context:
space:
mode:
authorGravatar Tom van der Lee <tom@vanderlee.io>2022-01-23 19:25:56 +0100
committerGravatar Tom van der Lee <tom@vanderlee.io>2022-01-25 22:06:58 +0100
commit2f27e222add9bf10b55971ab915ac411e81d24f0 (patch)
tree6ed9ea87932809d57d5db9d3c638a88a954ab8e2 /src/components
parent51a2ac628822e96459b3d570eada953ac8927d43 (diff)
downloadclient-2f27e222add9bf10b55971ab915ac411e81d24f0.tar.gz
client-2f27e222add9bf10b55971ab915ac411e81d24f0.tar.bz2
client-2f27e222add9bf10b55971ab915ac411e81d24f0.zip
Rewritten ui to use boostrap
Diffstat (limited to 'src/components')
-rw-r--r--src/components/App/App.module.scss35
-rw-r--r--src/components/App/App.tsx127
-rw-r--r--src/components/Content/Content.module.scss29
-rw-r--r--src/components/Content/Content.tsx50
-rw-r--r--src/components/Details/Details.module.scss66
-rw-r--r--src/components/Details/Details.tsx237
-rw-r--r--src/components/RequestSummary/RequestSummary.module.scss24
-rw-r--r--src/components/RequestSummary/RequestSummary.tsx1
8 files changed, 172 insertions, 397 deletions
diff --git a/src/components/App/App.module.scss b/src/components/App/App.module.scss
index 9837cdf..088a4f6 100644
--- a/src/components/App/App.module.scss
+++ b/src/components/App/App.module.scss
@@ -1,3 +1,34 @@
1.content { 1.app {
2 flex: 1 0 auto; 2 display: flex;
3 flex-flow: column nowrap;
4 grid-template-rows: auto 1fr;
5 height: 100vh;
6 overflow: hidden;
7}
8
9.main {
10 display: flex;
11 flex-flow: row nowrap;
12 flex-grow: 1;
13 overflow: hidden;
14}
15
16.sidebar {
17 width: calc((6 / 16) * 100%);
18 height: 100%;
19 overflow-y: auto;
20}
21
22.details {
23 width: calc((10 / 16) * 100%);
24 overflow: hidden;
25 height: 100%;
26}
27
28.noRequest, .noRequestSelected {
29 width: 100%;
30 height: 100%;
31 display: flex;
32 justify-content: center;
33 align-items: center;
3} 34}
diff --git a/src/components/App/App.tsx b/src/components/App/App.tsx
index 61f88f6..cb82abc 100644
--- a/src/components/App/App.tsx
+++ b/src/components/App/App.tsx
@@ -1,12 +1,15 @@
1import * as React from "react"; 1import * as React from "react";
2import useRequests, {RequestResponse, ReadyState} from "../../hooks/useRequests";
3import {useEffect, useMemo, useState} from "react"; 2import {useEffect, useMemo, useState} from "react";
3import useRequests, {
4 ReadyState,
5 RequestResponse
6} from "../../hooks/useRequests";
4 7
5import styles from './App.module.scss'; 8import styles from './App.module.scss';
6import Details from "../Details/Details"; 9import Details from "../Details/Details";
7import RequestSummary from "../RequestSummary/RequestSummary"; 10import RequestSummary from "../RequestSummary/RequestSummary";
8import {getHost} from "../../utils"; 11import {getHost} from "../../utils";
9import {Container, Navbar, Col, Row, Nav, ListGroup} from "react-bootstrap"; 12import {Container, ListGroup, Navbar} from "react-bootstrap";
10import classNames from "classnames"; 13import classNames from "classnames";
11 14
12interface Config { 15interface Config {
@@ -52,11 +55,12 @@ export default function App() {
52 ), [selectedRequestIndex, calls]); 55 ), [selectedRequestIndex, calls]);
53 56
54 return config && ( 57 return config && (
55 <> 58 <div className={styles.app}>
56 <Navbar 59 <Navbar
57 bg="dark" 60 bg="dark"
58 variant="dark" 61 variant="dark"
59 expand 62 expand
63 as="header"
60 > 64 >
61 <Container fluid> 65 <Container fluid>
62 <Navbar.Brand> 66 <Navbar.Brand>
@@ -67,44 +71,45 @@ export default function App() {
67 </Navbar.Text> 71 </Navbar.Text>
68 </Container> 72 </Container>
69 </Navbar> 73 </Navbar>
70 <Container>
71 74
72 </Container> 75 <main className={styles.main}>
73 <Row className={classNames(styles.content, 'gx-0', 'overflow-hidden')}> 76 <ListGroup
74 <Col className='border-end overflow-auto' xs={4}> 77 variant='flush'
75 <ListGroup variant='flush'> 78 as="ul"
76 { 79 className={classNames("border-end", styles.sidebar)}
77 calls.length > 0 80 >
78 ? ( 81 {
79 calls.slice(0).reverse().map((requestResponse, index) => { 82 calls.length > 0
80 const selected = selectedRequestIndex === calls.length - index - 1; 83 ? (
81 return ( 84 calls.slice(0).reverse().map((requestResponse, index) => {
82 <ListGroup.Item 85 const selected = selectedRequestIndex === calls.length - index - 1;
83 onClick={() => setSelectedRequestIndex(calls.length - index - 1)} 86 return (
84 key={`request-${index}`} 87 <ListGroup.Item
85 className={classNames({ 88 as="li"
86 'bg-primary': selected, 89 onClick={() => setSelectedRequestIndex(calls.length - index - 1)}
87 'text-light': selected, 90 key={`request-${index}`}
88 'border-bottom': true 91 className={classNames({
89 })} 92 'bg-primary': selected,
90 > 93 'text-light': selected,
91 <RequestSummary 94 'border-bottom': true
92 requestResponse={requestResponse} 95 })}
93 selected={selected} 96 >
94 /> 97 <RequestSummary
95 </ListGroup.Item> 98 requestResponse={requestResponse}
96 ) 99 selected={selected}
97 }) 100 />
98 ) 101 </ListGroup.Item>
99 : ( 102 )
100 <div className={styles.noRequest}> 103 })
101 <p>No requests</p> 104 )
102 </div> 105 : (
103 ) 106 <div className={styles.noRequest}>
104 } 107 <p>No requests</p>
105 </ListGroup> 108 </div>
106 </Col> 109 )
107 <Col xs={8} className=''> 110 }
111 </ListGroup>
112 <div className={styles.details}>
108 { 113 {
109 selectedRequest !== null 114 selectedRequest !== null
110 ? ( 115 ? (
@@ -115,44 +120,8 @@ export default function App() {
115 </div> 120 </div>
116 ) 121 )
117 } 122 }
118 </Col> 123 </div>
119 </Row> 124 </main>
120 </> 125 </div>
121 // <div className={styles.app}>
122 // <header className={styles.header}>
123 // {statusMap[readyState]} TTUN
124 // <a href={config.url} target="_blank">{config.url}</a>
125 // </header>
126 // <main className={styles.main}>
127 // <ul className={styles.sidebar}>
128 // {
129 // calls.length > 0
130 // ? calls.slice(0).reverse().map((requestResponse, index) => (
131 // <li onClick={() => setSelectedRequestIndex(calls.length - index - 1)} key={`request-${index}`}>
132 // <RequestSummary requestResponse={requestResponse} />
133 // </li>
134 // ))
135 // : (
136 // <div className={styles.noRequest}>
137 // <p>No requests</p>
138 // </div>
139 // )
140 // }
141 // </ul>
142 //
143 // <div className={styles.details}>
144 // {
145 // selectedRequest !== null
146 // ? (
147 // <Details requestResponse={selectedRequest} />
148 // ) : (
149 // <div className={styles.noRequestSelected}>
150 // <p>Select a request to inspect it</p>
151 // </div>
152 // )
153 // }
154 // </div>
155 // </main>
156 // </div>
157 ); 126 );
158} 127}
diff --git a/src/components/Content/Content.module.scss b/src/components/Content/Content.module.scss
index 8908516..4720afd 100644
--- a/src/components/Content/Content.module.scss
+++ b/src/components/Content/Content.module.scss
@@ -6,33 +6,10 @@
6 overflow: hidden; 6 overflow: hidden;
7} 7}
8 8
9.header {
10 flex-shrink: 0;
11 flex-grow: 0;
12 width: 100%;
13 display: flex;
14 padding: 0.5em;
15 background-color: black;
16 color: white;
17}
18
19.body { 9.body {
20 flex-grow: 1; 10 flex-grow: 1;
21 flex-shrink: 1; 11 flex-shrink: 1;
22 overflow-y: auto; 12 overflow-y: auto;
23
24 pre {
25 width: 100%;
26 height: 100%;
27 padding: 1em;
28 font-family: monospace;
29 overflow: auto;
30 }
31
32 iframe {
33 height: 100%;
34 width: 100%;
35 }
36} 13}
37 14
38.renderError { 15.renderError {
@@ -42,10 +19,4 @@
42 flex-flow: column nowrap; 19 flex-flow: column nowrap;
43 justify-content: center; 20 justify-content: center;
44 align-items: center; 21 align-items: center;
45
46 a {
47 margin-top: 1em;
48 text-decoration: underline;
49 color: blue;
50 }
51} 22}
diff --git a/src/components/Content/Content.tsx b/src/components/Content/Content.tsx
index cb5e6bc..0e63f30 100644
--- a/src/components/Content/Content.tsx
+++ b/src/components/Content/Content.tsx
@@ -1,19 +1,9 @@
1import styles from "~components/Details/Details.module.scss";
2import * as React from "react"; 1import * as React from "react";
3import classNames from "classnames"; 2import {Dispatch, SetStateAction, useMemo} from "react";
4import {RequestPayload, ResponsePayload} from "~hooks/useRequests"; 3import {RequestPayload, ResponsePayload} from "~hooks/useRequests";
5import {
6 Dispatch,
7 forwardRef, SetStateAction,
8 useEffect,
9 useImperativeHandle,
10 useMemo,
11 useRef,
12 useState
13} from "react";
14import ReactJson from 'react-json-view'; 4import ReactJson from 'react-json-view';
15import styles from './Content.module.scss'; 5import styles from './Content.module.scss';
16import {Col, Container, Row} from "react-bootstrap"; 6import {Button, Col, Container, Row} from "react-bootstrap";
17 7
18function getHeader(headers: { [key: string]: string }, key: string, unit?: string): string | null { 8function getHeader(headers: { [key: string]: string }, key: string, unit?: string): string | null {
19 console.log(headers, key) 9 console.log(headers, key)
@@ -37,7 +27,7 @@ interface ContentProps {
37 27
38export default function Content({ raw, setRaw, data }: ContentProps): JSX.Element { 28export default function Content({ raw, setRaw, data }: ContentProps): JSX.Element {
39 return ( 29 return (
40 <> 30 <div className={styles.content}>
41 <Container fluid className="border-bottom"> 31 <Container fluid className="border-bottom">
42 <Row className="py-3"> 32 <Row className="py-3">
43 <Col> 33 <Col>
@@ -54,7 +44,7 @@ export default function Content({ raw, setRaw, data }: ContentProps): JSX.Elemen
54 </Col> 44 </Col>
55 </Row> 45 </Row>
56 </Container> 46 </Container>
57 <Row> 47 <Row className={styles.body}>
58 {(() => { 48 {(() => {
59 try { 49 try {
60 return ContentBody({ data, raw }) 50 return ContentBody({ data, raw })
@@ -62,33 +52,13 @@ export default function Content({ raw, setRaw, data }: ContentProps): JSX.Elemen
62 return ( 52 return (
63 <div className={styles.renderError}> 53 <div className={styles.renderError}>
64 <p>Body could not be rendered</p> 54 <p>Body could not be rendered</p>
65 <a onClick={() => setRaw(true)}>View raw</a> 55 <Button variant="link" onClick={() => setRaw(true)}>View raw</Button>
66 </div> 56 </div>
67 ) 57 )
68 } 58 }
69 })()} 59 })()}
70 </Row> 60 </Row>
71 </> 61 </div >
72 // <div className={styles.content}>
73 // <div className={styles.header}>
74 // <input id='raw' type='checkbox' checked={raw} onChange={() => setRaw(!raw)}/>
75 // <label htmlFor='raw'>Raw</label>
76 // </div>
77 // <div className={styles.body}>
78 // {(() => {
79 // try {
80 // return ContentBody({ ...props, raw })
81 // } catch {
82 // return (
83 // <div className={styles.renderError}>
84 // <p>Body could not be rendered</p>
85 // <a onClick={() => setRaw(true)}>View raw</a>
86 // </div>
87 // )
88 // }
89 // })()}
90 // </div>
91 // </div>
92 ) 62 )
93}; 63};
94 64
@@ -103,7 +73,13 @@ function ContentBody({ data, raw = false }: Omit<ContentProps, 'setRaw'>) {
103 }, [data, raw]); 73 }, [data, raw]);
104 74
105 if (raw) { 75 if (raw) {
106 return <pre>{atob(data.body)}</pre> 76 return (
77 <pre className="mb-0">
78 <code>
79 {atob(data.body)}
80 </code>
81 </pre>
82 )
107 } 83 }
108 84
109 if (['application/pdf', 'text/html'].includes(contentType)) { 85 if (['application/pdf', 'text/html'].includes(contentType)) {
diff --git a/src/components/Details/Details.module.scss b/src/components/Details/Details.module.scss
index 32197f0..146b5d8 100644
--- a/src/components/Details/Details.module.scss
+++ b/src/components/Details/Details.module.scss
@@ -16,69 +16,3 @@
16 flex-shrink: 1; 16 flex-shrink: 1;
17 overflow-y: auto; 17 overflow-y: auto;
18} 18}
19
20.summary {
21 font-size: 2em;
22}
23
24.tabs {
25 display: flex;
26 border-bottom: 1px solid black;
27
28 &:last-child {
29 flex-grow: 1;
30 }
31}
32
33.tab {
34 background-color: white;
35 border: none;
36 border-top: 1px solid black;
37 border-right: 1px solid black;
38 border-radius: 0;
39 color: black;
40 font-size: 1.2em;
41 padding: 0.5em;
42
43 &.selected {
44 background-color: black;
45 color: white;
46 }
47}
48
49.emptySpace {
50 flex-grow: 1;
51 display: flex;
52 justify-content: flex-end;
53 align-items: center;
54 font-size: 1.2em;
55 padding: 0.5em;
56}
57
58.resend {
59 margin-left: 1em;
60}
61
62.headers {
63 display: grid;
64 grid-template-columns: auto 1fr;
65 border: 1px solid black;
66 margin: 1em;
67 overflow-x: auto;
68
69 h2 {
70 grid-column: 1/ span 2;
71 background-color: black;
72 color: white;
73 padding: 0.5em;
74 }
75
76 > div {
77 line-break: auto;
78 padding: 0.5em;
79
80 &:nth-of-type(4n), &:nth-of-type(4n - 1) {
81 background-color: lightgray;
82 }
83 }
84}
diff --git a/src/components/Details/Details.tsx b/src/components/Details/Details.tsx
index c96aa7b..d4bb07a 100644
--- a/src/components/Details/Details.tsx
+++ b/src/components/Details/Details.tsx
@@ -1,25 +1,11 @@
1import * as React from "react"; 1import * as React from "react";
2import { 2import {useCallback, useMemo, useState} from "react";
3 RequestPayload, 3import {RequestResponse} from "~hooks/useRequests";
4 RequestResponse,
5 ResponsePayload
6} from "~hooks/useRequests";
7import {useCallback, useEffect, useMemo, useState} from "react";
8import styles from "./Details.module.scss"; 4import styles from "./Details.module.scss";
9import RequestSummary from "../RequestSummary/RequestSummary"; 5import RequestSummary from "../RequestSummary/RequestSummary";
10import classNames from 'classnames';
11import Content from "../Content/Content"; 6import Content from "../Content/Content";
12import {getHost} from "../../utils"; 7import {getHost} from "../../utils";
13import { 8import {Button, Card, Col, Container, Nav, Row, Table} from "react-bootstrap";
14 Button,
15 Card,
16 Col,
17 Container,
18 Nav,
19 NavItem,
20 Row,
21 Table
22} from "react-bootstrap";
23 9
24 10
25interface TimingProps { 11interface TimingProps {
@@ -99,147 +85,80 @@ export default function Details({ requestResponse }: DetailsProps) {
99 ), [requestResponse]); 85 ), [requestResponse]);
100 86
101 return ( 87 return (
102 <> 88 <div className={styles.details}>
103 <Row> 89 <div className={styles.header}>
104 <Col> 90 <Row>
105 <Container fluid style={{ fontSize: '1.5em' }} className="py-3"> 91 <Col>
106 <RequestSummary requestResponse={requestResponse} className={styles.summary}/> 92 <Container fluid style={{ fontSize: '1.5em' }} className="py-3">
107 </Container> 93 <RequestSummary requestResponse={requestResponse} className={styles.summary}/>
108 </Col> 94 </Container>
109 </Row> 95 </Col>
110 <Row className="gx-0 d-flex"> 96 </Row>
111 <Col> 97 <Row className="gx-0 d-flex">
112 <Nav 98 <Col>
113 variant="tabs" 99 <Nav
114 activeKey={tab} 100 variant="tabs"
115 onSelect={(tab) => selectTab(tab as Tab)} 101 activeKey={tab}
116 > 102 onSelect={(tab) => selectTab(tab as Tab)}
117 <Nav.Item> 103 >
118 <Nav.Link eventKey="headers"> 104 <Nav.Item>
119 Headers 105 <Nav.Link eventKey="headers">
120 </Nav.Link > 106 Headers
121 </Nav.Item> 107 </Nav.Link >
122 <Nav.Item> 108 </Nav.Item>
123 <Nav.Link eventKey="request"> 109 <Nav.Item>
124 Request 110 <Nav.Link eventKey="request">
125 </Nav.Link> 111 Request
126 </Nav.Item> 112 </Nav.Link>
127 <Nav.Item> 113 </Nav.Item>
128 <Nav.Link 114 <Nav.Item>
129 eventKey="response" 115 <Nav.Link
130 disabled={requestResponse.response === undefined} 116 eventKey="response"
131 > 117 disabled={requestResponse.response === undefined}
132 Response 118 >
133 </Nav.Link> 119 Response
134 </Nav.Item> 120 </Nav.Link>
135 </Nav> 121 </Nav.Item>
136 </Col> 122 </Nav>
137 <Col className="border-bottom px-3 " xs="auto"> 123 </Col>
138 <Timing timing={requestResponse.response?.timing ?? NaN} /> 124 <Col className="border-bottom px-3 " xs="auto">
139 <Button variant="outline-primary" onClick={() => resend()} className="ms-3"> 125 <Timing timing={requestResponse.response?.timing ?? NaN} />
140 Resend 126 <Button variant="outline-primary" onClick={() => resend()} className="ms-3">
141 </Button> 127 Resend
142 </Col> 128 </Button>
143 </Row> 129 </Col>
144 <Row> 130 </Row>
145 <Col> 131 </div>
146 { 132 <div className={styles.content}>
147 tab === 'headers' && ( 133 {
148 <> 134 tab === 'headers' && (
149 <Headers 135 <>
150 title="Request Headers" 136 <Headers
151 headers={requestResponse.request.headers} 137 title="request headers"
152 /> 138 headers={requestResponse.request.headers}
153 { 139 />
154 requestResponse.response && ( 140 {
155 <Headers 141 requestResponse.response && (
156 title="Response Headers" 142 <Headers
157 headers={requestResponse.response.headers} 143 title="response headers"
158 /> 144 headers={requestResponse.response.headers}
159 ) 145 />
160 } 146 )
161 </> 147 }
162 ) 148 </>
163 } 149 )
164 { 150 }
165 tab === 'request' && ( 151 {
166 <Content data={requestResponse.request} raw={raw} setRaw={setRaw}/> 152 tab === 'request' && (
167 ) 153 <Content data={requestResponse.request} raw={raw} setRaw={setRaw}/>
168 } 154 )
169 { 155 }
170 tab === 'response' && requestResponse.response !== undefined && ( 156 {
171 <Content data={requestResponse.response} raw={raw} setRaw={setRaw}/> 157 tab === 'response' && requestResponse.response !== undefined && (
172 ) 158 <Content data={requestResponse.response} raw={raw} setRaw={setRaw}/>
173 } 159 )
174 </Col> 160 }
175 </Row> 161 </div>
176 </> 162 </div>
177 // <div className={styles.details}>
178 // <div className={styles.header}>
179 //
180 // <div className={styles.tabs}>
181 // <button
182 // onClick={() => selectTab('headers')}
183 // className={classNames(styles.tab, {
184 // [styles.selected]: tab === 'headers'
185 // })}
186 // >
187 // Headers
188 // </button>
189 // <button
190 // onClick={() => selectTab('request')}
191 // className={classNames(styles.tab, {
192 // [styles.selected]: tab === 'request'
193 // })}
194 // >
195 // Request
196 // </button>
197 // <button
198 // onClick={() => selectTab('response')}
199 // className={classNames(styles.tab, {
200 // [styles.selected]: tab === 'response'
201 // })}
202 // disabled={requestResponse.response === undefined}
203 // >
204 // Response
205 // </button>
206 //
207 // <div className={styles.emptySpace}>
208 // <Timing timing={requestResponse.response?.timing ?? NaN} />
209 // <button className={styles.resend} onClick={() => resend()}>Resend</button>
210 // </div>
211 // </div>
212 // </div>
213 // <div className={styles.content}>
214 // {
215 // tab === 'headers' && (
216 // <>
217 // <Headers
218 // title="Request Headers"
219 // headers={requestResponse.request.headers}
220 // />
221 // {
222 // requestResponse.response && (
223 // <Headers
224 // title="Response Headers"
225 // headers={requestResponse.response.headers}
226 // />
227 // )
228 // }
229 // </>
230 // )
231 // }
232 // {
233 // tab === 'request' && (
234 // <Content data={requestResponse.request} raw={raw} setRaw={setRaw}/>
235 // )
236 // }
237 // {
238 // tab === 'response' && requestResponse.response !== undefined && (
239 // <Content data={requestResponse.response} raw={raw} setRaw={setRaw}/>
240 // )
241 // }
242 // </div>
243 // </div>
244 ) 163 )
245} 164}
diff --git a/src/components/RequestSummary/RequestSummary.module.scss b/src/components/RequestSummary/RequestSummary.module.scss
deleted file mode 100644
index e1752b3..0000000
--- a/src/components/RequestSummary/RequestSummary.module.scss
+++ /dev/null
@@ -1,24 +0,0 @@
1.requestSummary {
2 display: grid;
3 grid-template-columns: auto 1fr auto;
4 padding: 1em;
5 grid-gap: 1em;
6 align-items: center;
7}
8
9.method {
10}
11
12.statusCode {
13 padding: 0.2em;
14 border-radius: 0.4em;
15 background-color: darkgray;
16
17 &.info, &.success, &.redirect {
18 background-color: forestgreen;
19 }
20
21 &.clientError, &.serverError {
22 background-color: red;
23 }
24}
diff --git a/src/components/RequestSummary/RequestSummary.tsx b/src/components/RequestSummary/RequestSummary.tsx
index ea28f3e..b3e7ddc 100644
--- a/src/components/RequestSummary/RequestSummary.tsx
+++ b/src/components/RequestSummary/RequestSummary.tsx
@@ -2,7 +2,6 @@ import {RequestResponse} from "~hooks/useRequests";
2import * as React from "react"; 2import * as React from "react";
3import classNames from "classnames"; 3import classNames from "classnames";
4 4
5import styles from './RequestSummary.module.scss';
6import {Badge, Card, Col, Row} from "react-bootstrap"; 5import {Badge, Card, Col, Row} from "react-bootstrap";
7 6
8interface RequestSummaryProps { 7interface RequestSummaryProps {