mirror of
https://github.com/Redocly/redoc.git
synced 2025-08-01 19:00:21 +03:00
DOP-3342: Implement back button (#3)
This commit is contained in:
parent
b3d531770b
commit
7b85fa64fe
|
@ -4,7 +4,13 @@ describe('Menu', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have valid items count', () => {
|
it('should have valid items count', () => {
|
||||||
cy.get('.menu-content').find('li').should('have.length', 34);
|
cy.get('.menu-content').find('li').should('have.length', 35);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a back button', () => {
|
||||||
|
cy.contains('a', 'Back to Docs')
|
||||||
|
.should('have.attr', 'href')
|
||||||
|
.and('contain', 'https://mongodb.com/docs/');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should sync active menu items while scroll', () => {
|
it('should sync active menu items while scroll', () => {
|
||||||
|
@ -17,6 +23,7 @@ describe('Menu', () => {
|
||||||
.scrollIntoView()
|
.scrollIntoView()
|
||||||
.wait(100)
|
.wait(100)
|
||||||
.get('[role=menuitem].active')
|
.get('[role=menuitem].active')
|
||||||
|
.scrollIntoView()
|
||||||
.children()
|
.children()
|
||||||
.last()
|
.last()
|
||||||
.should('have.text', 'Add a new pet to the store')
|
.should('have.text', 'Add a new pet to the store')
|
||||||
|
@ -28,6 +35,7 @@ describe('Menu', () => {
|
||||||
.scrollIntoView()
|
.scrollIntoView()
|
||||||
.wait(100)
|
.wait(100)
|
||||||
.get('[role=menuitem].active')
|
.get('[role=menuitem].active')
|
||||||
|
.scrollIntoView()
|
||||||
.children()
|
.children()
|
||||||
.last()
|
.last()
|
||||||
.should('have.text', 'Add a new pet to the store')
|
.should('have.text', 'Add a new pet to the store')
|
||||||
|
@ -85,7 +93,7 @@ describe('Menu', () => {
|
||||||
cy.url().should('include', 'deletePetBy%22Id');
|
cy.url().should('include', 'deletePetBy%22Id');
|
||||||
});
|
});
|
||||||
|
|
||||||
it.only('should encode URL when the operation IDs have backslashes', () => {
|
it('should encode URL when the operation IDs have backslashes', () => {
|
||||||
cy.visit('e2e/standalone-3-1.html');
|
cy.visit('e2e/standalone-3-1.html');
|
||||||
cy.get('label span[title="pet"]').click({ multiple: true, force: true });
|
cy.get('label span[title="pet"]').click({ multiple: true, force: true });
|
||||||
cy.get('li').contains('OperationId with backslash').click({ multiple: true, force: true });
|
cy.get('li').contains('OperationId with backslash').click({ multiple: true, force: true });
|
||||||
|
|
|
@ -13,7 +13,8 @@ describe('Supporting both operation/* and parent/*/operation* urls', () => {
|
||||||
it('should supporting parent/*/operation url', () => {
|
it('should supporting parent/*/operation url', () => {
|
||||||
cy.url().then(loc => {
|
cy.url().then(loc => {
|
||||||
cy.visit(loc + '#tag/pet/operation/addPet');
|
cy.visit(loc + '#tag/pet/operation/addPet');
|
||||||
cy.get('li[data-item-id="tag/pet/operation/addPet"]').should('be.visible');
|
|
||||||
|
cy.get('li[data-item-id="tag/pet/operation/addPet"]').scrollIntoView().should('be.visible');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { AppStore } from '../../services';
|
||||||
import { ApiInfo } from '../ApiInfo/';
|
import { ApiInfo } from '../ApiInfo/';
|
||||||
import { ApiLogo } from '../ApiLogo/ApiLogo';
|
import { ApiLogo } from '../ApiLogo/ApiLogo';
|
||||||
import { ContentItems } from '../ContentItems/ContentItems';
|
import { ContentItems } from '../ContentItems/ContentItems';
|
||||||
import { SideMenu } from '../SideMenu/SideMenu';
|
import { SideMenu, SideMenuBackButton } from '../SideMenu';
|
||||||
import { StickyResponsiveSidebar } from '../StickySidebar/StickyResponsiveSidebar';
|
import { StickyResponsiveSidebar } from '../StickySidebar/StickyResponsiveSidebar';
|
||||||
import {
|
import {
|
||||||
ApiContentWrap,
|
ApiContentWrap,
|
||||||
|
@ -55,6 +55,10 @@ export class Redoc extends React.Component<RedocProps> {
|
||||||
<RedocWrap className="redoc-wrap">
|
<RedocWrap className="redoc-wrap">
|
||||||
<StickyResponsiveSidebar menu={menu} className="menu-content">
|
<StickyResponsiveSidebar menu={menu} className="menu-content">
|
||||||
<ApiLogo info={spec.info} />
|
<ApiLogo info={spec.info} />
|
||||||
|
<SideMenuBackButton
|
||||||
|
backNavigationPath={options.customOptions?.backNavigationPath}
|
||||||
|
siteTitle={options.customOptions?.siteTitle}
|
||||||
|
/>
|
||||||
<SideMenuTitle>{store.spec.info.title}</SideMenuTitle>
|
<SideMenuTitle>{store.spec.info.title}</SideMenuTitle>
|
||||||
{(!options.disableSearch && (
|
{(!options.disableSearch && (
|
||||||
<SearchBox
|
<SearchBox
|
||||||
|
|
|
@ -10,7 +10,7 @@ export const SideMenuTitle = styled.div`
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
margin: 24px 16px;
|
margin: 0 16px 24px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const RedocWrap = styled.div`
|
export const RedocWrap = styled.div`
|
||||||
|
|
38
src/components/SideMenu/SideMenuBackButton.tsx
Normal file
38
src/components/SideMenu/SideMenuBackButton.tsx
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import {
|
||||||
|
MenuItemLabel,
|
||||||
|
MenuItemLi,
|
||||||
|
MenuItemTitle,
|
||||||
|
MenuItemUl,
|
||||||
|
MenuLink,
|
||||||
|
MenuBreak,
|
||||||
|
} from './styled.elements';
|
||||||
|
|
||||||
|
interface SideMenuBackButtonProps {
|
||||||
|
backNavigationPath?: string;
|
||||||
|
siteTitle?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_NAVIGATION_PATH = 'https://mongodb.com/docs/';
|
||||||
|
|
||||||
|
export const SideMenuBackButton = ({ backNavigationPath, siteTitle }: SideMenuBackButtonProps) => {
|
||||||
|
// Depth of menu item can dictate the styling of the component
|
||||||
|
const depth = 1;
|
||||||
|
const href = backNavigationPath ?? DEFAULT_NAVIGATION_PATH;
|
||||||
|
const text = `Back to ${siteTitle ?? ''} Docs`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<MenuItemUl expanded={true}>
|
||||||
|
<MenuItemLi depth={depth}>
|
||||||
|
<MenuLink href={href}>
|
||||||
|
<MenuItemLabel depth={depth} active={false} isBackButton={true}>
|
||||||
|
<MenuItemTitle>← {text}</MenuItemTitle>
|
||||||
|
</MenuItemLabel>
|
||||||
|
</MenuLink>
|
||||||
|
</MenuItemLi>
|
||||||
|
</MenuItemUl>
|
||||||
|
<MenuBreak />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,4 +1,5 @@
|
||||||
export * from './MenuItem';
|
export * from './MenuItem';
|
||||||
export * from './MenuItems';
|
export * from './MenuItems';
|
||||||
export * from './SideMenu';
|
export * from './SideMenu';
|
||||||
|
export * from './SideMenuBackButton';
|
||||||
export * from './styled.elements';
|
export * from './styled.elements';
|
||||||
|
|
|
@ -45,6 +45,15 @@ function menuItemActive(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The back button and currently active labels maintain a different colors
|
||||||
|
function selectMenuLabelColor(
|
||||||
|
props: MenuItemLabelType & { theme: ResolvedThemeInterface },
|
||||||
|
): string {
|
||||||
|
const { active, depth, isBackButton, theme } = props;
|
||||||
|
if (isBackButton) return palette.gray.dark1;
|
||||||
|
return active ? menuItemActive(depth, props, 'activeTextColor') : theme.sidebar.textColor;
|
||||||
|
}
|
||||||
|
|
||||||
export const MenuItemUl = styled.ul<{ expanded: boolean }>`
|
export const MenuItemUl = styled.ul<{ expanded: boolean }>`
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -64,6 +73,10 @@ export const MenuItemLi = styled.li<{ depth: number }>`
|
||||||
${props => (props.depth === 0 ? 'margin-top: 15px' : '')};
|
${props => (props.depth === 0 ? 'margin-top: 15px' : '')};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const MenuLink = styled.a`
|
||||||
|
text-decoration: none;
|
||||||
|
`;
|
||||||
|
|
||||||
export const menuItemDepth = {
|
export const menuItemDepth = {
|
||||||
0: css`
|
0: css`
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
|
@ -82,6 +95,7 @@ export interface MenuItemLabelType {
|
||||||
depth: number;
|
depth: number;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
deprecated?: boolean;
|
deprecated?: boolean;
|
||||||
|
isBackButton?: boolean;
|
||||||
type?: string;
|
type?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,12 +106,10 @@ export const MenuItemLabel = styled.label.attrs((props: MenuItemLabelType) => ({
|
||||||
}),
|
}),
|
||||||
}))<MenuItemLabelType>`
|
}))<MenuItemLabelType>`
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: ${props =>
|
color: ${props => selectMenuLabelColor(props)};
|
||||||
props.active
|
|
||||||
? menuItemActive(props.depth, props, 'activeTextColor')
|
|
||||||
: props.theme.sidebar.textColor};
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 12.5px ${props => props.theme.spacing.unit * 4}px;
|
${props => props.isBackButton && 'margin-top: 16px;'}
|
||||||
|
padding: 6px 16px;
|
||||||
${({ depth, type, theme }) =>
|
${({ depth, type, theme }) =>
|
||||||
(type === 'section' && depth > 1 && 'padding-left: ' + theme.spacing.unit * 8 + 'px;') || ''}
|
(type === 'section' && depth > 1 && 'padding-left: ' + theme.spacing.unit * 8 + 'px;') || ''}
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -112,7 +124,10 @@ export const MenuItemLabel = styled.label.attrs((props: MenuItemLabelType) => ({
|
||||||
${props => (props.deprecated && deprecatedCss) || ''};
|
${props => (props.deprecated && deprecatedCss) || ''};
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: ${props => menuItemActive(props.depth, props, 'activeTextColor')};
|
color: ${props =>
|
||||||
|
props.isBackButton
|
||||||
|
? palette.gray.dark1
|
||||||
|
: menuItemActive(props.depth, props, 'activeTextColor')};
|
||||||
background-color: ${palette.gray.light2};
|
background-color: ${palette.gray.light2};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +140,13 @@ export const MenuItemLabel = styled.label.attrs((props: MenuItemLabelType) => ({
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const MenuBreak = styled.hr`
|
||||||
|
border: unset;
|
||||||
|
border-bottom: 1px solid ${palette.gray.light2};
|
||||||
|
margin: 16px 0;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
export const MenuItemTitle = styled.span<{ width?: string }>`
|
export const MenuItemTitle = styled.span<{ width?: string }>`
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
|
|
@ -76,6 +76,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
||||||
"minItems": undefined,
|
"minItems": undefined,
|
||||||
"options": RedocNormalizedOptions {
|
"options": RedocNormalizedOptions {
|
||||||
"allowedMdComponents": Object {},
|
"allowedMdComponents": Object {},
|
||||||
|
"customOptions": Object {},
|
||||||
"disableSearch": false,
|
"disableSearch": false,
|
||||||
"downloadDefinitionUrl": undefined,
|
"downloadDefinitionUrl": undefined,
|
||||||
"downloadFileName": undefined,
|
"downloadFileName": undefined,
|
||||||
|
@ -406,6 +407,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
||||||
"minItems": undefined,
|
"minItems": undefined,
|
||||||
"options": RedocNormalizedOptions {
|
"options": RedocNormalizedOptions {
|
||||||
"allowedMdComponents": Object {},
|
"allowedMdComponents": Object {},
|
||||||
|
"customOptions": Object {},
|
||||||
"disableSearch": false,
|
"disableSearch": false,
|
||||||
"downloadDefinitionUrl": undefined,
|
"downloadDefinitionUrl": undefined,
|
||||||
"downloadFileName": undefined,
|
"downloadFileName": undefined,
|
||||||
|
@ -723,6 +725,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
||||||
"minItems": undefined,
|
"minItems": undefined,
|
||||||
"options": RedocNormalizedOptions {
|
"options": RedocNormalizedOptions {
|
||||||
"allowedMdComponents": Object {},
|
"allowedMdComponents": Object {},
|
||||||
|
"customOptions": Object {},
|
||||||
"disableSearch": false,
|
"disableSearch": false,
|
||||||
"downloadDefinitionUrl": undefined,
|
"downloadDefinitionUrl": undefined,
|
||||||
"downloadFileName": undefined,
|
"downloadFileName": undefined,
|
||||||
|
@ -1102,6 +1105,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
||||||
"minItems": undefined,
|
"minItems": undefined,
|
||||||
"options": RedocNormalizedOptions {
|
"options": RedocNormalizedOptions {
|
||||||
"allowedMdComponents": Object {},
|
"allowedMdComponents": Object {},
|
||||||
|
"customOptions": Object {},
|
||||||
"disableSearch": false,
|
"disableSearch": false,
|
||||||
"downloadDefinitionUrl": undefined,
|
"downloadDefinitionUrl": undefined,
|
||||||
"downloadFileName": undefined,
|
"downloadFileName": undefined,
|
||||||
|
@ -1444,6 +1448,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
||||||
"minItems": undefined,
|
"minItems": undefined,
|
||||||
"options": RedocNormalizedOptions {
|
"options": RedocNormalizedOptions {
|
||||||
"allowedMdComponents": Object {},
|
"allowedMdComponents": Object {},
|
||||||
|
"customOptions": Object {},
|
||||||
"disableSearch": false,
|
"disableSearch": false,
|
||||||
"downloadDefinitionUrl": undefined,
|
"downloadDefinitionUrl": undefined,
|
||||||
"downloadFileName": undefined,
|
"downloadFileName": undefined,
|
||||||
|
@ -1757,6 +1762,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
||||||
"minItems": undefined,
|
"minItems": undefined,
|
||||||
"options": RedocNormalizedOptions {
|
"options": RedocNormalizedOptions {
|
||||||
"allowedMdComponents": Object {},
|
"allowedMdComponents": Object {},
|
||||||
|
"customOptions": Object {},
|
||||||
"disableSearch": false,
|
"disableSearch": false,
|
||||||
"downloadDefinitionUrl": undefined,
|
"downloadDefinitionUrl": undefined,
|
||||||
"downloadFileName": undefined,
|
"downloadFileName": undefined,
|
||||||
|
@ -2095,6 +2101,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
||||||
],
|
],
|
||||||
"options": RedocNormalizedOptions {
|
"options": RedocNormalizedOptions {
|
||||||
"allowedMdComponents": Object {},
|
"allowedMdComponents": Object {},
|
||||||
|
"customOptions": Object {},
|
||||||
"disableSearch": false,
|
"disableSearch": false,
|
||||||
"downloadDefinitionUrl": undefined,
|
"downloadDefinitionUrl": undefined,
|
||||||
"downloadFileName": undefined,
|
"downloadFileName": undefined,
|
||||||
|
@ -2463,6 +2470,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
||||||
"minItems": undefined,
|
"minItems": undefined,
|
||||||
"options": RedocNormalizedOptions {
|
"options": RedocNormalizedOptions {
|
||||||
"allowedMdComponents": Object {},
|
"allowedMdComponents": Object {},
|
||||||
|
"customOptions": Object {},
|
||||||
"disableSearch": false,
|
"disableSearch": false,
|
||||||
"downloadDefinitionUrl": undefined,
|
"downloadDefinitionUrl": undefined,
|
||||||
"downloadFileName": undefined,
|
"downloadFileName": undefined,
|
||||||
|
@ -2793,6 +2801,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
||||||
"minItems": undefined,
|
"minItems": undefined,
|
||||||
"options": RedocNormalizedOptions {
|
"options": RedocNormalizedOptions {
|
||||||
"allowedMdComponents": Object {},
|
"allowedMdComponents": Object {},
|
||||||
|
"customOptions": Object {},
|
||||||
"disableSearch": false,
|
"disableSearch": false,
|
||||||
"downloadDefinitionUrl": undefined,
|
"downloadDefinitionUrl": undefined,
|
||||||
"downloadFileName": undefined,
|
"downloadFileName": undefined,
|
||||||
|
@ -3110,6 +3119,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
|
||||||
"minItems": undefined,
|
"minItems": undefined,
|
||||||
"options": RedocNormalizedOptions {
|
"options": RedocNormalizedOptions {
|
||||||
"allowedMdComponents": Object {},
|
"allowedMdComponents": Object {},
|
||||||
|
"customOptions": Object {},
|
||||||
"disableSearch": false,
|
"disableSearch": false,
|
||||||
"downloadDefinitionUrl": undefined,
|
"downloadDefinitionUrl": undefined,
|
||||||
"downloadFileName": undefined,
|
"downloadFileName": undefined,
|
||||||
|
|
|
@ -3,21 +3,21 @@
|
||||||
exports[`SecurityRequirement should render SecurityDefs 1`] = `
|
exports[`SecurityRequirement should render SecurityDefs 1`] = `
|
||||||
"<div id=\\"section/Authentication/petstore_auth\\" data-section-id=\\"section/Authentication/petstore_auth\\" class=\\"sc-eCApnc gxBYnR\\"><div class=\\"sc-iCoGMd dglGZe\\"><div class=\\"sc-hKFxyN gXsFjB\\"><h2 class=\\"sc-pNWdM fyozOE\\">petstore_auth</h2><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><p>Get access to data while protecting your account credentials.
|
"<div id=\\"section/Authentication/petstore_auth\\" data-section-id=\\"section/Authentication/petstore_auth\\" class=\\"sc-eCApnc gxBYnR\\"><div class=\\"sc-iCoGMd dglGZe\\"><div class=\\"sc-hKFxyN gXsFjB\\"><h2 class=\\"sc-pNWdM fyozOE\\">petstore_auth</h2><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><p>Get access to data while protecting your account credentials.
|
||||||
OAuth2 is also a safer and more secure way to give you access.</p>
|
OAuth2 is also a safer and more secure way to give you access.</p>
|
||||||
</div><div class=\\"sc-EZqKI XgSsW\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Security Scheme Type: </b><span>OAuth2</span></div><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><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 lasomv redoc-markdown\\"><p>modify pets in your account</p>
|
</div><div class=\\"sc-eEVmNe cScyK\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Security Scheme Type: </b><span>OAuth2</span></div><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Flow type: </b><code>implicit </code></div><div class=\\"sc-jXcxbT gllWlr\\"><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-jXcxbT gllWlr\\"><b> Scopes: </b></div><div class=\\"sc-fmdNqN eKoRDV container\\" style=\\"height: 4em;\\"><ul><li><code>write:pets</code> - <span class=\\"sc-carFqZ lasomv redoc-markdown\\"><p>modify pets in your account</p>
|
||||||
</span></li><li><code>read:pets</code> - <span class=\\"sc-carFqZ lasomv redoc-markdown\\"><p>read your pets</p>
|
</span></li><li><code>read:pets</code> - <span class=\\"sc-carFqZ lasomv 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 gxBYnR\\"><div class=\\"sc-iCoGMd dglGZe\\"><div class=\\"sc-hKFxyN gXsFjB\\"><h2 class=\\"sc-pNWdM fyozOE\\">GitLab_PersonalAccessToken</h2><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><p>GitLab Personal Access Token description</p>
|
</span></li></ul></div><div class=\\"sc-ljsmAU blhEdv\\"></div></div></div></div></div></div><div id=\\"section/Authentication/GitLab_PersonalAccessToken\\" data-section-id=\\"section/Authentication/GitLab_PersonalAccessToken\\" class=\\"sc-eCApnc gxBYnR\\"><div class=\\"sc-iCoGMd dglGZe\\"><div class=\\"sc-hKFxyN gXsFjB\\"><h2 class=\\"sc-pNWdM fyozOE\\">GitLab_PersonalAccessToken</h2><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><p>GitLab Personal Access Token description</p>
|
||||||
</div><div class=\\"sc-EZqKI XgSsW\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Security Scheme Type: </b><span>API Key</span></div><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><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 gxBYnR\\"><div class=\\"sc-iCoGMd dglGZe\\"><div class=\\"sc-hKFxyN gXsFjB\\"><h2 class=\\"sc-pNWdM fyozOE\\">GitLab_OpenIdConnect</h2><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><p>GitLab OpenIdConnect description</p>
|
</div><div class=\\"sc-eEVmNe cScyK\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Security Scheme Type: </b><span>API Key</span></div><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><div class=\\"sc-jXcxbT gllWlr\\"><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 gxBYnR\\"><div class=\\"sc-iCoGMd dglGZe\\"><div class=\\"sc-hKFxyN gXsFjB\\"><h2 class=\\"sc-pNWdM fyozOE\\">GitLab_OpenIdConnect</h2><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><p>GitLab OpenIdConnect description</p>
|
||||||
</div><div class=\\"sc-EZqKI XgSsW\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Security Scheme Type: </b><span>OpenID Connect</span></div><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><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 gxBYnR\\"><div class=\\"sc-iCoGMd dglGZe\\"><div class=\\"sc-hKFxyN gXsFjB\\"><h2 class=\\"sc-pNWdM fyozOE\\">basicAuth</h2><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"></div><div class=\\"sc-EZqKI XgSsW\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Security Scheme Type: </b><span>HTTP</span></div><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><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>"
|
</div><div class=\\"sc-eEVmNe cScyK\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Security Scheme Type: </b><span>OpenID Connect</span></div><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><div class=\\"sc-jXcxbT gllWlr\\"><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 gxBYnR\\"><div class=\\"sc-iCoGMd dglGZe\\"><div class=\\"sc-hKFxyN gXsFjB\\"><h2 class=\\"sc-pNWdM fyozOE\\">basicAuth</h2><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"></div><div class=\\"sc-eEVmNe cScyK\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Security Scheme Type: </b><span>HTTP</span></div><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>HTTP Authorization Scheme: </b><code>basic</code></div><div class=\\"sc-jXcxbT gllWlr\\"></div></div></div></div></div></div>"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SecurityRequirement should render authDefinition 1`] = `"<div class=\\"sc-bQCEYZ dFCVnY\\"><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 egUPBF\\"><span class=\\"sc-kYPZxB hfhKoI\\">(<span class=\\"sc-hzUIXc jFcJRk\\">API Key: <i>GitLab_PersonalAccessToken</i></span><span class=\\"sc-hzUIXc jFcJRk\\">OpenID Connect: <i>GitLab_OpenIdConnect</i></span><span class=\\"sc-hzUIXc jFcJRk\\">HTTP: <i>basicAuth</i></span>) </span><span class=\\"sc-kYPZxB hfhKoI\\"><span class=\\"sc-hzUIXc jFcJRk\\">OAuth2: <i>petstore_auth</i></span></span></div></div>,"`;
|
exports[`SecurityRequirement should render authDefinition 1`] = `"<div class=\\"sc-EZqKI kGytBW\\"><div class=\\"sc-jHcXXw kurgNF\\"><h5 class=\\"sc-iqAclL sc-fXgAZx eONCmm xiVXt\\">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-bQCEYZ fTcEhU\\"><span class=\\"sc-dWBRfb hMKSgN\\">(<span class=\\"sc-xGAEC ejInCB\\">API Key: <i>GitLab_PersonalAccessToken</i></span><span class=\\"sc-xGAEC ejInCB\\">OpenID Connect: <i>GitLab_OpenIdConnect</i></span><span class=\\"sc-xGAEC ejInCB\\">HTTP: <i>basicAuth</i></span>) </span><span class=\\"sc-dWBRfb hMKSgN\\"><span class=\\"sc-xGAEC ejInCB\\">OAuth2: <i>petstore_auth</i></span></span></div></div>,"`;
|
||||||
|
|
||||||
exports[`SecurityRequirement should render authDefinition 2`] = `
|
exports[`SecurityRequirement should render authDefinition 2`] = `
|
||||||
"<div class=\\"sc-bQCEYZ cHLZiQ\\"><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 iXBOyl\\"><span class=\\"sc-kYPZxB fUZJUa\\">(<span class=\\"sc-hzUIXc jFcJRk\\">API Key: <i>GitLab_PersonalAccessToken</i></span><span class=\\"sc-hzUIXc jFcJRk\\">OpenID Connect: <i>GitLab_OpenIdConnect</i></span><span class=\\"sc-hzUIXc jFcJRk\\">HTTP: <i>basicAuth</i></span>) </span><span class=\\"sc-kYPZxB fUZJUa\\"><span class=\\"sc-hzUIXc jFcJRk\\">OAuth2: <i>petstore_auth</i> (<code class=\\"sc-eHEENL ktuYhQ\\">write:pets</code><code class=\\"sc-eHEENL ktuYhQ\\">read:pets</code>) </span></span></div></div><div class=\\"sc-EZqKI XgSsW\\"><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 dTVIxT gmKdHC\\"><p>Get access to data while protecting your account credentials.
|
"<div class=\\"sc-EZqKI cdLWLC\\"><div class=\\"sc-jHcXXw kurgNF\\"><h5 class=\\"sc-iqAclL sc-fXgAZx eONCmm xiVXt\\">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-bQCEYZ bPYjiQ\\"><span class=\\"sc-dWBRfb fJIppX\\">(<span class=\\"sc-xGAEC ejInCB\\">API Key: <i>GitLab_PersonalAccessToken</i></span><span class=\\"sc-xGAEC ejInCB\\">OpenID Connect: <i>GitLab_OpenIdConnect</i></span><span class=\\"sc-xGAEC ejInCB\\">HTTP: <i>basicAuth</i></span>) </span><span class=\\"sc-dWBRfb fJIppX\\"><span class=\\"sc-xGAEC ejInCB\\">OAuth2: <i>petstore_auth</i> (<code class=\\"sc-kYPZxB jkXEVp\\">write:pets</code><code class=\\"sc-kYPZxB jkXEVp\\">read:pets</code>) </span></span></div></div><div class=\\"sc-eEVmNe cScyK\\"><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 dTVIxT gmKdHC\\"><p>Get access to data while protecting your account credentials.
|
||||||
OAuth2 is also a safer and more secure way to give you access.</p>
|
OAuth2 is also a safer and more secure way to give you access.</p>
|
||||||
</div><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><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 lasomv redoc-markdown\\"><p>modify pets in your account</p>
|
</div><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Flow type: </b><code>implicit </code></div><div class=\\"sc-jXcxbT gllWlr\\"><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-jXcxbT gllWlr\\"><b> Scopes: </b></div><div class=\\"sc-fmdNqN eKoRDV container\\" style=\\"height: 4em;\\"><ul><li><code>write:pets</code> - <span class=\\"sc-carFqZ lasomv redoc-markdown\\"><p>modify pets in your account</p>
|
||||||
</span></li><li><code>read:pets</code> - <span class=\\"sc-carFqZ lasomv redoc-markdown\\"><p>read your pets</p>
|
</span></li><li><code>read:pets</code> - <span class=\\"sc-carFqZ lasomv redoc-markdown\\"><p>read your pets</p>
|
||||||
</span></li></ul></div><div class=\\"sc-eEVmNe gbLbHj\\"></div></div></div><div class=\\"sc-EZqKI XgSsW\\"><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 dTVIxT gmKdHC\\"><p>GitLab Personal Access Token description</p>
|
</span></li></ul></div><div class=\\"sc-ljsmAU blhEdv\\"></div></div></div><div class=\\"sc-eEVmNe cScyK\\"><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 dTVIxT gmKdHC\\"><p>GitLab Personal Access Token description</p>
|
||||||
</div><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>Header parameter name: </b><code>PRIVATE-TOKEN</code></div></div></div><div class=\\"sc-EZqKI XgSsW\\"><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 dTVIxT gmKdHC\\"><p>GitLab OpenIdConnect description</p>
|
</div><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Header parameter name: </b><code>PRIVATE-TOKEN</code></div></div></div><div class=\\"sc-eEVmNe cScyK\\"><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 dTVIxT gmKdHC\\"><p>GitLab OpenIdConnect description</p>
|
||||||
</div><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><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 XgSsW\\"><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 dTVIxT gmKdHC\\"></div><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><div class=\\"sc-fXgAZx gZCyoW\\"><b>HTTP Authorization Scheme: </b><code>basic</code></div><div class=\\"sc-fXgAZx gZCyoW\\"></div></div></div>,"
|
</div><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><div class=\\"sc-jXcxbT gllWlr\\"><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-eEVmNe cScyK\\"><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 dTVIxT gmKdHC\\"></div><div class=\\"sc-iJCRrE sc-ciSkZP dTVIxT gmKdHC\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>HTTP Authorization Scheme: </b><code>basic</code></div><div class=\\"sc-jXcxbT gllWlr\\"></div></div></div>,"
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -6,6 +6,12 @@ import { setRedocLabels } from './Labels';
|
||||||
import { SideNavStyleEnum } from './types';
|
import { SideNavStyleEnum } from './types';
|
||||||
import type { LabelsConfigRaw, MDXComponentMeta } from './types';
|
import type { LabelsConfigRaw, MDXComponentMeta } from './types';
|
||||||
|
|
||||||
|
// Custom options needed by DOP. Add any custom options here.
|
||||||
|
interface CustomOptions {
|
||||||
|
backNavigationPath?: string;
|
||||||
|
siteTitle?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface RedocRawOptions {
|
export interface RedocRawOptions {
|
||||||
theme?: ThemeInterface;
|
theme?: ThemeInterface;
|
||||||
scrollYOffset?: number | string | (() => number);
|
scrollYOffset?: number | string | (() => number);
|
||||||
|
@ -56,6 +62,9 @@ export interface RedocRawOptions {
|
||||||
hideFab?: boolean;
|
hideFab?: boolean;
|
||||||
minCharacterLengthToInitSearch?: number;
|
minCharacterLengthToInitSearch?: number;
|
||||||
showWebhookVerb?: boolean;
|
showWebhookVerb?: boolean;
|
||||||
|
|
||||||
|
// Custom options specific to DOP's use case
|
||||||
|
customOptions?: CustomOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function argValueToBoolean(val?: string | boolean, defaultValue?: boolean): boolean {
|
export function argValueToBoolean(val?: string | boolean, defaultValue?: boolean): boolean {
|
||||||
|
@ -259,6 +268,8 @@ export class RedocNormalizedOptions {
|
||||||
|
|
||||||
nonce?: string;
|
nonce?: string;
|
||||||
|
|
||||||
|
customOptions?: CustomOptions;
|
||||||
|
|
||||||
constructor(raw: RedocRawOptions, defaults: RedocRawOptions = {}) {
|
constructor(raw: RedocRawOptions, defaults: RedocRawOptions = {}) {
|
||||||
raw = { ...defaults, ...raw };
|
raw = { ...defaults, ...raw };
|
||||||
const hook = raw.theme && raw.theme.extensionsHook;
|
const hook = raw.theme && raw.theme.extensionsHook;
|
||||||
|
@ -335,5 +346,8 @@ export class RedocNormalizedOptions {
|
||||||
this.hideFab = argValueToBoolean(raw.hideFab);
|
this.hideFab = argValueToBoolean(raw.hideFab);
|
||||||
this.minCharacterLengthToInitSearch = argValueToNumber(raw.minCharacterLengthToInitSearch) || 3;
|
this.minCharacterLengthToInitSearch = argValueToNumber(raw.minCharacterLengthToInitSearch) || 3;
|
||||||
this.showWebhookVerb = argValueToBoolean(raw.showWebhookVerb);
|
this.showWebhookVerb = argValueToBoolean(raw.showWebhookVerb);
|
||||||
|
|
||||||
|
// No normalization needed for custom options at the moment. Expand if needed
|
||||||
|
this.customOptions = raw.customOptions || {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user