diff --git a/src/components/CallbackSamples/CallbackSamples.tsx b/src/components/CallbackSamples/CallbackSamples.tsx new file mode 100644 index 0000000000..0edfca786f --- /dev/null +++ b/src/components/CallbackSamples/CallbackSamples.tsx @@ -0,0 +1,87 @@ +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { isPayloadSample, RedocNormalizedOptions } from '../../services'; +import { PayloadSamples } from '../PayloadSamples/PayloadSamples'; +import { SourceCodeWithCopy } from '../SourceCode/SourceCode'; + +import { RightPanelHeader, Tab, TabList, TabPanel, Tabs } from '../../common-elements'; +import { OptionsContext } from '../OptionsProvider'; +import { CallbackModel } from '../../services/models'; +import { Endpoint } from '../Endpoint/Endpoint'; + +export interface CallbackSamplesProps { + callbacks: CallbackModel[]; +} + +@observer +export class CallbackSamples extends React.Component { + static contextType = OptionsContext; + context: RedocNormalizedOptions; + + render() { + const { callbacks } = this.props; + + // Sums number of code samples per operation per callback + const numSamples = callbacks.reduce( + (callbackSum, callback) => + callbackSum + + callback.operations.reduce( + (sampleSum, operation) => sampleSum + operation.codeSamples.length, + 0, + ), + 0, + ); + + const hasSamples = numSamples > 0; + const hideTabList = numSamples === 1 ? this.context.hideSingleRequestSampleTab : false; + + const renderTabs = () => { + return callbacks.map(callback => { + return callback.operations.map(operation => { + return operation.codeSamples.map(sample => { + return ( + + {operation.name} {sample.label !== undefined ? sample.label : sample.lang} + + ); + }); + }); + }); + }; + + const renderTabPanels = () => { + return callbacks.map(callback => { + return callback.operations.map(operation => { + return operation.codeSamples.map(sample => { + return ( + + {isPayloadSample(sample) ? ( +
+ + +
+ ) : ( + + )} +
+ ); + }); + }); + }); + }; + + return ( + (hasSamples && ( +
+ Callback samples + + + + {renderTabPanels()} + +
+ )) || + null + ); + } +} diff --git a/src/components/Callbacks/Callback.tsx b/src/components/Callbacks/Callback.tsx index ffec7f6c18..761f350486 100644 --- a/src/components/Callbacks/Callback.tsx +++ b/src/components/Callbacks/Callback.tsx @@ -1,23 +1,29 @@ import { observer } from 'mobx-react'; import * as React from 'react'; -import { CallbackModel } from '../../services/models'; +import { OperationModel } from '../../services/models'; +import { CallbackDetails } from './CallbackDetails'; import { CallbackDetailsWrap, StyledCallbackTitle } from '../Callbacks/styled.elements'; @observer -export class CallbackView extends React.Component<{ callback: CallbackModel }> { +export class CallbackView extends React.Component<{ callbackOperation: OperationModel }> { toggle = () => { - this.props.callback.toggle(); + this.props.callbackOperation.toggle(); }; render() { - const { name, expanded } = this.props.callback; + const { name, description, expanded } = this.props.callbackOperation; return (
- + {expanded && ( - {name} + )}
diff --git a/src/components/Callbacks/CallbackDetails.tsx b/src/components/Callbacks/CallbackDetails.tsx new file mode 100644 index 0000000000..e84bc091de --- /dev/null +++ b/src/components/Callbacks/CallbackDetails.tsx @@ -0,0 +1,9 @@ +import * as React from 'react'; +import { OperationModel } from '../../services/models'; +import { OperationItem } from '../ContentItems/ContentItems'; + +export class CallbackDetails extends React.PureComponent<{ callbackOperation: OperationModel }> { + render() { + return ; + } +} diff --git a/src/components/Callbacks/CallbackTitle.tsx b/src/components/Callbacks/CallbackTitle.tsx index f594238e20..b72fc45679 100644 --- a/src/components/Callbacks/CallbackTitle.tsx +++ b/src/components/Callbacks/CallbackTitle.tsx @@ -1,9 +1,11 @@ import * as React from 'react'; import { ShelfIcon } from '../../common-elements'; +import { Markdown } from '../Markdown/Markdown'; export interface CallbackTitleProps { name: string; + description?: string; opened?: boolean; className?: string; onClick?: () => void; @@ -11,11 +13,12 @@ export interface CallbackTitleProps { export class CallbackTitle extends React.PureComponent { render() { - const { name, opened, className, onClick } = this.props; + const { name, description, opened, className, onClick } = this.props; return (
- + {name} + {description && }
); } diff --git a/src/components/Callbacks/CallbacksList.tsx b/src/components/Callbacks/CallbacksList.tsx index 826cdb2a3f..ce108ccbba 100644 --- a/src/components/Callbacks/CallbacksList.tsx +++ b/src/components/Callbacks/CallbacksList.tsx @@ -27,7 +27,9 @@ export class CallbacksList extends React.PureComponent {
Callbacks {callbacks.map(callback => { - return ; + return callback.operations.map(operation => { + return ; + }); })}
); diff --git a/src/components/ContentItems/ContentItems.tsx b/src/components/ContentItems/ContentItems.tsx index 61fa1bdc0d..1963f5861a 100644 --- a/src/components/ContentItems/ContentItems.tsx +++ b/src/components/ContentItems/ContentItems.tsx @@ -8,15 +8,6 @@ import { Operation } from '..'; import { H1, H2, MiddlePanel, Row, Section, ShareLink } from '../../common-elements'; import { ContentItemModel } from '../../services'; import { GroupModel, OperationModel } from '../../services/models'; -import styled from '../../styled-components'; - -const CallbacksHeader = styled.h3` - font-size: 18px; - padding: 0 40px; - margin: 3em 0 1.1em; - color: #253137; - font-weight: normal; -`; @observer export class ContentItems extends React.Component<{ @@ -28,18 +19,6 @@ export class ContentItems extends React.Component<{ return null; } return items.map(item => { - if (item.type === 'operation' && item.callbacks.length > 0) { - return ( - - - Callbacks - {item.callbacks.map((callbackIndex, idx) => { - return ; - })} - - ); - } - return ; }); } diff --git a/src/components/Operation/Operation.tsx b/src/components/Operation/Operation.tsx index 1283a6ad89..aff0cb0bcb 100644 --- a/src/components/Operation/Operation.tsx +++ b/src/components/Operation/Operation.tsx @@ -15,11 +15,18 @@ import { Parameters } from '../Parameters/Parameters'; import { RequestSamples } from '../RequestSamples/RequestSamples'; import { ResponsesList } from '../Responses/ResponsesList'; import { ResponseSamples } from '../ResponseSamples/ResponseSamples'; +import { CallbacksList } from '../Callbacks'; +import { CallbackSamples } from '../CallbackSamples/CallbackSamples'; import { OperationModel as OperationType } from '../../services/models'; import styled from '../../styled-components'; import { Extensions } from '../Fields/Extensions'; +const CallbackMiddlePanel = styled(MiddlePanel)` + width: 100%; + padding: 0; +`; + const OperationRow = styled(Row)` backface-visibility: hidden; contain: content; @@ -42,18 +49,23 @@ export class Operation extends React.Component { const { name: summary, description, deprecated, externalDocs } = operation; const hasDescription = !!(description || externalDocs); + const AdaptiveMiddlePanel = operation.isCallback ? CallbackMiddlePanel : MiddlePanel; return ( {options => ( - -

- - {summary} {deprecated && Deprecated } -

- {options.pathInMiddlePanel && } - {hasDescription && ( + + {!operation.isCallback && ( +

+ + {summary} {deprecated && Deprecated } +

+ )} + {!operation.isCallback && options.pathInMiddlePanel && ( + + )} + {!operation.isCallback && hasDescription && ( {description !== undefined && } {externalDocs && } @@ -63,12 +75,18 @@ export class Operation extends React.Component { -
- - {!options.pathInMiddlePanel && } - - - + + + {!operation.isCallback && ( + + {!options.pathInMiddlePanel && } + + + {operation.callbacks.length > 0 && ( + + )} + + )}
)}
diff --git a/src/components/__tests__/Callbacks.test.tsx b/src/components/__tests__/Callbacks.test.tsx index b4ac67ef1f..d33705d871 100644 --- a/src/components/__tests__/Callbacks.test.tsx +++ b/src/components/__tests__/Callbacks.test.tsx @@ -22,7 +22,7 @@ describe('Components', () => { options, ); const callbackViewElement = shallow( - , + , ).getElement(); expect(callbackViewElement.props).toBeDefined(); expect(callbackViewElement.props.children).toBeDefined(); diff --git a/src/services/models/Operation.ts b/src/services/models/Operation.ts index 48bf07f73a..f8c8f37d95 100644 --- a/src/services/models/Operation.ts +++ b/src/services/models/Operation.ts @@ -173,6 +173,14 @@ export class OperationModel implements IMenuItem { this.active = false; } + /** + * Toggle expansion in middle panel (for callbacks, which are operations) + */ + @action + toggle() { + this.expanded = !this.expanded; + } + expand() { if (this.parent) { this.parent.expand();