Skip to content

Commit

Permalink
Lift up debug page (#4599)
Browse files Browse the repository at this point in the history
* lift up debug page

* address comments + stylistic improvements

* set debug form open for 3 params

* fix debug form opening constantly

* don't close the debug page in useEffect if already open
  • Loading branch information
Dogacel authored Feb 28, 2023
1 parent d661d49 commit ff25d6f
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 129 deletions.
290 changes: 169 additions & 121 deletions docs-client/src/containers/MethodPage/DebugPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
* under the License.
*/

import Alert from '@material-ui/lab/Alert';
import Button from '@material-ui/core/Button';
import Grid from '@material-ui/core/Grid';
import IconButton from '@material-ui/core/IconButton';
import Snackbar from '@material-ui/core/Snackbar';
Expand All @@ -26,6 +24,7 @@ import DeleteSweepIcon from '@material-ui/icons/DeleteSweep';
import FileCopyIcon from '@material-ui/icons/FileCopy';
import React, {
ChangeEvent,
Dispatch,
useCallback,
useEffect,
useMemo,
Expand All @@ -38,7 +37,15 @@ import json from 'react-syntax-highlighter/dist/esm/languages/hljs/json';

import jsonMinify from 'jsonminify';
import { RouteComponentProps } from 'react-router';
import Section from '../../components/Section';
import {
Dialog,
DialogActions,
DialogContent,
DialogTitle,
} from '@material-ui/core';
import Button from '@material-ui/core/Button';
import Alert from '@material-ui/lab/Alert';
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
import { docServiceDebug } from '../../lib/header-provider';
import jsonPrettify from '../../lib/json-prettify';
import { Method } from '../../lib/specification';
Expand All @@ -50,6 +57,18 @@ import HttpQueryString from './HttpQueryString';
import RequestBody from './RequestBody';
import GraphqlRequestBody from './GraphqlRequestBody';

const useStyles = makeStyles((theme: Theme) =>
createStyles({
actionDialog: {
justifyContent: 'space-between',
margin: theme.spacing(1),
},
responseGrid: {
borderLeft: `2px solid ${theme.palette.divider}`,
},
}),
);

SyntaxHighlighter.registerLanguage('json', json);

interface OwnProps {
Expand All @@ -61,6 +80,8 @@ interface OwnProps {
exampleQueries: SelectOption[];
exactPathMapping: boolean;
useRequestBody: boolean;
debugFormIsOpen: boolean;
setDebugFormIsOpen: Dispatch<React.SetStateAction<boolean>>;
}

type Props = OwnProps & RouteComponentProps;
Expand Down Expand Up @@ -92,13 +113,6 @@ const copyTextToClipboard = (text: string) => {
document.body.removeChild(textArea);
};

const scrollToDebugForm = () => {
const scrollNode = document.getElementById('debug-form');
if (scrollNode) {
scrollNode.scrollIntoView({ behavior: 'smooth' });
}
};

const toggle = (prev: boolean, override: unknown) => {
if (typeof override === 'boolean') {
return override;
Expand All @@ -125,6 +139,8 @@ const DebugPage: React.FunctionComponent<Props> = ({
match,
method,
useRequestBody,
debugFormIsOpen,
setDebugFormIsOpen,
}) => {
const [requestBodyOpen, toggleRequestBodyOpen] = useReducer(toggle, true);
const [requestBody, setRequestBody] = useState('');
Expand All @@ -149,6 +165,8 @@ const DebugPage: React.FunctionComponent<Props> = ({
false,
);

const classes = useStyles();

const transport = TRANSPORTS.getDebugTransport(method);
if (!transport) {
throw new Error("This method doesn't have a debug transport.");
Expand All @@ -157,11 +175,10 @@ const DebugPage: React.FunctionComponent<Props> = ({
useEffect(() => {
const urlParams = new URLSearchParams(location.search);

let urlRequestBody;
let urlRequestBody = '';
if (useRequestBody) {
if (urlParams.has('request_body')) {
urlRequestBody = jsonPrettify(urlParams.get('request_body')!);
scrollToDebugForm();
}
}

Expand All @@ -180,7 +197,7 @@ const DebugPage: React.FunctionComponent<Props> = ({
)?.pathMapping || '';
}

const urlQueries = isAnnotatedService ? urlParams.get('queries') : '';
const urlQueries = isAnnotatedService ? urlParams.get('queries') ?? '' : '';

if (!keepDebugResponse) {
setDebugResponse('');
Expand All @@ -190,6 +207,9 @@ const DebugPage: React.FunctionComponent<Props> = ({
setRequestBody(urlRequestBody || method.exampleRequests[0] || '');
setAdditionalPath(urlPath || '');
setAdditionalQueries(urlQueries || '');
setDebugFormIsOpen(
(isOpen) => isOpen || urlRequestBody !== '' || urlQueries !== '',
);
}, [
exactPathMapping,
exampleQueries.length,
Expand All @@ -201,6 +221,7 @@ const DebugPage: React.FunctionComponent<Props> = ({
transport,
useRequestBody,
keepDebugResponse,
setDebugFormIsOpen,
]);

/* eslint-disable react-hooks/exhaustive-deps */
Expand Down Expand Up @@ -534,16 +555,22 @@ const DebugPage: React.FunctionComponent<Props> = ({
});
}, [isAnnotatedService, isGraphqlService, transport, method, examplePaths]);

const [debugAlertIsOpen, setDebugAlertIsOpen] = React.useState(true);

return (
<Section>
<div id="debug-form">
<Typography variant="body2" paragraph />
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<Typography variant="h6" paragraph>
Debug
</Typography>
<Alert severity="info">
<div>
<Dialog
onClose={() => setDebugFormIsOpen(false)}
open={debugFormIsOpen}
fullWidth
maxWidth="lg"
>
<DialogTitle id="customized-dialog-title">
<Typography variant="h6" paragraph>
Debug
</Typography>
{debugAlertIsOpen && (
<Alert severity="info" onClose={() => setDebugAlertIsOpen(false)}>
You can set the default values by{' '}
<a
href="https://armeria.dev/docs/server-docservice/#example-requests-and-headers"
Expand All @@ -554,112 +581,133 @@ const DebugPage: React.FunctionComponent<Props> = ({
</a>
.
</Alert>
<EndpointPath
examplePaths={supportedExamplePaths}
editable={!exactPathMapping}
isAnnotatedService={isAnnotatedService}
isGraphqlService={isGraphqlService}
endpointPathOpen={endpointPathOpen}
additionalPath={additionalPath}
onEditEndpointPathClick={toggleEndpointPathOpen}
onPathFormChange={onPathFormChange}
onSelectedPathChange={onSelectedPathChange}
/>
{isAnnotatedService && (
<HttpQueryString
exampleQueries={exampleQueries}
additionalQueriesOpen={additionalQueriesOpen}
additionalQueries={additionalQueries}
onEditHttpQueriesClick={toggleAdditionalQueriesOpen}
onQueriesFormChange={onQueriesFormChange}
onSelectedQueriesChange={onSelectedQueriesChange}
/>
)}
<HttpHeaders
exampleHeaders={exampleHeaders}
additionalHeadersOpen={additionalHeadersOpen}
additionalHeaders={additionalHeaders}
stickyHeaders={stickyHeaders}
onEditHttpHeadersClick={toggleAdditionalHeadersOpen}
onSelectedHeadersChange={onSelectedHeadersChange}
onHeadersFormChange={onHeadersFormChange}
onStickyHeadersChange={toggleStickyHeaders}
/>
{useRequestBody && isGraphqlService ? (
<GraphqlRequestBody
requestBodyOpen={requestBodyOpen}
requestBody={requestBody}
onEditRequestBodyClick={toggleRequestBodyOpen}
onDebugFormChange={onDebugFormChange}
schemaUrlPath={extractUrlPath(method)}
/>
) : (
<RequestBody
exampleRequests={method.exampleRequests}
onSelectedRequestBodyChange={onSelectedRequestBodyChange}
requestBodyOpen={requestBodyOpen}
requestBody={requestBody}
onEditRequestBodyClick={toggleRequestBodyOpen}
onDebugFormChange={onDebugFormChange}
/>
)}
)}
</DialogTitle>
<DialogContent dividers>
<div id="debug-form">
<Typography variant="body2" paragraph />
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<EndpointPath
examplePaths={supportedExamplePaths}
editable={!exactPathMapping}
isAnnotatedService={isAnnotatedService}
isGraphqlService={isGraphqlService}
endpointPathOpen={endpointPathOpen}
additionalPath={additionalPath}
onEditEndpointPathClick={toggleEndpointPathOpen}
onPathFormChange={onPathFormChange}
onSelectedPathChange={onSelectedPathChange}
/>
{isAnnotatedService && (
<HttpQueryString
exampleQueries={exampleQueries}
additionalQueriesOpen={additionalQueriesOpen}
additionalQueries={additionalQueries}
onEditHttpQueriesClick={toggleAdditionalQueriesOpen}
onQueriesFormChange={onQueriesFormChange}
onSelectedQueriesChange={onSelectedQueriesChange}
/>
)}
<HttpHeaders
exampleHeaders={exampleHeaders}
additionalHeadersOpen={additionalHeadersOpen}
additionalHeaders={additionalHeaders}
stickyHeaders={stickyHeaders}
onEditHttpHeadersClick={toggleAdditionalHeadersOpen}
onSelectedHeadersChange={onSelectedHeadersChange}
onHeadersFormChange={onHeadersFormChange}
onStickyHeadersChange={toggleStickyHeaders}
/>
{useRequestBody && isGraphqlService ? (
<GraphqlRequestBody
requestBodyOpen={requestBodyOpen}
requestBody={requestBody}
onEditRequestBodyClick={toggleRequestBodyOpen}
onDebugFormChange={onDebugFormChange}
schemaUrlPath={extractUrlPath(method)}
/>
) : (
<RequestBody
exampleRequests={method.exampleRequests}
onSelectedRequestBodyChange={onSelectedRequestBodyChange}
requestBodyOpen={requestBodyOpen}
requestBody={requestBody}
onEditRequestBodyClick={toggleRequestBodyOpen}
onDebugFormChange={onDebugFormChange}
/>
)}
<Typography variant="body2" paragraph />
</Grid>
<Grid item xs={12} sm={6} className={classes.responseGrid}>
<Grid container spacing={1}>
<Grid item xs="auto">
<Tooltip title="Copy response">
<div>
<IconButton
onClick={onCopy}
disabled={debugResponse.length === 0}
>
<FileCopyIcon />
</IconButton>
</div>
</Tooltip>
</Grid>
<Grid item xs="auto">
<Tooltip title="Clear response">
<div>
<IconButton
onClick={onClear}
disabled={debugResponse.length === 0}
>
<DeleteSweepIcon />
</IconButton>
</div>
</Tooltip>
</Grid>
</Grid>
<SyntaxHighlighter
language="json"
style={githubGist}
wrapLines={false}
>
{debugResponse}
</SyntaxHighlighter>
</Grid>
</Grid>
<Snackbar
open={snackbarOpen}
message={snackbarMessage}
autoHideDuration={3000}
onClose={dismissSnackbar}
action={
<IconButton color="inherit" onClick={dismissSnackbar}>
<CloseIcon />
</IconButton>
}
/>
</div>
</DialogContent>
<DialogActions className={classes.actionDialog}>
<div>
<Button variant="contained" color="primary" onClick={onSubmit}>
Submit
</Button>
<Button variant="text" color="secondary" onClick={onExport}>
Copy as a curl command
</Button>
</Grid>
<Grid item xs={12} sm={6}>
<Grid container spacing={1}>
<Grid item xs="auto">
<Tooltip title="Copy response">
<div>
<IconButton
onClick={onCopy}
disabled={debugResponse.length === 0}
>
<FileCopyIcon />
</IconButton>
</div>
</Tooltip>
</Grid>
<Grid item xs="auto">
<Tooltip title="Clear response">
<div>
<IconButton
onClick={onClear}
disabled={debugResponse.length === 0}
>
<DeleteSweepIcon />
</IconButton>
</div>
</Tooltip>
</Grid>
</Grid>
<SyntaxHighlighter
language="json"
style={githubGist}
wrapLines={false}
>
{debugResponse}
</SyntaxHighlighter>
</Grid>
</Grid>
<Snackbar
open={snackbarOpen}
message={snackbarMessage}
autoHideDuration={3000}
onClose={dismissSnackbar}
action={
<IconButton color="inherit" onClick={dismissSnackbar}>
<CloseIcon />
</IconButton>
}
/>
</div>
</Section>
</div>
<Button
autoFocus
onClick={() => setDebugFormIsOpen(false)}
variant="contained"
color="primary"
>
Close
</Button>
</DialogActions>
</Dialog>
</div>
);
};

Expand Down
Loading

0 comments on commit ff25d6f

Please sign in to comment.