chore: fix broken test & components refactoring

This commit is contained in:
Oprysk 2021-12-10 15:04:46 +02:00 committed by Oprysk Vyacheslav
parent a42d29d5c9
commit 6c41e95aa0
6 changed files with 91 additions and 71 deletions

View File

@ -1,40 +1,47 @@
import { observer } from 'mobx-react';
import * as React from 'react'; import * as React from 'react';
import { observer } from 'mobx-react';
import { ResponseModel } from '../../services/models'; import type { ResponseModel, MediaTypeModel } from '../../services/models';
import { ResponseDetails } from './ResponseDetails'; import { ResponseDetails } from './ResponseDetails';
import { ResponseDetailsWrap, StyledResponseTitle } from './styled.elements'; import { ResponseDetailsWrap, StyledResponseTitle } from './styled.elements';
@observer export interface ResponseViewProps {
export class ResponseView extends React.Component<{ response: ResponseModel }> { response: ResponseModel;
toggle = () => {
this.props.response.toggle();
};
render() {
const { extensions, headers, type, summary, description, code, expanded, content } = this.props.response;
const mimes =
content === undefined ? [] : content.mediaTypes.filter(mime => mime.schema !== undefined);
const empty = (!extensions || Object.keys(extensions).length === 0) &&
headers.length === 0 && mimes.length === 0 && !description;
return (
<div>
<StyledResponseTitle
onClick={this.toggle}
type={type}
empty={empty}
title={summary || ''}
code={code}
opened={expanded}
/>
{expanded && !empty && (
<ResponseDetailsWrap>
<ResponseDetails response={this.props.response} />
</ResponseDetailsWrap>
)}
</div>
);
}
} }
export const ResponseView = observer(({ response }: ResponseViewProps): React.ReactElement => {
const { extensions, headers, type, summary, description, code, expanded, content } = response;
const mimes = React.useMemo<MediaTypeModel[]>(
() =>
content === undefined ? [] : content.mediaTypes.filter(mime => mime.schema !== undefined),
[content],
);
const empty = React.useMemo<boolean>(
() =>
(!extensions || Object.keys(extensions).length === 0) &&
headers.length === 0 &&
mimes.length === 0 &&
!description,
[extensions, headers, mimes, description],
);
return (
<div>
<StyledResponseTitle
onClick={response.toggle}
type={type}
empty={empty}
title={summary || ''}
code={code}
opened={expanded}
/>
{expanded && !empty && (
<ResponseDetailsWrap>
<ResponseDetails response={response} />
</ResponseDetailsWrap>
)}
</div>
);
});

View File

@ -14,27 +14,34 @@ export interface ResponseTitleProps {
onClick?: () => void; onClick?: () => void;
} }
export class ResponseTitle extends React.PureComponent<ResponseTitleProps> { function ResponseTitleComponent({
render() { title,
const { title, type, empty, code, opened, className, onClick } = this.props; type,
return ( empty,
<button code,
className={className} opened,
onClick={(!empty && onClick) || undefined} className,
aria-expanded={opened} onClick,
disabled={empty} }: ResponseTitleProps): React.ReactElement {
> return (
{!empty && ( <button
<ShelfIcon className={className}
size={'1.5em'} onClick={(!empty && onClick) || undefined}
color={type} aria-expanded={opened}
direction={opened ? 'down' : 'right'} disabled={empty}
float={'left'} >
/> {!empty && (
)} <ShelfIcon
<Code>{code} </Code> size={'1.5em'}
<Markdown compact={true} inline={true} source={title} /> color={type}
</button> direction={opened ? 'down' : 'right'}
); float={'left'}
} />
)}
<Code>{code} </Code>
<Markdown compact={true} inline={true} source={title} />
</button>
);
} }
export const ResponseTitle = React.memo<ResponseTitleProps>(ResponseTitleComponent);

View File

@ -11,14 +11,12 @@ export const StyledResponseTitle = styled(ResponseTitle)`
border-radius: 2px; border-radius: 2px;
margin-bottom: 4px; margin-bottom: 4px;
line-height: 1.5em; line-height: 1.5em;
background-color: #f2f2f2;
cursor: pointer; cursor: pointer;
color: ${props => props.theme.colors.responses[props.type].color}; color: ${props => props.theme.colors.responses[props.type].color};
background-color: ${props => props.theme.colors.responses[props.type].backgroundColor}; background-color: ${props => props.theme.colors.responses[props.type].backgroundColor};
&:focus { &:focus {
outline: auto; outline: auto ${props => props.theme.colors.responses[props.type].color};
outline-color: ${props => props.theme.colors.responses[props.type].color};
} }
${props => ${props =>
(props.empty && (props.empty &&

View File

@ -42,9 +42,16 @@ describe('Models', () => {
test('ensure extensions are shown if showExtensions is true', () => { test('ensure extensions are shown if showExtensions is true', () => {
const options = new RedocNormalizedOptions({ showExtensions: true }); const options = new RedocNormalizedOptions({ showExtensions: true });
const resp = new ResponseModel(parser, 'default', true, { 'x-example': {a: 1} } as any, options); const resp = new ResponseModel({
parser,
code: 'default',
defaultAsError: true,
infoOrRef: { 'x-example': { a: 1 } },
options,
isEvent: true,
});
expect(Object.keys(resp.extensions).length).toEqual(1); expect(Object.keys(resp.extensions).length).toEqual(1);
expect(resp.extensions['x-example']).toEqual({a: 1}); expect(resp.extensions['x-example']).toEqual({ a: 1 });
}); });
}); });
}); });

View File

@ -17,8 +17,7 @@ export class RequestBodyModel {
required: boolean; required: boolean;
content?: MediaContentModel; content?: MediaContentModel;
constructor(props: RequestBodyProps) { constructor({ parser, infoOrRef, options, isEvent }: RequestBodyProps) {
const { parser, infoOrRef, options, isEvent } = props;
const isRequest = !isEvent; const isRequest = !isEvent;
const info = parser.deref(infoOrRef); const info = parser.deref(infoOrRef);
this.description = info.description || ''; this.description = info.description || '';

View File

@ -2,10 +2,7 @@ import { action, observable, makeObservable } from 'mobx';
import { OpenAPIResponse, Referenced } from '../../types'; import { OpenAPIResponse, Referenced } from '../../types';
import { import { getStatusCodeType, extractExtensions } from '../../utils';
getStatusCodeType,
extractExtensions
} from '../../utils';
import { OpenAPIParser } from '../OpenAPIParser'; import { OpenAPIParser } from '../OpenAPIParser';
import { RedocNormalizedOptions } from '../RedocNormalizedOptions'; import { RedocNormalizedOptions } from '../RedocNormalizedOptions';
import { FieldModel } from './Field'; import { FieldModel } from './Field';
@ -32,9 +29,14 @@ export class ResponseModel {
headers: FieldModel[] = []; headers: FieldModel[] = [];
extensions: Record<string, any>; extensions: Record<string, any>;
constructor(props: ResponseProps) { constructor({
const { parser, code, defaultAsError, infoOrRef, options, isEvent } = props; parser,
const isRequest = isEvent ? true : false; code,
defaultAsError,
infoOrRef,
options,
isEvent: isRequest,
}: ResponseProps) {
makeObservable(this); makeObservable(this);
this.expanded = options.expandResponses === 'all' || options.expandResponses[code]; this.expanded = options.expandResponses === 'all' || options.expandResponses[code];