mirror of
https://github.com/Redocly/redoc.git
synced 2024-11-22 00:26:34 +03:00
feat: remove auth section (#2022)
This commit is contained in:
parent
b98c7a0d34
commit
a863302cc8
|
@ -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.~~
|
||||
* `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).
|
||||
* `noAutoAuth` - do not inject Authentication section automatically.
|
||||
* `onlyRequiredInSamples` - shows only required fields in request samples.
|
||||
* `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.
|
||||
|
|
71
src/components/SecurityRequirement/OAuthFlow.tsx
Normal file
71
src/components/SecurityRequirement/OAuthFlow.tsx
Normal 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);
|
18
src/components/SecurityRequirement/RequiredScopesRow.tsx
Normal file
18
src/components/SecurityRequirement/RequiredScopesRow.tsx
Normal 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>
|
||||
);
|
||||
};
|
65
src/components/SecurityRequirement/SecurityDetails.tsx
Normal file
65
src/components/SecurityRequirement/SecurityDetails.tsx
Normal 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>
|
||||
);
|
||||
}
|
43
src/components/SecurityRequirement/SecurityHeader.tsx
Normal file
43
src/components/SecurityRequirement/SecurityHeader.tsx
Normal 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>
|
||||
);
|
||||
}
|
|
@ -1,153 +1,102 @@
|
|||
import * as React from 'react';
|
||||
|
||||
import styled, { media } from '../../styled-components';
|
||||
|
||||
import { Link, UnderlinedHeader } from '../../common-elements/';
|
||||
import { useState } from 'react';
|
||||
import { SecurityRequirementModel } from '../../services/models/SecurityRequirement';
|
||||
import { linksCss } from '../Markdown/styled.elements';
|
||||
|
||||
const ScopeNameList = styled.ul`
|
||||
display: inline;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
display: inherit;
|
||||
|
||||
&:after {
|
||||
content: ',';
|
||||
}
|
||||
&:last-child:after {
|
||||
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;
|
||||
`}
|
||||
`;
|
||||
import {
|
||||
AuthHeader,
|
||||
AuthHeaderColumn,
|
||||
SecuritiesColumn,
|
||||
SecurityDetailsStyle,
|
||||
Wrap,
|
||||
} from './styled.elements';
|
||||
import { useStore } from '../StoreBuilder';
|
||||
import { SecurityHeader } from './SecurityHeader';
|
||||
import { RequiredScopesRow } from './RequiredScopesRow';
|
||||
import { AUTH_TYPES } from '../SecuritySchemes/SecuritySchemes';
|
||||
import { Markdown } from '../Markdown/Markdown';
|
||||
import { SecurityDetails } from './SecurityDetails';
|
||||
import { ShelfIcon } from '../../common-elements';
|
||||
|
||||
export interface SecurityRequirementsProps {
|
||||
securities: SecurityRequirementModel[];
|
||||
}
|
||||
|
||||
export class SecurityRequirements extends React.PureComponent<SecurityRequirementsProps> {
|
||||
render() {
|
||||
const securities = this.props.securities;
|
||||
if (!securities.length) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Wrap>
|
||||
<AuthHeaderColumn>
|
||||
<AuthHeader>Authorizations: </AuthHeader>
|
||||
export function SecurityRequirements(props: SecurityRequirementsProps) {
|
||||
const store = useStore();
|
||||
const showSecuritySchemeType = store?.options.showSecuritySchemeType;
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
|
||||
const { securities } = props;
|
||||
|
||||
if (!securities?.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const operationSecuritySchemes = store?.spec.securitySchemes.schemes.filter(({ id }) => {
|
||||
return securities.find(security => security.schemes.find(scheme => scheme.id === id));
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Wrap expanded={expanded}>
|
||||
<AuthHeaderColumn onClick={() => setExpanded(!expanded)}>
|
||||
<AuthHeader>Authorizations:</AuthHeader>
|
||||
<ShelfIcon size={'1.3em'} direction={expanded ? 'down' : 'right'} />
|
||||
</AuthHeaderColumn>
|
||||
<SecuritiesColumn>
|
||||
<SecuritiesColumn expanded={expanded}>
|
||||
{securities.map((security, idx) => (
|
||||
<SecurityRequirement key={idx} security={security} />
|
||||
<SecurityHeader
|
||||
key={idx}
|
||||
expanded={expanded}
|
||||
showSecuritySchemeType={showSecuritySchemeType}
|
||||
security={security}
|
||||
/>
|
||||
))}
|
||||
</SecuritiesColumn>
|
||||
</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));
|
||||
}
|
||||
|
|
129
src/components/SecurityRequirement/styled.elements.ts
Normal file
129
src/components/SecurityRequirement/styled.elements.ts
Normal 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;
|
||||
}
|
||||
`;
|
|
@ -1,72 +1,18 @@
|
|||
import * as React from 'react';
|
||||
|
||||
import { SecuritySchemesModel } from '../../services/models';
|
||||
|
||||
import { H2, MiddlePanel, Row, Section, ShareLink } from '../../common-elements';
|
||||
import { OpenAPISecurityScheme } from '../../types';
|
||||
import { titleize } from '../../utils/helpers';
|
||||
import { SecuritySchemesModel } from '../../services';
|
||||
import { H2, Row, ShareLink, MiddlePanel, Section } from '../../common-elements';
|
||||
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',
|
||||
apiKey: 'API Key',
|
||||
http: 'HTTP',
|
||||
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 {
|
||||
securitySchemes: SecuritySchemesModel;
|
||||
}
|
||||
|
@ -82,52 +28,13 @@ export class SecurityDefs extends React.PureComponent<SecurityDefsProps> {
|
|||
{scheme.displayName}
|
||||
</H2>
|
||||
<Markdown source={scheme.description || ''} />
|
||||
<StyledMarkdownBlock>
|
||||
<table className="security-details">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th> Security Scheme Type </th>
|
||||
<td> {AUTH_TYPES[scheme.type] || scheme.type} </td>
|
||||
</tr>
|
||||
{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> "{scheme.http.bearerFormat}" </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>
|
||||
<SecurityDetailsStyle>
|
||||
<SecurityRow>
|
||||
<b>Security Scheme Type: </b>
|
||||
<span>{AUTH_TYPES[scheme.type] || scheme.type}</span>
|
||||
</SecurityRow>
|
||||
<SecurityDetails scheme={scheme} />
|
||||
</SecurityDetailsStyle>
|
||||
</MiddlePanel>
|
||||
</Row>
|
||||
</Section>
|
||||
|
|
65
src/components/SeeMore/SeeMore.tsx
Normal file
65
src/components/SeeMore/SeeMore.tsx
Normal 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;
|
||||
`;
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from 'react';
|
||||
import { createContext } from 'react';
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
import { AppStore } from '../services/';
|
||||
import { RedocRawOptions } from '../services/RedocNormalizedOptions';
|
||||
|
@ -79,3 +79,7 @@ export function StoreBuilder(props: StoreBuilderProps) {
|
|||
store,
|
||||
});
|
||||
}
|
||||
|
||||
export function useStore(): AppStore | undefined {
|
||||
return useContext(StoreContext);
|
||||
}
|
||||
|
|
|
@ -1,28 +1,52 @@
|
|||
import * as React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { mount } from 'enzyme';
|
||||
|
||||
import { OpenAPIParser } from '../../services';
|
||||
import { SecurityRequirementModel } from '../../services/models/SecurityRequirement';
|
||||
import { SecurityRequirement } from '../SecurityRequirement/SecurityRequirement';
|
||||
import { RedocNormalizedOptions } from '../../services/RedocNormalizedOptions';
|
||||
import {
|
||||
createStore,
|
||||
OpenAPIParser,
|
||||
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', () => {
|
||||
it("should render 'None' when empty object in security open api", () => {
|
||||
const parser = new OpenAPIParser(
|
||||
{ openapi: '3.0', info: { title: 'test', version: '0' }, paths: {} },
|
||||
undefined,
|
||||
options,
|
||||
describe('SecurityRequirement', () => {
|
||||
it('should render authDefinition', async () => {
|
||||
const store = await createStore(simpleSecurityFixture, undefined, {
|
||||
showSecuritySchemeType: true,
|
||||
});
|
||||
|
||||
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);
|
||||
const securityElement = shallow(
|
||||
<SecurityRequirement key={1} security={securityRequirement} />,
|
||||
).getElement();
|
||||
expect(securityElement.props.children.type.target).toEqual('span');
|
||||
expect(securityElement.props.children.props.children).toEqual('None');
|
||||
});
|
||||
expect(component.html()).toMatchSnapshot();
|
||||
component.find('svg').simulate('click');
|
||||
//Security expanded
|
||||
expect(component.html()).toMatchSnapshot();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -96,7 +96,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"menuToggle": true,
|
||||
"minCharacterLengthToInitSearch": 3,
|
||||
"nativeScrollbars": false,
|
||||
"noAutoAuth": false,
|
||||
"nonce": undefined,
|
||||
"onlyRequiredInSamples": false,
|
||||
"pathInMiddlePanel": false,
|
||||
|
@ -106,6 +105,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"scrollYOffset": [Function],
|
||||
"showExtensions": false,
|
||||
"showObjectSchemaExamples": false,
|
||||
"showSecuritySchemeType": false,
|
||||
"showWebhookVerb": false,
|
||||
"sideNavStyle": "summary-only",
|
||||
"simpleOneOfTypeLabel": false,
|
||||
|
@ -353,7 +353,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"menuToggle": true,
|
||||
"minCharacterLengthToInitSearch": 3,
|
||||
"nativeScrollbars": false,
|
||||
"noAutoAuth": false,
|
||||
"nonce": undefined,
|
||||
"onlyRequiredInSamples": false,
|
||||
"pathInMiddlePanel": false,
|
||||
|
@ -363,6 +362,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"scrollYOffset": [Function],
|
||||
"showExtensions": false,
|
||||
"showObjectSchemaExamples": false,
|
||||
"showSecuritySchemeType": false,
|
||||
"showWebhookVerb": false,
|
||||
"sideNavStyle": "summary-only",
|
||||
"simpleOneOfTypeLabel": false,
|
||||
|
@ -585,7 +585,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"menuToggle": true,
|
||||
"minCharacterLengthToInitSearch": 3,
|
||||
"nativeScrollbars": false,
|
||||
"noAutoAuth": false,
|
||||
"nonce": undefined,
|
||||
"onlyRequiredInSamples": false,
|
||||
"pathInMiddlePanel": false,
|
||||
|
@ -595,6 +594,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"scrollYOffset": [Function],
|
||||
"showExtensions": false,
|
||||
"showObjectSchemaExamples": false,
|
||||
"showSecuritySchemeType": false,
|
||||
"showWebhookVerb": false,
|
||||
"sideNavStyle": "summary-only",
|
||||
"simpleOneOfTypeLabel": false,
|
||||
|
@ -884,7 +884,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"menuToggle": true,
|
||||
"minCharacterLengthToInitSearch": 3,
|
||||
"nativeScrollbars": false,
|
||||
"noAutoAuth": false,
|
||||
"nonce": undefined,
|
||||
"onlyRequiredInSamples": false,
|
||||
"pathInMiddlePanel": false,
|
||||
|
@ -894,6 +893,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"scrollYOffset": [Function],
|
||||
"showExtensions": false,
|
||||
"showObjectSchemaExamples": false,
|
||||
"showSecuritySchemeType": false,
|
||||
"showWebhookVerb": false,
|
||||
"sideNavStyle": "summary-only",
|
||||
"simpleOneOfTypeLabel": false,
|
||||
|
@ -1141,7 +1141,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"menuToggle": true,
|
||||
"minCharacterLengthToInitSearch": 3,
|
||||
"nativeScrollbars": false,
|
||||
"noAutoAuth": false,
|
||||
"nonce": undefined,
|
||||
"onlyRequiredInSamples": false,
|
||||
"pathInMiddlePanel": false,
|
||||
|
@ -1151,6 +1150,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"scrollYOffset": [Function],
|
||||
"showExtensions": false,
|
||||
"showObjectSchemaExamples": false,
|
||||
"showSecuritySchemeType": false,
|
||||
"showWebhookVerb": false,
|
||||
"sideNavStyle": "summary-only",
|
||||
"simpleOneOfTypeLabel": false,
|
||||
|
@ -1373,7 +1373,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"menuToggle": true,
|
||||
"minCharacterLengthToInitSearch": 3,
|
||||
"nativeScrollbars": false,
|
||||
"noAutoAuth": false,
|
||||
"nonce": undefined,
|
||||
"onlyRequiredInSamples": false,
|
||||
"pathInMiddlePanel": false,
|
||||
|
@ -1383,6 +1382,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"scrollYOffset": [Function],
|
||||
"showExtensions": false,
|
||||
"showObjectSchemaExamples": false,
|
||||
"showSecuritySchemeType": false,
|
||||
"showWebhookVerb": false,
|
||||
"sideNavStyle": "summary-only",
|
||||
"simpleOneOfTypeLabel": false,
|
||||
|
@ -1628,7 +1628,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"menuToggle": true,
|
||||
"minCharacterLengthToInitSearch": 3,
|
||||
"nativeScrollbars": false,
|
||||
"noAutoAuth": false,
|
||||
"nonce": undefined,
|
||||
"onlyRequiredInSamples": false,
|
||||
"pathInMiddlePanel": false,
|
||||
|
@ -1638,6 +1637,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"scrollYOffset": [Function],
|
||||
"showExtensions": false,
|
||||
"showObjectSchemaExamples": false,
|
||||
"showSecuritySchemeType": false,
|
||||
"showWebhookVerb": false,
|
||||
"sideNavStyle": "summary-only",
|
||||
"simpleOneOfTypeLabel": false,
|
||||
|
@ -1924,7 +1924,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"menuToggle": true,
|
||||
"minCharacterLengthToInitSearch": 3,
|
||||
"nativeScrollbars": false,
|
||||
"noAutoAuth": false,
|
||||
"nonce": undefined,
|
||||
"onlyRequiredInSamples": false,
|
||||
"pathInMiddlePanel": false,
|
||||
|
@ -1934,6 +1933,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"scrollYOffset": [Function],
|
||||
"showExtensions": false,
|
||||
"showObjectSchemaExamples": false,
|
||||
"showSecuritySchemeType": false,
|
||||
"showWebhookVerb": false,
|
||||
"sideNavStyle": "summary-only",
|
||||
"simpleOneOfTypeLabel": false,
|
||||
|
@ -2181,7 +2181,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"menuToggle": true,
|
||||
"minCharacterLengthToInitSearch": 3,
|
||||
"nativeScrollbars": false,
|
||||
"noAutoAuth": false,
|
||||
"nonce": undefined,
|
||||
"onlyRequiredInSamples": false,
|
||||
"pathInMiddlePanel": false,
|
||||
|
@ -2191,6 +2190,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"scrollYOffset": [Function],
|
||||
"showExtensions": false,
|
||||
"showObjectSchemaExamples": false,
|
||||
"showSecuritySchemeType": false,
|
||||
"showWebhookVerb": false,
|
||||
"sideNavStyle": "summary-only",
|
||||
"simpleOneOfTypeLabel": false,
|
||||
|
@ -2413,7 +2413,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"menuToggle": true,
|
||||
"minCharacterLengthToInitSearch": 3,
|
||||
"nativeScrollbars": false,
|
||||
"noAutoAuth": false,
|
||||
"nonce": undefined,
|
||||
"onlyRequiredInSamples": false,
|
||||
"pathInMiddlePanel": false,
|
||||
|
@ -2423,6 +2422,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
|||
"scrollYOffset": [Function],
|
||||
"showExtensions": false,
|
||||
"showObjectSchemaExamples": false,
|
||||
"showSecuritySchemeType": false,
|
||||
"showWebhookVerb": false,
|
||||
"sideNavStyle": "summary-only",
|
||||
"simpleOneOfTypeLabel": false,
|
||||
|
|
|
@ -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>,"
|
||||
`;
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,11 +12,7 @@ import { SearchStore } from './SearchStore';
|
|||
|
||||
import { SchemaDefinition } from '../components/SchemaDefinition/SchemaDefinition';
|
||||
import { SecurityDefs } from '../components/SecuritySchemes/SecuritySchemes';
|
||||
import {
|
||||
SCHEMA_DEFINITION_JSX_NAME,
|
||||
SECURITY_DEFINITIONS_COMPONENT_NAME,
|
||||
SECURITY_DEFINITIONS_JSX_NAME,
|
||||
} from '../utils/openapi';
|
||||
import { SCHEMA_DEFINITION_JSX_NAME, SECURITY_DEFINITIONS_JSX_NAME } from '../utils/openapi';
|
||||
|
||||
import { IS_BROWSER } from '../utils';
|
||||
|
||||
|
@ -158,12 +154,6 @@ export class AppStore {
|
|||
|
||||
const DEFAULT_OPTIONS: RedocRawOptions = {
|
||||
allowedMdComponents: {
|
||||
[SECURITY_DEFINITIONS_COMPONENT_NAME]: {
|
||||
component: SecurityDefs,
|
||||
propsSelector: (store: AppStore) => ({
|
||||
securitySchemes: store.spec.securitySchemes,
|
||||
}),
|
||||
},
|
||||
[SECURITY_DEFINITIONS_JSX_NAME]: {
|
||||
component: SecurityDefs,
|
||||
propsSelector: (store: AppStore) => ({
|
||||
|
|
|
@ -7,13 +7,7 @@ import {
|
|||
OpenAPIServer,
|
||||
OpenAPIPaths,
|
||||
} from '../types';
|
||||
import {
|
||||
isOperationName,
|
||||
SECURITY_DEFINITIONS_COMPONENT_NAME,
|
||||
setSecuritySchemePrefix,
|
||||
JsonPointer,
|
||||
alphabeticallyByProp,
|
||||
} from '../utils';
|
||||
import { isOperationName, JsonPointer, alphabeticallyByProp } from '../utils';
|
||||
import { MarkdownRenderer } from './MarkdownRenderer';
|
||||
import { GroupModel, OperationModel } from './models';
|
||||
import { OpenAPIParser } from './OpenAPIParser';
|
||||
|
@ -93,14 +87,7 @@ export class MenuBuilder {
|
|||
if (heading.items) {
|
||||
group.items = mapHeadingsDeep(group, heading.items, depth + 1);
|
||||
}
|
||||
if (
|
||||
MarkdownRenderer.containsComponent(
|
||||
group.description || '',
|
||||
SECURITY_DEFINITIONS_COMPONENT_NAME,
|
||||
)
|
||||
) {
|
||||
setSecuritySchemePrefix(group.id + '/');
|
||||
}
|
||||
|
||||
return group;
|
||||
});
|
||||
|
||||
|
|
|
@ -146,6 +146,7 @@ export class MenuStore {
|
|||
let item: IMenuItem | undefined;
|
||||
|
||||
item = this.flatItems.find(i => i.id === id);
|
||||
|
||||
if (item) {
|
||||
this.activateAndScroll(item, false);
|
||||
} else {
|
||||
|
|
|
@ -1,14 +1,8 @@
|
|||
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 {
|
||||
getDefinitionName,
|
||||
isNamedDefinition,
|
||||
SECURITY_DEFINITIONS_COMPONENT_NAME,
|
||||
SECURITY_DEFINITIONS_JSX_NAME,
|
||||
} from '../utils/openapi';
|
||||
import { buildComponentComment, MarkdownRenderer } from './MarkdownRenderer';
|
||||
import { getDefinitionName, isNamedDefinition } from '../utils/openapi';
|
||||
import { RedocNormalizedOptions } from './RedocNormalizedOptions';
|
||||
|
||||
export type MergedOpenAPISchema = OpenAPISchema & { parentRefs?: string[] };
|
||||
|
@ -53,7 +47,6 @@ export class OpenAPIParser {
|
|||
private options: RedocNormalizedOptions = new RedocNormalizedOptions({}),
|
||||
) {
|
||||
this.validate(spec);
|
||||
this.preprocess(spec);
|
||||
|
||||
this.spec = spec;
|
||||
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)
|
||||
*/
|
||||
|
|
|
@ -21,7 +21,6 @@ export interface RedocRawOptions {
|
|||
sortEnumValuesAlphabetically?: boolean | string;
|
||||
sortOperationsAlphabetically?: boolean | string;
|
||||
sortTagsAlphabetically?: boolean | string;
|
||||
noAutoAuth?: boolean | string;
|
||||
nativeScrollbars?: boolean | string;
|
||||
pathInMiddlePanel?: boolean | string;
|
||||
untrustedSpec?: boolean | string;
|
||||
|
@ -42,6 +41,7 @@ export interface RedocRawOptions {
|
|||
expandSingleSchemaField?: boolean | string;
|
||||
schemaExpansionLevel?: number | string | 'all';
|
||||
showObjectSchemaExamples?: boolean | string;
|
||||
showSecuritySchemeType?: boolean;
|
||||
|
||||
unstable_ignoreMimeParameters?: boolean;
|
||||
|
||||
|
@ -224,7 +224,6 @@ export class RedocNormalizedOptions {
|
|||
sortEnumValuesAlphabetically: boolean;
|
||||
sortOperationsAlphabetically: boolean;
|
||||
sortTagsAlphabetically: boolean;
|
||||
noAutoAuth: boolean;
|
||||
nativeScrollbars: boolean;
|
||||
pathInMiddlePanel: boolean;
|
||||
untrustedSpec: boolean;
|
||||
|
@ -245,6 +244,7 @@ export class RedocNormalizedOptions {
|
|||
expandSingleSchemaField: boolean;
|
||||
schemaExpansionLevel: number;
|
||||
showObjectSchemaExamples: boolean;
|
||||
showSecuritySchemeType?: boolean;
|
||||
|
||||
/* tslint:disable-next-line */
|
||||
unstable_ignoreMimeParameters: boolean;
|
||||
|
@ -294,7 +294,6 @@ export class RedocNormalizedOptions {
|
|||
this.sortEnumValuesAlphabetically = argValueToBoolean(raw.sortEnumValuesAlphabetically);
|
||||
this.sortOperationsAlphabetically = argValueToBoolean(raw.sortOperationsAlphabetically);
|
||||
this.sortTagsAlphabetically = argValueToBoolean(raw.sortTagsAlphabetically);
|
||||
this.noAutoAuth = argValueToBoolean(raw.noAutoAuth);
|
||||
this.nativeScrollbars = argValueToBoolean(raw.nativeScrollbars);
|
||||
this.pathInMiddlePanel = argValueToBoolean(raw.pathInMiddlePanel);
|
||||
this.untrustedSpec = argValueToBoolean(raw.untrustedSpec);
|
||||
|
@ -317,6 +316,7 @@ export class RedocNormalizedOptions {
|
|||
this.expandSingleSchemaField = argValueToBoolean(raw.expandSingleSchemaField);
|
||||
this.schemaExpansionLevel = argValueToExpandLevel(raw.schemaExpansionLevel);
|
||||
this.showObjectSchemaExamples = argValueToBoolean(raw.showObjectSchemaExamples);
|
||||
this.showSecuritySchemeType = argValueToBoolean(raw.showSecuritySchemeType);
|
||||
|
||||
this.unstable_ignoreMimeParameters = argValueToBoolean(raw.unstable_ignoreMimeParameters);
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { OpenAPISecurityRequirement, OpenAPISecurityScheme } from '../../types';
|
||||
import { SECURITY_SCHEMES_SECTION_PREFIX } from '../../utils/openapi';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
|
||||
export interface SecurityScheme extends OpenAPISecurityScheme {
|
||||
|
@ -29,7 +28,7 @@ export class SecurityRequirementModel {
|
|||
return {
|
||||
...scheme,
|
||||
id,
|
||||
sectionId: SECURITY_SCHEMES_SECTION_PREFIX + id,
|
||||
sectionId: id,
|
||||
displayName,
|
||||
scopes,
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { OpenAPISecurityScheme, Referenced } from '../../types';
|
||||
import { SECURITY_SCHEMES_SECTION_PREFIX } from '../../utils/openapi';
|
||||
import { SECURITY_SCHEMES_SECTION_PREFIX } from '../../utils';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
|
||||
export class SecuritySchemeModel {
|
||||
|
|
|
@ -615,7 +615,6 @@ export function normalizeServers(
|
|||
});
|
||||
}
|
||||
|
||||
export const SECURITY_DEFINITIONS_COMPONENT_NAME = 'security-definitions';
|
||||
export const SECURITY_DEFINITIONS_JSX_NAME = 'SecurityDefinitions';
|
||||
export const SCHEMA_DEFINITION_JSX_NAME = 'SchemaDefinition';
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user