feat: remove auth section (#2022)

This commit is contained in:
Anastasiia Derymarko 2022-05-30 18:55:39 +03:00 committed by GitHub
parent b98c7a0d34
commit a863302cc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 653 additions and 339 deletions

View File

@ -232,7 +232,6 @@ You can use all of the following options with the standalone version of the <red
* `lazyRendering` - _Not implemented yet_ ~~if set, enables lazy rendering mode in ReDoc. This mode is useful for APIs with big number of operations (e.g. > 50). In this mode ReDoc shows initial screen ASAP and then renders the rest operations asynchronously while showing progress bar on the top. Check out the [demo](\\redocly.github.io/redoc) for the example.~~ * `lazyRendering` - _Not implemented yet_ ~~if set, enables lazy rendering mode in ReDoc. This mode is useful for APIs with big number of operations (e.g. > 50). In this mode ReDoc shows initial screen ASAP and then renders the rest operations asynchronously while showing progress bar on the top. Check out the [demo](\\redocly.github.io/redoc) for the example.~~
* `menuToggle` - if true clicking second time on expanded menu item will collapse it, default `true`. * `menuToggle` - if true clicking second time on expanded menu item will collapse it, default `true`.
* `nativeScrollbars` - use native scrollbar for sidemenu instead of perfect-scroll (scrolling performance optimization for big specs). * `nativeScrollbars` - use native scrollbar for sidemenu instead of perfect-scroll (scrolling performance optimization for big specs).
* `noAutoAuth` - do not inject Authentication section automatically.
* `onlyRequiredInSamples` - shows only required fields in request samples. * `onlyRequiredInSamples` - shows only required fields in request samples.
* `pathInMiddlePanel` - show path link and HTTP verb in the middle panel instead of the right one. * `pathInMiddlePanel` - show path link and HTTP verb in the middle panel instead of the right one.
* `requiredPropsFirst` - show required properties first ordered in the same order as in `required` array. * `requiredPropsFirst` - show required properties first ordered in the same order as in `required` array.

View File

@ -0,0 +1,71 @@
import * as React from 'react';
import { OpenAPISecurityScheme } from '../../types';
import { SecurityRow } from './styled.elements';
import { SeeMore } from '../SeeMore/SeeMore';
import { Markdown } from '../Markdown/Markdown';
export interface OAuthFlowProps {
type: string;
flow: OpenAPISecurityScheme['flows'][keyof OpenAPISecurityScheme['flows']];
RequiredScopes?: JSX.Element;
}
export function OAuthFlowComponent(props: OAuthFlowProps) {
const { type, flow, RequiredScopes } = props;
const scopesNames = Object.keys(flow?.scopes || {});
console.log('rended');
return (
<>
<SecurityRow>
<b>Flow type: </b>
<code>{type} </code>
</SecurityRow>
{(type === 'implicit' || type === 'authorizationCode') && (
<SecurityRow>
<strong> Authorization URL: </strong>
<code>
<a target="_blank" rel="noopener noreferrer" href={(flow as any).authorizationUrl}>
{(flow as any).authorizationUrl}
</a>
</code>
</SecurityRow>
)}
{(type === 'password' || type === 'clientCredentials' || type === 'authorizationCode') && (
<SecurityRow>
<b> Token URL: </b>
<code>{(flow as any).tokenUrl}</code>
</SecurityRow>
)}
{flow!.refreshUrl && (
<SecurityRow>
<strong> Refresh URL: </strong>
{flow!.refreshUrl}
</SecurityRow>
)}
{!!scopesNames.length && (
<>
{RequiredScopes || null}
<SecurityRow>
<b> Scopes: </b>
</SecurityRow>
<SeeMore height="4em">
<ul>
{scopesNames.map(scope => (
<li key={scope}>
<code>{scope}</code> -{' '}
<Markdown
className={'redoc-markdown'}
inline={true}
source={flow!.scopes[scope] || ''}
/>
</li>
))}
</ul>
</SeeMore>
</>
)}
</>
);
}
export const OAuthFlow = React.memo<OAuthFlowProps>(OAuthFlowComponent);

View File

@ -0,0 +1,18 @@
import * as React from 'react';
export const RequiredScopesRow = ({ scopes }: { scopes: string[] }): JSX.Element | null => {
if (!scopes.length) return null;
return (
<div>
<b>Required scopes: </b>
{scopes.map((scope, idx) => {
return (
<React.Fragment key={idx}>
<code>{scope}</code>{' '}
</React.Fragment>
);
})}
</div>
);
};

View File

@ -0,0 +1,65 @@
import * as React from 'react';
import { SecuritySchemeModel } from '../../services';
import { titleize } from '../../utils';
import { StyledMarkdownBlock } from '../Markdown/styled.elements';
import { SecurityRow } from './styled.elements';
import { OAuthFlow } from './OAuthFlow';
interface SecuritySchemaProps {
RequiredScopes?: JSX.Element;
scheme: SecuritySchemeModel;
}
export function SecurityDetails(props: SecuritySchemaProps) {
const { RequiredScopes, scheme } = props;
return (
<StyledMarkdownBlock>
{scheme.apiKey ? (
<>
<SecurityRow>
<b>{titleize(scheme.apiKey.in || '')} parameter name: </b>
<code>{scheme.apiKey.name}</code>
</SecurityRow>
{RequiredScopes}
</>
) : scheme.http ? (
<>
<SecurityRow>
<b>HTTP Authorization Scheme: </b>
<code>{scheme.http.scheme}</code>
</SecurityRow>
<SecurityRow>
{scheme.http.scheme === 'bearer' && scheme.http.bearerFormat && (
<>
<b>Bearer format: </b>
<code>{scheme.http.bearerFormat}</code>
</>
)}
</SecurityRow>
{RequiredScopes}
</>
) : scheme.openId ? (
<>
<SecurityRow>
<b>Connect URL: </b>
<code>
<a target="_blank" rel="noopener noreferrer" href={scheme.openId.connectUrl}>
{scheme.openId.connectUrl}
</a>
</code>
</SecurityRow>
{RequiredScopes}
</>
) : scheme.flows ? (
Object.keys(scheme.flows).map(type => (
<OAuthFlow
key={type}
type={type}
RequiredScopes={RequiredScopes}
flow={scheme.flows[type]}
/>
))
) : null}
</StyledMarkdownBlock>
);
}

View File

@ -0,0 +1,43 @@
import { SecurityRequirementModel } from '../../services/models/SecurityRequirement';
import {
ScopeName,
SecurityRequirementAndWrap,
SecurityRequirementOrWrap,
} from './styled.elements';
import * as React from 'react';
import { AUTH_TYPES } from '../SecuritySchemes/SecuritySchemes';
export interface SecurityRequirementProps {
security: SecurityRequirementModel;
showSecuritySchemeType?: boolean;
expanded: boolean;
}
export function SecurityHeader(props: SecurityRequirementProps) {
const { security, showSecuritySchemeType, expanded } = props;
const grouping = security.schemes.length > 1;
return (
<SecurityRequirementOrWrap expanded={expanded}>
{grouping && '('}
{security.schemes.map(scheme => {
return (
<SecurityRequirementAndWrap key={scheme.id}>
{showSecuritySchemeType && `${AUTH_TYPES[scheme.type] || scheme.type}: `}
<i>{scheme.displayName}</i>
{expanded && scheme.scopes.length
? [
' (',
scheme.scopes.map<React.ReactNode>(scope => (
<ScopeName key={scope}>{scope}</ScopeName>
)),
') ',
]
: null}
</SecurityRequirementAndWrap>
);
})}
{grouping && ') '}
</SecurityRequirementOrWrap>
);
}

View File

@ -1,153 +1,102 @@
import * as React from 'react'; import * as React from 'react';
import { useState } from 'react';
import styled, { media } from '../../styled-components';
import { Link, UnderlinedHeader } from '../../common-elements/';
import { SecurityRequirementModel } from '../../services/models/SecurityRequirement'; import { SecurityRequirementModel } from '../../services/models/SecurityRequirement';
import { linksCss } from '../Markdown/styled.elements'; import {
AuthHeader,
const ScopeNameList = styled.ul` AuthHeaderColumn,
display: inline; SecuritiesColumn,
list-style: none; SecurityDetailsStyle,
padding: 0; Wrap,
} from './styled.elements';
li { import { useStore } from '../StoreBuilder';
display: inherit; import { SecurityHeader } from './SecurityHeader';
import { RequiredScopesRow } from './RequiredScopesRow';
&:after { import { AUTH_TYPES } from '../SecuritySchemes/SecuritySchemes';
content: ','; import { Markdown } from '../Markdown/Markdown';
} import { SecurityDetails } from './SecurityDetails';
&:last-child:after { import { ShelfIcon } from '../../common-elements';
content: none;
}
}
`;
const ScopeName = styled.code`
font-size: ${props => props.theme.typography.code.fontSize};
font-family: ${props => props.theme.typography.code.fontFamily};
border: 1px solid ${({ theme }) => theme.colors.border.dark};
margin: 0 3px;
padding: 0.2em;
display: inline-block;
line-height: 1;
`;
const SecurityRequirementAndWrap = styled.span`
&:after {
content: ' AND ';
font-weight: bold;
}
&:last-child:after {
content: none;
}
${linksCss};
`;
const SecurityRequirementOrWrap = styled.span`
&:before {
content: '( ';
font-weight: bold;
}
&:after {
content: ' ) OR ';
font-weight: bold;
}
&:last-child:after {
content: ' )';
}
&:only-child:before,
&:only-child:after {
content: none;
}
${linksCss};
`;
export interface SecurityRequirementProps {
security: SecurityRequirementModel;
}
export class SecurityRequirement extends React.PureComponent<SecurityRequirementProps> {
render() {
const security = this.props.security;
return (
<SecurityRequirementOrWrap>
{security.schemes.length ? (
security.schemes.map(scheme => {
return (
<SecurityRequirementAndWrap key={scheme.id}>
<Link to={scheme.sectionId}>{scheme.displayName}</Link>
{scheme.scopes.length > 0 && ' ('}
<ScopeNameList>
{scheme.scopes.map(scope => (
<li key={scope}>
<ScopeName>{scope}</ScopeName>
</li>
))}
</ScopeNameList>
{scheme.scopes.length > 0 && ') '}
</SecurityRequirementAndWrap>
);
})
) : (
<SecurityRequirementAndWrap>None</SecurityRequirementAndWrap>
)}
</SecurityRequirementOrWrap>
);
}
}
const AuthHeaderColumn = styled.div`
flex: 1 1 auto;
`;
const SecuritiesColumn = styled.div`
width: ${props => props.theme.schema.defaultDetailsWidth};
${media.lessThan('small')`
margin-top: 10px;
`}
`;
const AuthHeader = styled(UnderlinedHeader)`
display: inline-block;
margin: 0;
`;
const Wrap = styled.div`
width: 100%;
display: flex;
margin: 1em 0;
${media.lessThan('small')`
flex-direction: column;
`}
`;
export interface SecurityRequirementsProps { export interface SecurityRequirementsProps {
securities: SecurityRequirementModel[]; securities: SecurityRequirementModel[];
} }
export class SecurityRequirements extends React.PureComponent<SecurityRequirementsProps> { export function SecurityRequirements(props: SecurityRequirementsProps) {
render() { const store = useStore();
const securities = this.props.securities; const showSecuritySchemeType = store?.options.showSecuritySchemeType;
if (!securities.length) { const [expanded, setExpanded] = useState(false);
const { securities } = props;
if (!securities?.length) {
return null; return null;
} }
const operationSecuritySchemes = store?.spec.securitySchemes.schemes.filter(({ id }) => {
return securities.find(security => security.schemes.find(scheme => scheme.id === id));
});
return ( return (
<Wrap> <>
<AuthHeaderColumn> <Wrap expanded={expanded}>
<AuthHeaderColumn onClick={() => setExpanded(!expanded)}>
<AuthHeader>Authorizations:</AuthHeader> <AuthHeader>Authorizations:</AuthHeader>
<ShelfIcon size={'1.3em'} direction={expanded ? 'down' : 'right'} />
</AuthHeaderColumn> </AuthHeaderColumn>
<SecuritiesColumn> <SecuritiesColumn expanded={expanded}>
{securities.map((security, idx) => ( {securities.map((security, idx) => (
<SecurityRequirement key={idx} security={security} /> <SecurityHeader
key={idx}
expanded={expanded}
showSecuritySchemeType={showSecuritySchemeType}
security={security}
/>
))} ))}
</SecuritiesColumn> </SecuritiesColumn>
</Wrap> </Wrap>
{expanded &&
operationSecuritySchemes?.length &&
operationSecuritySchemes.map((scheme, idx) => (
<SecurityDetailsStyle key={idx}>
<h5>
<LockIcon /> {AUTH_TYPES[scheme.type] || scheme.type}: {scheme.id}
</h5>
<Markdown source={scheme.description || ''} />
<SecurityDetails
key={scheme.id}
scheme={scheme}
RequiredScopes={
<RequiredScopesRow scopes={getRequiredScopes(scheme.id, securities)} />
}
/>
</SecurityDetailsStyle>
))}
</>
); );
} }
const LockIcon = () => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="11" height="11">
<path
fill="currentColor"
d="M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z"
/>
</svg>
);
function getRequiredScopes(id: string, securities: SecurityRequirementModel[]): string[] {
const allScopes: string[] = [];
let securitiesLength = securities.length;
while (securitiesLength--) {
const security = securities[securitiesLength];
let schemesLength = security.schemes.length;
while (schemesLength--) {
const scheme = security.schemes[schemesLength];
if (scheme.id === id) {
allScopes.push(...scheme.scopes);
}
}
}
return Array.from(new Set(allScopes));
} }

View File

@ -0,0 +1,129 @@
import styled from 'styled-components';
import { linksCss } from '../Markdown/styled.elements';
import { media } from '../../styled-components';
import { UnderlinedHeader } from '../../common-elements';
export const Header = styled.div`
background-color: #e4e7eb;
`;
export const ScopeNameList = styled.ul`
display: inline;
list-style: none;
padding: 0;
li {
display: inherit;
&:after {
content: ',';
}
&:last-child:after {
content: none;
}
}
`;
export const ScopeName = styled.code`
font-size: ${props => props.theme.typography.code.fontSize};
font-family: ${props => props.theme.typography.code.fontFamily};
margin: 0 3px;
padding: 0.2em;
display: inline-block;
line-height: 1;
&:after {
content: ',';
font-weight: normal;
}
&:last-child:after {
content: none;
}
`;
export const SecurityRequirementAndWrap = styled.span`
&:after {
content: ' and ';
font-weight: normal;
}
&:last-child:after {
content: none;
}
${linksCss};
`;
export const SecurityRequirementOrWrap = styled.span<{ expanded?: boolean }>`
${p => !p.expanded && `white-space: nowrap;`}
&:after {
content: ' or ';
${p => p.expanded && `content: ' or \\a';`}
white-space: pre;
}
&:last-child:after,
&:only-child:after {
content: none;
}
${linksCss};
`;
export const AuthHeaderColumn = styled.div`
flex: 1 1 auto;
cursor: pointer;
`;
export const SecuritiesColumn = styled.div<{ expanded?: boolean }>`
width: ${props => props.theme.schema.defaultDetailsWidth};
text-overflow: ellipsis;
border-radius: 4px;
overflow: hidden;
${p =>
p.expanded &&
`background: ${p.theme.colors.gray['100']};
padding: 8px 9.6px;
margin: 20px 0;
width: 100%;
`};
${media.lessThan('small')`
margin-top: 10px;
`}
`;
export const AuthHeader = styled(UnderlinedHeader)`
display: inline-block;
margin: 0;
`;
export const Wrap = styled.div<{ expanded?: boolean }>`
width: 100%;
display: flex;
margin: 1em 0;
flex-direction: ${p => (p.expanded ? 'column' : 'row')};
${media.lessThan('small')`
flex-direction: column;
`}
`;
export const SecurityRow = styled.div`
margin: 0.5em 0;
`;
export const SecurityDetailsStyle = styled.div`
border-bottom: 1px solid ${({ theme }) => theme.colors.border.dark};
margin-bottom: 1.5em;
padding-bottom: 0.7em;
h5 {
line-height: 1em;
margin: 0 0 0.6em;
font-size: ${({ theme }) => theme.typography.fontSize};
}
.redoc-markdown p:first-child {
display: inline;
}
`;

View File

@ -1,72 +1,18 @@
import * as React from 'react'; import * as React from 'react';
import { SecuritySchemesModel } from '../../services/models'; import { SecuritySchemesModel } from '../../services';
import { H2, Row, ShareLink, MiddlePanel, Section } from '../../common-elements';
import { H2, MiddlePanel, Row, Section, ShareLink } from '../../common-elements';
import { OpenAPISecurityScheme } from '../../types';
import { titleize } from '../../utils/helpers';
import { Markdown } from '../Markdown/Markdown'; import { Markdown } from '../Markdown/Markdown';
import { StyledMarkdownBlock } from '../Markdown/styled.elements'; import { SecurityDetails } from '../SecurityRequirement/SecurityDetails';
import { SecurityDetailsStyle, SecurityRow } from '../SecurityRequirement/styled.elements';
const AUTH_TYPES = { export const AUTH_TYPES = {
oauth2: 'OAuth2', oauth2: 'OAuth2',
apiKey: 'API Key', apiKey: 'API Key',
http: 'HTTP', http: 'HTTP',
openIdConnect: 'OpenID Connect', openIdConnect: 'OpenID Connect',
}; };
export interface OAuthFlowProps {
type: string;
flow: OpenAPISecurityScheme['flows'][keyof OpenAPISecurityScheme['flows']];
}
export class OAuthFlow extends React.PureComponent<OAuthFlowProps> {
render() {
const { type, flow } = this.props;
const scopesNames = Object.keys(flow?.scopes || {});
return (
<tr>
<th> {type} OAuth Flow </th>
<td>
{type === 'implicit' || type === 'authorizationCode' ? (
<div>
<strong> Authorization URL: </strong>
{(flow as any).authorizationUrl}
</div>
) : null}
{type === 'password' || type === 'clientCredentials' || type === 'authorizationCode' ? (
<div>
<strong> Token URL: </strong>
{(flow as any).tokenUrl}
</div>
) : null}
{flow!.refreshUrl && (
<div>
<strong> Refresh URL: </strong>
{flow!.refreshUrl}
</div>
)}
{!!scopesNames.length && (
<>
<div>
<strong> Scopes: </strong>
</div>
<ul>
{scopesNames.map(scope => (
<li key={scope}>
<code>{scope}</code> -{' '}
<Markdown inline={true} source={flow!.scopes[scope] || ''} />
</li>
))}
</ul>
</>
)}
</td>
</tr>
);
}
}
export interface SecurityDefsProps { export interface SecurityDefsProps {
securitySchemes: SecuritySchemesModel; securitySchemes: SecuritySchemesModel;
} }
@ -82,52 +28,13 @@ export class SecurityDefs extends React.PureComponent<SecurityDefsProps> {
{scheme.displayName} {scheme.displayName}
</H2> </H2>
<Markdown source={scheme.description || ''} /> <Markdown source={scheme.description || ''} />
<StyledMarkdownBlock> <SecurityDetailsStyle>
<table className="security-details"> <SecurityRow>
<tbody> <b>Security Scheme Type: </b>
<tr> <span>{AUTH_TYPES[scheme.type] || scheme.type}</span>
<th> Security Scheme Type </th> </SecurityRow>
<td> {AUTH_TYPES[scheme.type] || scheme.type} </td> <SecurityDetails scheme={scheme} />
</tr> </SecurityDetailsStyle>
{scheme.apiKey ? (
<tr>
<th> {titleize(scheme.apiKey.in || '')} parameter name:</th>
<td> {scheme.apiKey.name} </td>
</tr>
) : scheme.http ? (
[
<tr key="scheme">
<th> HTTP Authorization Scheme </th>
<td> {scheme.http.scheme} </td>
</tr>,
scheme.http.scheme === 'bearer' && scheme.http.bearerFormat && (
<tr key="bearer">
<th> Bearer format </th>
<td> &quot;{scheme.http.bearerFormat}&quot; </td>
</tr>
),
]
) : scheme.openId ? (
<tr>
<th> Connect URL </th>
<td>
<a
target="_blank"
rel="noopener noreferrer"
href={scheme.openId.connectUrl}
>
{scheme.openId.connectUrl}
</a>
</td>
</tr>
) : scheme.flows ? (
Object.keys(scheme.flows).map(type => (
<OAuthFlow key={type} type={type} flow={scheme.flows[type]} />
))
) : null}
</tbody>
</table>
</StyledMarkdownBlock>
</MiddlePanel> </MiddlePanel>
</Row> </Row>
</Section> </Section>

View File

@ -0,0 +1,65 @@
import * as React from 'react';
import styled from 'styled-components';
const TOLERANCE_PX = 20;
interface SeeMoreProps {
children?: React.ReactNode;
height: string;
}
export function SeeMore({ children, height }: SeeMoreProps): JSX.Element {
const ref = React.createRef() as React.RefObject<HTMLDivElement>;
const [showMore, setShowMore] = React.useState(false);
const [showLink, setShowLink] = React.useState(false);
React.useEffect(() => {
if (ref.current && ref.current.clientHeight + TOLERANCE_PX < ref.current.scrollHeight) {
setShowLink(true);
}
}, [ref]);
const onClickMore = () => {
setShowMore(!showMore);
};
return (
<>
<Container
ref={ref}
className={showMore ? '' : 'container'}
style={{ height: showMore ? 'auto' : height }}
>
{children}
</Container>
<ButtonContainer dimmed={!showMore}>
{showLink && (
<ButtonLinkStyled onClick={onClickMore}>
{showMore ? 'See less' : 'See more'}
</ButtonLinkStyled>
)}
</ButtonContainer>
</>
);
}
const Container = styled.div`
overflow-y: hidden;
`;
const ButtonContainer = styled.div<{ dimmed?: boolean }>`
text-align: center;
line-height: 1.5em;
${({ dimmed }) =>
dimmed &&
`background-image: linear-gradient(to bottom, transparent,rgb(255 255 255));
position: relative;
top: -0.5em;
padding-top: 0.5em;
background-position-y: -1em;
`}
`;
const ButtonLinkStyled = styled.a`
cursor: pointer;
`;

View File

@ -1,5 +1,5 @@
import * as React from 'react'; import * as React from 'react';
import { createContext } from 'react'; import { createContext, useContext } from 'react';
import { AppStore } from '../services/'; import { AppStore } from '../services/';
import { RedocRawOptions } from '../services/RedocNormalizedOptions'; import { RedocRawOptions } from '../services/RedocNormalizedOptions';
@ -79,3 +79,7 @@ export function StoreBuilder(props: StoreBuilderProps) {
store, store,
}); });
} }
export function useStore(): AppStore | undefined {
return useContext(StoreContext);
}

View File

@ -1,28 +1,52 @@
import * as React from 'react'; import * as React from 'react';
import { shallow } from 'enzyme'; import { mount } from 'enzyme';
import { OpenAPIParser } from '../../services'; import {
import { SecurityRequirementModel } from '../../services/models/SecurityRequirement'; createStore,
import { SecurityRequirement } from '../SecurityRequirement/SecurityRequirement'; OpenAPIParser,
import { RedocNormalizedOptions } from '../../services/RedocNormalizedOptions'; OperationModel,
RedocNormalizedOptions,
SecuritySchemesModel,
} from '../../services';
import { StoreProvider } from '../StoreBuilder';
import { SecurityRequirements } from '../SecurityRequirement/SecurityRequirement';
import { withTheme } from '../testProviders';
import { SecurityDefs } from '../SecuritySchemes/SecuritySchemes';
import * as simpleSecurityFixture from './fixtures/simple-security-fixture.json';
const options = new RedocNormalizedOptions({});
describe('Components', () => {
describe('SecurityRequirement', () => { describe('SecurityRequirement', () => {
describe('SecurityRequirement', () => { it('should render authDefinition', async () => {
it("should render 'None' when empty object in security open api", () => { const store = await createStore(simpleSecurityFixture, undefined, {
const parser = new OpenAPIParser( showSecuritySchemeType: true,
{ openapi: '3.0', info: { title: 'test', version: '0' }, paths: {} }, });
undefined,
options, store.spec.contentItems.forEach((item: OperationModel) => {
if (item.security) {
const component = mount(
withTheme(
<StoreProvider value={store}>
<SecurityRequirements securities={item.security} />,
</StoreProvider>,
),
); );
const securityRequirement = new SecurityRequirementModel({}, parser); expect(component.html()).toMatchSnapshot();
const securityElement = shallow( component.find('svg').simulate('click');
<SecurityRequirement key={1} security={securityRequirement} />, //Security expanded
).getElement(); expect(component.html()).toMatchSnapshot();
expect(securityElement.props.children.type.target).toEqual('span'); }
expect(securityElement.props.children.props.children).toEqual('None');
}); });
}); });
it('should render SecurityDefs', async () => {
const parser = new OpenAPIParser(
simpleSecurityFixture,
undefined,
new RedocNormalizedOptions({}),
);
const component = mount(
withTheme(<SecurityDefs securitySchemes={new SecuritySchemesModel(parser)} />),
);
expect(component.html()).toMatchSnapshot();
}); });
}); });

View File

@ -96,7 +96,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"menuToggle": true, "menuToggle": true,
"minCharacterLengthToInitSearch": 3, "minCharacterLengthToInitSearch": 3,
"nativeScrollbars": false, "nativeScrollbars": false,
"noAutoAuth": false,
"nonce": undefined, "nonce": undefined,
"onlyRequiredInSamples": false, "onlyRequiredInSamples": false,
"pathInMiddlePanel": false, "pathInMiddlePanel": false,
@ -106,6 +105,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"scrollYOffset": [Function], "scrollYOffset": [Function],
"showExtensions": false, "showExtensions": false,
"showObjectSchemaExamples": false, "showObjectSchemaExamples": false,
"showSecuritySchemeType": false,
"showWebhookVerb": false, "showWebhookVerb": false,
"sideNavStyle": "summary-only", "sideNavStyle": "summary-only",
"simpleOneOfTypeLabel": false, "simpleOneOfTypeLabel": false,
@ -353,7 +353,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"menuToggle": true, "menuToggle": true,
"minCharacterLengthToInitSearch": 3, "minCharacterLengthToInitSearch": 3,
"nativeScrollbars": false, "nativeScrollbars": false,
"noAutoAuth": false,
"nonce": undefined, "nonce": undefined,
"onlyRequiredInSamples": false, "onlyRequiredInSamples": false,
"pathInMiddlePanel": false, "pathInMiddlePanel": false,
@ -363,6 +362,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"scrollYOffset": [Function], "scrollYOffset": [Function],
"showExtensions": false, "showExtensions": false,
"showObjectSchemaExamples": false, "showObjectSchemaExamples": false,
"showSecuritySchemeType": false,
"showWebhookVerb": false, "showWebhookVerb": false,
"sideNavStyle": "summary-only", "sideNavStyle": "summary-only",
"simpleOneOfTypeLabel": false, "simpleOneOfTypeLabel": false,
@ -585,7 +585,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"menuToggle": true, "menuToggle": true,
"minCharacterLengthToInitSearch": 3, "minCharacterLengthToInitSearch": 3,
"nativeScrollbars": false, "nativeScrollbars": false,
"noAutoAuth": false,
"nonce": undefined, "nonce": undefined,
"onlyRequiredInSamples": false, "onlyRequiredInSamples": false,
"pathInMiddlePanel": false, "pathInMiddlePanel": false,
@ -595,6 +594,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"scrollYOffset": [Function], "scrollYOffset": [Function],
"showExtensions": false, "showExtensions": false,
"showObjectSchemaExamples": false, "showObjectSchemaExamples": false,
"showSecuritySchemeType": false,
"showWebhookVerb": false, "showWebhookVerb": false,
"sideNavStyle": "summary-only", "sideNavStyle": "summary-only",
"simpleOneOfTypeLabel": false, "simpleOneOfTypeLabel": false,
@ -884,7 +884,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"menuToggle": true, "menuToggle": true,
"minCharacterLengthToInitSearch": 3, "minCharacterLengthToInitSearch": 3,
"nativeScrollbars": false, "nativeScrollbars": false,
"noAutoAuth": false,
"nonce": undefined, "nonce": undefined,
"onlyRequiredInSamples": false, "onlyRequiredInSamples": false,
"pathInMiddlePanel": false, "pathInMiddlePanel": false,
@ -894,6 +893,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"scrollYOffset": [Function], "scrollYOffset": [Function],
"showExtensions": false, "showExtensions": false,
"showObjectSchemaExamples": false, "showObjectSchemaExamples": false,
"showSecuritySchemeType": false,
"showWebhookVerb": false, "showWebhookVerb": false,
"sideNavStyle": "summary-only", "sideNavStyle": "summary-only",
"simpleOneOfTypeLabel": false, "simpleOneOfTypeLabel": false,
@ -1141,7 +1141,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"menuToggle": true, "menuToggle": true,
"minCharacterLengthToInitSearch": 3, "minCharacterLengthToInitSearch": 3,
"nativeScrollbars": false, "nativeScrollbars": false,
"noAutoAuth": false,
"nonce": undefined, "nonce": undefined,
"onlyRequiredInSamples": false, "onlyRequiredInSamples": false,
"pathInMiddlePanel": false, "pathInMiddlePanel": false,
@ -1151,6 +1150,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"scrollYOffset": [Function], "scrollYOffset": [Function],
"showExtensions": false, "showExtensions": false,
"showObjectSchemaExamples": false, "showObjectSchemaExamples": false,
"showSecuritySchemeType": false,
"showWebhookVerb": false, "showWebhookVerb": false,
"sideNavStyle": "summary-only", "sideNavStyle": "summary-only",
"simpleOneOfTypeLabel": false, "simpleOneOfTypeLabel": false,
@ -1373,7 +1373,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"menuToggle": true, "menuToggle": true,
"minCharacterLengthToInitSearch": 3, "minCharacterLengthToInitSearch": 3,
"nativeScrollbars": false, "nativeScrollbars": false,
"noAutoAuth": false,
"nonce": undefined, "nonce": undefined,
"onlyRequiredInSamples": false, "onlyRequiredInSamples": false,
"pathInMiddlePanel": false, "pathInMiddlePanel": false,
@ -1383,6 +1382,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"scrollYOffset": [Function], "scrollYOffset": [Function],
"showExtensions": false, "showExtensions": false,
"showObjectSchemaExamples": false, "showObjectSchemaExamples": false,
"showSecuritySchemeType": false,
"showWebhookVerb": false, "showWebhookVerb": false,
"sideNavStyle": "summary-only", "sideNavStyle": "summary-only",
"simpleOneOfTypeLabel": false, "simpleOneOfTypeLabel": false,
@ -1628,7 +1628,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"menuToggle": true, "menuToggle": true,
"minCharacterLengthToInitSearch": 3, "minCharacterLengthToInitSearch": 3,
"nativeScrollbars": false, "nativeScrollbars": false,
"noAutoAuth": false,
"nonce": undefined, "nonce": undefined,
"onlyRequiredInSamples": false, "onlyRequiredInSamples": false,
"pathInMiddlePanel": false, "pathInMiddlePanel": false,
@ -1638,6 +1637,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"scrollYOffset": [Function], "scrollYOffset": [Function],
"showExtensions": false, "showExtensions": false,
"showObjectSchemaExamples": false, "showObjectSchemaExamples": false,
"showSecuritySchemeType": false,
"showWebhookVerb": false, "showWebhookVerb": false,
"sideNavStyle": "summary-only", "sideNavStyle": "summary-only",
"simpleOneOfTypeLabel": false, "simpleOneOfTypeLabel": false,
@ -1924,7 +1924,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"menuToggle": true, "menuToggle": true,
"minCharacterLengthToInitSearch": 3, "minCharacterLengthToInitSearch": 3,
"nativeScrollbars": false, "nativeScrollbars": false,
"noAutoAuth": false,
"nonce": undefined, "nonce": undefined,
"onlyRequiredInSamples": false, "onlyRequiredInSamples": false,
"pathInMiddlePanel": false, "pathInMiddlePanel": false,
@ -1934,6 +1933,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"scrollYOffset": [Function], "scrollYOffset": [Function],
"showExtensions": false, "showExtensions": false,
"showObjectSchemaExamples": false, "showObjectSchemaExamples": false,
"showSecuritySchemeType": false,
"showWebhookVerb": false, "showWebhookVerb": false,
"sideNavStyle": "summary-only", "sideNavStyle": "summary-only",
"simpleOneOfTypeLabel": false, "simpleOneOfTypeLabel": false,
@ -2181,7 +2181,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"menuToggle": true, "menuToggle": true,
"minCharacterLengthToInitSearch": 3, "minCharacterLengthToInitSearch": 3,
"nativeScrollbars": false, "nativeScrollbars": false,
"noAutoAuth": false,
"nonce": undefined, "nonce": undefined,
"onlyRequiredInSamples": false, "onlyRequiredInSamples": false,
"pathInMiddlePanel": false, "pathInMiddlePanel": false,
@ -2191,6 +2190,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"scrollYOffset": [Function], "scrollYOffset": [Function],
"showExtensions": false, "showExtensions": false,
"showObjectSchemaExamples": false, "showObjectSchemaExamples": false,
"showSecuritySchemeType": false,
"showWebhookVerb": false, "showWebhookVerb": false,
"sideNavStyle": "summary-only", "sideNavStyle": "summary-only",
"simpleOneOfTypeLabel": false, "simpleOneOfTypeLabel": false,
@ -2413,7 +2413,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"menuToggle": true, "menuToggle": true,
"minCharacterLengthToInitSearch": 3, "minCharacterLengthToInitSearch": 3,
"nativeScrollbars": false, "nativeScrollbars": false,
"noAutoAuth": false,
"nonce": undefined, "nonce": undefined,
"onlyRequiredInSamples": false, "onlyRequiredInSamples": false,
"pathInMiddlePanel": false, "pathInMiddlePanel": false,
@ -2423,6 +2422,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"scrollYOffset": [Function], "scrollYOffset": [Function],
"showExtensions": false, "showExtensions": false,
"showObjectSchemaExamples": false, "showObjectSchemaExamples": false,
"showSecuritySchemeType": false,
"showWebhookVerb": false, "showWebhookVerb": false,
"sideNavStyle": "summary-only", "sideNavStyle": "summary-only",
"simpleOneOfTypeLabel": false, "simpleOneOfTypeLabel": false,

View File

@ -0,0 +1,23 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`SecurityRequirement should render SecurityDefs 1`] = `
"<div id=\\"section/Authentication/petstore_auth\\" data-section-id=\\"section/Authentication/petstore_auth\\" class=\\"sc-eCApnc jlMQbh\\"><div class=\\"sc-iCoGMd gLxhOh\\"><div class=\\"sc-hKFxyN juinod\\"><h2 class=\\"sc-pNWdM eftmgB\\">petstore_auth</h2><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>Get access to data while protecting your account credentials.
OAuth2 is also a safer and more secure way to give you access.</p>
</div><div class=\\"sc-EZqKI aOkZE\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Security Scheme Type: </b><span>OAuth2</span></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Flow type: </b><code>implicit </code></div><div class=\\"sc-fXgAZx gZCyoW\\"><strong> Authorization URL: </strong><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"http://petstore.swagger.io/api/oauth/dialog\\">http://petstore.swagger.io/api/oauth/dialog</a></code></div><div class=\\"sc-fXgAZx gZCyoW\\"><b> Scopes: </b></div><div class=\\"sc-jXcxbT blWOKY container\\" style=\\"height: 4em;\\"><ul><li><code>write:pets</code> - <span class=\\"sc-carFqZ bmTzxo redoc-markdown\\"><p>modify pets in your account</p>
</span></li><li><code>read:pets</code> - <span class=\\"sc-carFqZ bmTzxo redoc-markdown\\"><p>read your pets</p>
</span></li></ul></div><div class=\\"sc-eEVmNe gbLbHj\\"></div></div></div></div></div></div><div id=\\"section/Authentication/GitLab_PersonalAccessToken\\" data-section-id=\\"section/Authentication/GitLab_PersonalAccessToken\\" class=\\"sc-eCApnc jlMQbh\\"><div class=\\"sc-iCoGMd gLxhOh\\"><div class=\\"sc-hKFxyN juinod\\"><h2 class=\\"sc-pNWdM eftmgB\\">GitLab_PersonalAccessToken</h2><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>GitLab Personal Access Token description</p>
</div><div class=\\"sc-EZqKI aOkZE\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Security Scheme Type: </b><span>API Key</span></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Header parameter name: </b><code>PRIVATE-TOKEN</code></div></div></div></div></div></div><div id=\\"section/Authentication/GitLab_OpenIdConnect\\" data-section-id=\\"section/Authentication/GitLab_OpenIdConnect\\" class=\\"sc-eCApnc jlMQbh\\"><div class=\\"sc-iCoGMd gLxhOh\\"><div class=\\"sc-hKFxyN juinod\\"><h2 class=\\"sc-pNWdM eftmgB\\">GitLab_OpenIdConnect</h2><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>GitLab OpenIdConnect description</p>
</div><div class=\\"sc-EZqKI aOkZE\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Security Scheme Type: </b><span>OpenID Connect</span></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Connect URL: </b><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"https://gitlab.com/.well-known/openid-configuration\\">https://gitlab.com/.well-known/openid-configuration</a></code></div></div></div></div></div></div><div id=\\"section/Authentication/basicAuth\\" data-section-id=\\"section/Authentication/basicAuth\\" class=\\"sc-eCApnc jlMQbh\\"><div class=\\"sc-iCoGMd gLxhOh\\"><div class=\\"sc-hKFxyN juinod\\"><h2 class=\\"sc-pNWdM eftmgB\\">basicAuth</h2><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"></div><div class=\\"sc-EZqKI aOkZE\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Security Scheme Type: </b><span>HTTP</span></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>HTTP Authorization Scheme: </b><code>basic</code></div><div class=\\"sc-fXgAZx gZCyoW\\"></div></div></div></div></div></div>"
`;
exports[`SecurityRequirement should render authDefinition 1`] = `"<div class=\\"sc-bQCEYZ eDdCgW\\"><div class=\\"sc-xGAEC femyTb\\"><h5 class=\\"sc-iqAclL sc-jHcXXw eONCmm keQLTh\\">Authorizations:</h5><svg class=\\"sc-dIsUp iPqByX\\" version=\\"1.1\\" viewBox=\\"0 0 24 24\\" x=\\"0\\" xmlns=\\"http://www.w3.org/2000/svg\\" y=\\"0\\" aria-hidden=\\"true\\"><polygon points=\\"17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 \\"></polygon></svg></div><div class=\\"sc-dWBRfb kJFNCL\\"><span class=\\"sc-kYPZxB irJeRy\\">(<span class=\\"sc-hzUIXc gcouO\\">API Key: <i>GitLab_PersonalAccessToken</i></span><span class=\\"sc-hzUIXc gcouO\\">OpenID Connect: <i>GitLab_OpenIdConnect</i></span><span class=\\"sc-hzUIXc gcouO\\">HTTP: <i>basicAuth</i></span>) </span><span class=\\"sc-kYPZxB irJeRy\\"><span class=\\"sc-hzUIXc gcouO\\">OAuth2: <i>petstore_auth</i></span></span></div></div>,"`;
exports[`SecurityRequirement should render authDefinition 2`] = `
"<div class=\\"sc-bQCEYZ dSwEDq\\"><div class=\\"sc-xGAEC femyTb\\"><h5 class=\\"sc-iqAclL sc-jHcXXw eONCmm keQLTh\\">Authorizations:</h5><svg class=\\"sc-dIsUp fVWtGJ\\" version=\\"1.1\\" viewBox=\\"0 0 24 24\\" x=\\"0\\" xmlns=\\"http://www.w3.org/2000/svg\\" y=\\"0\\" aria-hidden=\\"true\\"><polygon points=\\"17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 \\"></polygon></svg></div><div class=\\"sc-dWBRfb ekRdav\\"><span class=\\"sc-kYPZxB fhGdrc\\">(<span class=\\"sc-hzUIXc gcouO\\">API Key: <i>GitLab_PersonalAccessToken</i></span><span class=\\"sc-hzUIXc gcouO\\">OpenID Connect: <i>GitLab_OpenIdConnect</i></span><span class=\\"sc-hzUIXc gcouO\\">HTTP: <i>basicAuth</i></span>) </span><span class=\\"sc-kYPZxB fhGdrc\\"><span class=\\"sc-hzUIXc gcouO\\">OAuth2: <i>petstore_auth</i> (<code class=\\"sc-eHEENL fwFTyL\\">write:pets</code><code class=\\"sc-eHEENL fwFTyL\\">read:pets</code>) </span></span></div></div><div class=\\"sc-EZqKI aOkZE\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> OAuth2: petstore_auth</h5><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>Get access to data while protecting your account credentials.
OAuth2 is also a safer and more secure way to give you access.</p>
</div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Flow type: </b><code>implicit </code></div><div class=\\"sc-fXgAZx gZCyoW\\"><strong> Authorization URL: </strong><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"http://petstore.swagger.io/api/oauth/dialog\\">http://petstore.swagger.io/api/oauth/dialog</a></code></div><div><b>Required scopes: </b><code>write:pets</code> <code>read:pets</code> </div><div class=\\"sc-fXgAZx gZCyoW\\"><b> Scopes: </b></div><div class=\\"sc-jXcxbT blWOKY container\\" style=\\"height: 4em;\\"><ul><li><code>write:pets</code> - <span class=\\"sc-carFqZ bmTzxo redoc-markdown\\"><p>modify pets in your account</p>
</span></li><li><code>read:pets</code> - <span class=\\"sc-carFqZ bmTzxo redoc-markdown\\"><p>read your pets</p>
</span></li></ul></div><div class=\\"sc-eEVmNe gbLbHj\\"></div></div></div><div class=\\"sc-EZqKI aOkZE\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> API Key: GitLab_PersonalAccessToken</h5><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>GitLab Personal Access Token description</p>
</div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Header parameter name: </b><code>PRIVATE-TOKEN</code></div></div></div><div class=\\"sc-EZqKI aOkZE\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> OpenID Connect: GitLab_OpenIdConnect</h5><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>GitLab OpenIdConnect description</p>
</div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Connect URL: </b><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"https://gitlab.com/.well-known/openid-configuration\\">https://gitlab.com/.well-known/openid-configuration</a></code></div></div></div><div class=\\"sc-EZqKI aOkZE\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> HTTP: basicAuth</h5><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>HTTP Authorization Scheme: </b><code>basic</code></div><div class=\\"sc-fXgAZx gZCyoW\\"></div></div></div>,"
`;

View File

@ -0,0 +1,67 @@
{
"openapi": "3.0",
"info": {
"title": "test",
"version": "0"
},
"paths": {
"/pet": {
"put": {
"summary": "Add a new pet to the store",
"description": "Add new pet to the store inventory.",
"operationId": "updatePet",
"responses": {
"405": {
"description": "Invalid input"
}
},
"security": [
{
"GitLab_PersonalAccessToken": [],
"GitLab_OpenIdConnect": [],
"basicAuth": []
},
{
"petstore_auth": ["write:pets", "read:pets"]
}
]
}
}
},
"components": {
"securitySchemes": {
"petstore_auth": {
"description": "Get access to data while protecting your account credentials.\nOAuth2 is also a safer and more secure way to give you access.\n",
"type": "oauth2",
"bearerFormat": "",
"flows": {
"implicit": {
"authorizationUrl": "http://petstore.swagger.io/api/oauth/dialog",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets"
}
}
}
},
"GitLab_PersonalAccessToken": {
"description": "GitLab Personal Access Token description",
"type": "apiKey",
"name": "PRIVATE-TOKEN",
"in": "header",
"bearerFormat": "",
"flows": {}
},
"GitLab_OpenIdConnect": {
"description": "GitLab OpenIdConnect description",
"bearerFormat": "",
"type": "openIdConnect",
"openIdConnectUrl": "https://gitlab.com/.well-known/openid-configuration"
},
"basicAuth": {
"type": "http",
"scheme": "basic"
}
}
}
}

View File

@ -12,11 +12,7 @@ import { SearchStore } from './SearchStore';
import { SchemaDefinition } from '../components/SchemaDefinition/SchemaDefinition'; import { SchemaDefinition } from '../components/SchemaDefinition/SchemaDefinition';
import { SecurityDefs } from '../components/SecuritySchemes/SecuritySchemes'; import { SecurityDefs } from '../components/SecuritySchemes/SecuritySchemes';
import { import { SCHEMA_DEFINITION_JSX_NAME, SECURITY_DEFINITIONS_JSX_NAME } from '../utils/openapi';
SCHEMA_DEFINITION_JSX_NAME,
SECURITY_DEFINITIONS_COMPONENT_NAME,
SECURITY_DEFINITIONS_JSX_NAME,
} from '../utils/openapi';
import { IS_BROWSER } from '../utils'; import { IS_BROWSER } from '../utils';
@ -158,12 +154,6 @@ export class AppStore {
const DEFAULT_OPTIONS: RedocRawOptions = { const DEFAULT_OPTIONS: RedocRawOptions = {
allowedMdComponents: { allowedMdComponents: {
[SECURITY_DEFINITIONS_COMPONENT_NAME]: {
component: SecurityDefs,
propsSelector: (store: AppStore) => ({
securitySchemes: store.spec.securitySchemes,
}),
},
[SECURITY_DEFINITIONS_JSX_NAME]: { [SECURITY_DEFINITIONS_JSX_NAME]: {
component: SecurityDefs, component: SecurityDefs,
propsSelector: (store: AppStore) => ({ propsSelector: (store: AppStore) => ({

View File

@ -7,13 +7,7 @@ import {
OpenAPIServer, OpenAPIServer,
OpenAPIPaths, OpenAPIPaths,
} from '../types'; } from '../types';
import { import { isOperationName, JsonPointer, alphabeticallyByProp } from '../utils';
isOperationName,
SECURITY_DEFINITIONS_COMPONENT_NAME,
setSecuritySchemePrefix,
JsonPointer,
alphabeticallyByProp,
} from '../utils';
import { MarkdownRenderer } from './MarkdownRenderer'; import { MarkdownRenderer } from './MarkdownRenderer';
import { GroupModel, OperationModel } from './models'; import { GroupModel, OperationModel } from './models';
import { OpenAPIParser } from './OpenAPIParser'; import { OpenAPIParser } from './OpenAPIParser';
@ -93,14 +87,7 @@ export class MenuBuilder {
if (heading.items) { if (heading.items) {
group.items = mapHeadingsDeep(group, heading.items, depth + 1); group.items = mapHeadingsDeep(group, heading.items, depth + 1);
} }
if (
MarkdownRenderer.containsComponent(
group.description || '',
SECURITY_DEFINITIONS_COMPONENT_NAME,
)
) {
setSecuritySchemePrefix(group.id + '/');
}
return group; return group;
}); });

View File

@ -146,6 +146,7 @@ export class MenuStore {
let item: IMenuItem | undefined; let item: IMenuItem | undefined;
item = this.flatItems.find(i => i.id === id); item = this.flatItems.find(i => i.id === id);
if (item) { if (item) {
this.activateAndScroll(item, false); this.activateAndScroll(item, false);
} else { } else {

View File

@ -1,14 +1,8 @@
import { OpenAPIRef, OpenAPISchema, OpenAPISpec, Referenced } from '../types'; import { OpenAPIRef, OpenAPISchema, OpenAPISpec, Referenced } from '../types';
import { appendToMdHeading, isArray, isBoolean, IS_BROWSER } from '../utils/'; import { isArray, isBoolean, IS_BROWSER } from '../utils/';
import { JsonPointer } from '../utils/JsonPointer'; import { JsonPointer } from '../utils/JsonPointer';
import { import { getDefinitionName, isNamedDefinition } from '../utils/openapi';
getDefinitionName,
isNamedDefinition,
SECURITY_DEFINITIONS_COMPONENT_NAME,
SECURITY_DEFINITIONS_JSX_NAME,
} from '../utils/openapi';
import { buildComponentComment, MarkdownRenderer } from './MarkdownRenderer';
import { RedocNormalizedOptions } from './RedocNormalizedOptions'; import { RedocNormalizedOptions } from './RedocNormalizedOptions';
export type MergedOpenAPISchema = OpenAPISchema & { parentRefs?: string[] }; export type MergedOpenAPISchema = OpenAPISchema & { parentRefs?: string[] };
@ -53,7 +47,6 @@ export class OpenAPIParser {
private options: RedocNormalizedOptions = new RedocNormalizedOptions({}), private options: RedocNormalizedOptions = new RedocNormalizedOptions({}),
) { ) {
this.validate(spec); this.validate(spec);
this.preprocess(spec);
this.spec = spec; this.spec = spec;
this.allowMergeRefs = spec.openapi.startsWith('3.1'); this.allowMergeRefs = spec.openapi.startsWith('3.1');
@ -70,25 +63,6 @@ export class OpenAPIParser {
} }
} }
preprocess(spec: OpenAPISpec) {
if (
!this.options.noAutoAuth &&
spec.info &&
spec.components &&
spec.components.securitySchemes
) {
// Automatically inject Authentication section with SecurityDefinitions component
const description = spec.info.description || '';
if (
!MarkdownRenderer.containsComponent(description, SECURITY_DEFINITIONS_COMPONENT_NAME) &&
!MarkdownRenderer.containsComponent(description, SECURITY_DEFINITIONS_JSX_NAME)
) {
const comment = buildComponentComment(SECURITY_DEFINITIONS_COMPONENT_NAME);
spec.info.description = appendToMdHeading(description, 'Authentication', comment);
}
}
}
/** /**
* get spec part by JsonPointer ($ref) * get spec part by JsonPointer ($ref)
*/ */

View File

@ -21,7 +21,6 @@ export interface RedocRawOptions {
sortEnumValuesAlphabetically?: boolean | string; sortEnumValuesAlphabetically?: boolean | string;
sortOperationsAlphabetically?: boolean | string; sortOperationsAlphabetically?: boolean | string;
sortTagsAlphabetically?: boolean | string; sortTagsAlphabetically?: boolean | string;
noAutoAuth?: boolean | string;
nativeScrollbars?: boolean | string; nativeScrollbars?: boolean | string;
pathInMiddlePanel?: boolean | string; pathInMiddlePanel?: boolean | string;
untrustedSpec?: boolean | string; untrustedSpec?: boolean | string;
@ -42,6 +41,7 @@ export interface RedocRawOptions {
expandSingleSchemaField?: boolean | string; expandSingleSchemaField?: boolean | string;
schemaExpansionLevel?: number | string | 'all'; schemaExpansionLevel?: number | string | 'all';
showObjectSchemaExamples?: boolean | string; showObjectSchemaExamples?: boolean | string;
showSecuritySchemeType?: boolean;
unstable_ignoreMimeParameters?: boolean; unstable_ignoreMimeParameters?: boolean;
@ -224,7 +224,6 @@ export class RedocNormalizedOptions {
sortEnumValuesAlphabetically: boolean; sortEnumValuesAlphabetically: boolean;
sortOperationsAlphabetically: boolean; sortOperationsAlphabetically: boolean;
sortTagsAlphabetically: boolean; sortTagsAlphabetically: boolean;
noAutoAuth: boolean;
nativeScrollbars: boolean; nativeScrollbars: boolean;
pathInMiddlePanel: boolean; pathInMiddlePanel: boolean;
untrustedSpec: boolean; untrustedSpec: boolean;
@ -245,6 +244,7 @@ export class RedocNormalizedOptions {
expandSingleSchemaField: boolean; expandSingleSchemaField: boolean;
schemaExpansionLevel: number; schemaExpansionLevel: number;
showObjectSchemaExamples: boolean; showObjectSchemaExamples: boolean;
showSecuritySchemeType?: boolean;
/* tslint:disable-next-line */ /* tslint:disable-next-line */
unstable_ignoreMimeParameters: boolean; unstable_ignoreMimeParameters: boolean;
@ -294,7 +294,6 @@ export class RedocNormalizedOptions {
this.sortEnumValuesAlphabetically = argValueToBoolean(raw.sortEnumValuesAlphabetically); this.sortEnumValuesAlphabetically = argValueToBoolean(raw.sortEnumValuesAlphabetically);
this.sortOperationsAlphabetically = argValueToBoolean(raw.sortOperationsAlphabetically); this.sortOperationsAlphabetically = argValueToBoolean(raw.sortOperationsAlphabetically);
this.sortTagsAlphabetically = argValueToBoolean(raw.sortTagsAlphabetically); this.sortTagsAlphabetically = argValueToBoolean(raw.sortTagsAlphabetically);
this.noAutoAuth = argValueToBoolean(raw.noAutoAuth);
this.nativeScrollbars = argValueToBoolean(raw.nativeScrollbars); this.nativeScrollbars = argValueToBoolean(raw.nativeScrollbars);
this.pathInMiddlePanel = argValueToBoolean(raw.pathInMiddlePanel); this.pathInMiddlePanel = argValueToBoolean(raw.pathInMiddlePanel);
this.untrustedSpec = argValueToBoolean(raw.untrustedSpec); this.untrustedSpec = argValueToBoolean(raw.untrustedSpec);
@ -317,6 +316,7 @@ export class RedocNormalizedOptions {
this.expandSingleSchemaField = argValueToBoolean(raw.expandSingleSchemaField); this.expandSingleSchemaField = argValueToBoolean(raw.expandSingleSchemaField);
this.schemaExpansionLevel = argValueToExpandLevel(raw.schemaExpansionLevel); this.schemaExpansionLevel = argValueToExpandLevel(raw.schemaExpansionLevel);
this.showObjectSchemaExamples = argValueToBoolean(raw.showObjectSchemaExamples); this.showObjectSchemaExamples = argValueToBoolean(raw.showObjectSchemaExamples);
this.showSecuritySchemeType = argValueToBoolean(raw.showSecuritySchemeType);
this.unstable_ignoreMimeParameters = argValueToBoolean(raw.unstable_ignoreMimeParameters); this.unstable_ignoreMimeParameters = argValueToBoolean(raw.unstable_ignoreMimeParameters);

View File

@ -1,5 +1,4 @@
import { OpenAPISecurityRequirement, OpenAPISecurityScheme } from '../../types'; import { OpenAPISecurityRequirement, OpenAPISecurityScheme } from '../../types';
import { SECURITY_SCHEMES_SECTION_PREFIX } from '../../utils/openapi';
import { OpenAPIParser } from '../OpenAPIParser'; import { OpenAPIParser } from '../OpenAPIParser';
export interface SecurityScheme extends OpenAPISecurityScheme { export interface SecurityScheme extends OpenAPISecurityScheme {
@ -29,7 +28,7 @@ export class SecurityRequirementModel {
return { return {
...scheme, ...scheme,
id, id,
sectionId: SECURITY_SCHEMES_SECTION_PREFIX + id, sectionId: id,
displayName, displayName,
scopes, scopes,
}; };

View File

@ -1,5 +1,5 @@
import { OpenAPISecurityScheme, Referenced } from '../../types'; import { OpenAPISecurityScheme, Referenced } from '../../types';
import { SECURITY_SCHEMES_SECTION_PREFIX } from '../../utils/openapi'; import { SECURITY_SCHEMES_SECTION_PREFIX } from '../../utils';
import { OpenAPIParser } from '../OpenAPIParser'; import { OpenAPIParser } from '../OpenAPIParser';
export class SecuritySchemeModel { export class SecuritySchemeModel {

View File

@ -615,7 +615,6 @@ export function normalizeServers(
}); });
} }
export const SECURITY_DEFINITIONS_COMPONENT_NAME = 'security-definitions';
export const SECURITY_DEFINITIONS_JSX_NAME = 'SecurityDefinitions'; export const SECURITY_DEFINITIONS_JSX_NAME = 'SecurityDefinitions';
export const SCHEMA_DEFINITION_JSX_NAME = 'SchemaDefinition'; export const SCHEMA_DEFINITION_JSX_NAME = 'SchemaDefinition';