SG API docs

This commit is contained in:
Pankov 2025-09-10 21:07:13 +03:00
parent 5a9e6a5633
commit 4b8a2da368
15 changed files with 21491 additions and 73 deletions

View File

@ -1,53 +1,167 @@
import * as React from 'react';
import { useEffect, useState } from 'react';
import { render } from 'react-dom';
import { AppContainer } from 'react-hot-loader';
// import DevTools from 'mobx-react-devtools';
import { Redoc, RedocProps } from '../../src/components/Redoc/Redoc';
import styled from 'styled-components';
import { Loading } from '../../src';
import { Redoc } from '../../src/components/Redoc/Redoc';
import { AppStore } from '../../src/services/AppStore';
import { RedocRawOptions } from '../../src/services/RedocNormalizedOptions';
import { loadAndBundleSpec } from '../../src/utils/loadAndBundleSpec';
const renderRoot = (props: RedocProps) =>
const API_SOURCES = [
{ name: 'Supergrid', url: '../swagger/sg/swagger.json' },
{ name: 'What If', url: '../swagger/t5/swagger.json' },
];
const RedocPlayground = () => {
const [store, setStore] = useState<AppStore | null>(null);
const [selectedApi, setSelectedApi] = useState(0);
const [showDownloadButton, setShowDownloadButton] = useState(true);
const [loading, setLoading] = useState(false);
const redocOptions = {
hideDownloadButton: window.location.protocol === 'file:',
theme: {
colors: {
primary: {
main: '#37B5FF',
},
},
typography: {
fontWeightRegular: '400',
fontWeightBold: '700',
fontWeightLight: '300',
fontFamily: '\'Open Sans\', sans-serif',
headings: {
fontFamily: '\'Open Sans\', sans-serif',
},
},
menu: {
backgroundColor: '#fff',
},
logo: {
maxWidth: '150px',
maxHeight: '60px',
gutter: '10px 20px',
},
rightPanel: {
textColor: '#000',
headerTextColor: '#697386',
backgroundColor: '#fff',
tabPanelBackgroundColor: '#f5f5f5',
},
codeSample: {
endpointBackgroundColor: '#59618d',
},
schema: {
defaultDetailsWidth: '100%',
},
},
};
const loadApi = async (apiIndex: number) => {
try {
setLoading(true);
if (store) { store.dispose(); }
const specUrl = API_SOURCES[apiIndex].url;
const spec = await loadAndBundleSpec(specUrl);
const newStore = new AppStore(spec, specUrl, redocOptions);
setStore(newStore);
} catch (error) {
console.error('Error loading API:', error);
} finally {
setLoading(false);
}
};
useEffect(() => {
if (window.location.protocol === 'file:') {
setShowDownloadButton(false);
}
loadApi(selectedApi);
}, []);
const handleApiChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
const newIndex = parseInt(e.target.value, 10);
setSelectedApi(newIndex);
loadApi(newIndex);
};
return (
<div>
<Header>
{showDownloadButton && (
<DownloadButton
target="_blank"
href="../Export/ExportApiDoc"
className="download-button"
>
Download HTML Version
</DownloadButton>
)}
<span style={{ marginLeft: '14px' }}>
<label htmlFor="ApiSources">Tempus Api: </label>
<select id="ApiSources" value={selectedApi} onChange={handleApiChange}>
{API_SOURCES.map((api, index) => (
<option key={index} value={index}>{api.name}</option>
))}
</select>
</span>
</Header>
<div id="redoc">
{loading && (
<Loading color={redocOptions.theme.colors.primary.main} />
)}
{!loading && store && <Redoc store={store} />}
</div>
</div>
);
};
const Header = styled.div`
position: absolute;
top: 0;
right: 0;
z-index: 200;
text-align: right;
height: 30px;
padding: 19px;
font-family: 'Open Sans', sans-serif;
font-weight: 400;
line-height: 1.5em;
font-size: 14px;
`;
const DownloadButton = styled.a`
border: 1px solid rgb(55, 181, 255);
color: rgb(55, 181, 255);
font-weight: normal;
margin-left: 0.5em;
padding: 4px 8px;
display: inline-block;
text-decoration: none;
cursor: pointer;
box-sizing: border-box;
-webkit-tap-highlight-color: rgba(255, 255, 255, 0);
`;
// Рендеринг
const renderRoot = () => {
render(
<AppContainer>
<Redoc {...props} />
<RedocPlayground />
</AppContainer>,
document.getElementById('example'),
);
};
const big = window.location.search.indexOf('big') > -1;
const swagger = window.location.search.indexOf('swagger') > -1;
const userUrl = window.location.search.match(/url=(.*)$/);
const specUrl =
(userUrl && userUrl[1]) || (swagger ? 'swagger.yaml' : big ? 'big-openapi.json' : 'openapi.yaml');
let store;
const options: RedocRawOptions = { nativeScrollbars: false };
async function init() {
const spec = await loadAndBundleSpec(specUrl);
store = new AppStore(spec, specUrl, options);
renderRoot({ store });
}
init();
renderRoot();
// Hot Module Replacement
if (module.hot) {
const reload = (reloadStore = false) => async () => {
if (reloadStore) {
// create a new Store
store.dispose();
const state = await store.toJS();
store = AppStore.fromJS(state);
}
renderRoot({ store });
};
module.hot.accept(['../../src/components/Redoc/Redoc'], reload());
module.hot.accept(['../../src/services/AppStore'], reload(true));
module.hot.accept(() => {
renderRoot();
});
}

View File

@ -4,22 +4,29 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ReDoc</title>
<title>Supergrid API Reference</title>
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700&display=swap" rel="stylesheet">
<link rel="shortcut icon" href="assets/favicon.ico" type="image/x-icon">
<link rel="icon" href="../assets/plugins/redoc/assets/favicon.ico" type="image/x-icon" />
<style>
body {
margin: 0;
padding: 0;
}
redoc {
display: block;
#example {
width: 100%;
}
.tab-success .react-tabs__tab--selected {
color: rgb(0, 170, 19);
background-color: rgba(0, 170, 19, 0.1);
border-color: transparent;
}
</style>
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
</head>
<body>
<redoc id="example"></redoc>
<div id="example"></div>
</body>
</html>

18690
demo/swagger/sg/swagger.json Normal file

File diff suppressed because one or more lines are too long

2528
demo/swagger/t5/swagger.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -98,7 +98,7 @@
"html-webpack-plugin": "^3.1.0",
"jest": "^24.8.0",
"license-checker": "^25.0.1",
"lodash": "^4.17.15",
"lodash": "^4.17.21",
"mobx": "^4.3.1",
"prettier": "^1.18.2",
"prettier-eslint": "^9.0.0",

View File

@ -74,7 +74,7 @@ export const PrismDiv = styled.div`
.token.char,
.token.builtin,
.token.inserted {
color: #a0fbaa;
color: #000000;
& + a,
& + a:visited {
color: #4ed2ba;

View File

@ -35,19 +35,21 @@ export const H3 = styled.h2`
`;
export const RightPanelHeader = styled.h3`
color: ${({ theme }) => theme.rightPanel.textColor};
color: #697386;
font-size: 14px;
font-weight: 600;
${extensionsHook('RightPanelHeader')};
`;
export const UnderlinedHeader = styled.h5`
border-bottom: 1px solid rgba(38, 50, 56, 0.3);
margin: 1em 0 1em 0;
color: rgba(38, 50, 56, 0.5);
font-weight: normal;
color: rgb(0, 0, 0);
font-weight: 600;
text-transform: uppercase;
font-size: 0.929em;
line-height: 20px;
display: inline-block;
margin: 0;
${extensionsHook('UnderlinedHeader')};
`;

View File

@ -39,7 +39,7 @@ export const Section = styled.div.attrs(props => ({
width: 100%;
display: block;
content: '';
border-bottom: 1px solid rgba(0, 0, 0, 0.2);
border-bottom: 1px solid rgb(243, 243, 243);
}
`) ||
''}

View File

@ -5,7 +5,7 @@ import styled from '../styled-components';
export { Tab, TabList, TabPanel } from 'react-tabs';
export const Tabs = styled(ReactTabs)`
export const RequestSamplesTabs = styled(ReactTabs)`
> ul {
list-style: none;
padding: 0;
@ -13,31 +13,30 @@ export const Tabs = styled(ReactTabs)`
margin: 0 -5px;
> li {
padding: 5px 10px;
color: rgb(0, 0, 0);
background: rgb(255, 255, 255);
padding: 2px 5px;
display: inline-block;
background-color: ${({ theme }) => theme.codeSample.backgroundColor};
border-bottom: 1px solid rgba(0, 0, 0, 0.5);
cursor: pointer;
text-align: center;
outline: none;
color: ${({ theme }) => darken(theme.colors.tonalOffset, theme.rightPanel.textColor)};
margin: 0
${({ theme }) => `${theme.spacing.unit}px ${theme.spacing.unit}px ${theme.spacing.unit}px`};
border: 1px solid ${({ theme }) => darken(0.05, theme.codeSample.backgroundColor)};
border: 1px solid rgb(245, 245, 245);
border-radius: 5px;
min-width: 60px;
min-width: 50px;
font-size: 0.9em;
font-weight: bold;
&.react-tabs__tab--selected {
color: ${props => props.theme.colors.text.primary};
background: ${({ theme }) => theme.rightPanel.textColor};
color: rgb(55, 181, 255);
border-color: rgb(55, 181, 255);
background: rgb(255, 255, 255);
}
&:only-child {
flex: none;
min-width: 100px;
}
&.tab-success {
@ -58,7 +57,77 @@ export const Tabs = styled(ReactTabs)`
}
}
> .react-tabs__tab-panel {
background: ${({ theme }) => theme.codeSample.backgroundColor};
border: 1px solid rgb(242, 242, 242);
background: rgb(245, 245, 245);
border-radius: 4px;
& > div,
& > pre {
padding: ${props => props.theme.spacing.unit * 4}px;
margin: 0;
}
& > div > pre {
padding: 0;
}
}
`;
export const Tabs = styled(ReactTabs)`
> ul {
list-style: none;
padding: 0;
margin: 0;
margin: 0 -5px;
> li {
padding: 2px 5px;
display: inline-block;
background-color: ${({ theme }) => theme.codeSample.backgroundColor};
border-bottom: 1px solid rgba(0, 0, 0, 0.5);
cursor: pointer;
text-align: center;
outline: none;
color: ${({ theme }) => darken(theme.colors.tonalOffset, theme.rightPanel.textColor)};
margin: 0
${({ theme }) => `${theme.spacing.unit}px ${theme.spacing.unit}px ${theme.spacing.unit}px`};
border: 1px solid ${({ theme }) => darken(0.05, theme.codeSample.backgroundColor)};
border-radius: 5px;
min-width: 50px;
font-size: 0.9em;
font-weight: bold;
&.react-tabs__tab--selected {
color: rgb(0, 170, 19);
background-color: rgba(0, 170, 19, 0.1);
border-color: transparent;
}
&:only-child {
flex: none;
}
&.tab-success {
color: ${props => props.theme.colors.responses.success.color};
}
&.tab-redirect {
color: ${props => props.theme.colors.responses.redirect.color};
}
&.tab-info {
color: ${props => props.theme.colors.responses.info.color};
}
&.tab-error {
color: ${props => props.theme.colors.responses.error.color};
}
}
}
> .react-tabs__tab-panel {
border: 1px solid rgb(242, 242, 242);
background: rgb(245, 245, 245);
border-radius: 4px;
& > div,
& > pre {
padding: ${props => props.theme.spacing.unit * 4}px;

View File

@ -16,15 +16,20 @@ export const ServerRelativeURL = styled.span`
export const EndpointInfo = styled.div<{ expanded?: boolean; inverted?: boolean }>`
padding: 10px 30px 10px ${props => (props.inverted ? '10px' : '20px')};
border-radius: ${props => (props.inverted ? '0' : '4px 4px 0 0')};
background-color: ${props =>
props.inverted ? 'transparent' : props.theme.codeSample.backgroundColor};
border-radius: 4px;
background-color: ${props => props.theme.codeSample.endpointBackgroundColor || props.theme.codeSample.backgroundColor};
display: flex;
white-space: nowrap;
align-items: center;
border: ${props => (props.inverted ? '0' : '1px solid transparent')};
border-bottom: ${props => (props.inverted ? '1px solid #ccc' : '0')};
transition: border-color 0.25s ease;
font-family: Courier, monospace;
color: rgb(255, 255, 255);
font-weight: 600;
flex: 1 1 0;
overflow-x: hidden;
text-overflow: ellipsis;
${props =>
(props.expanded && !props.inverted && `border-color: ${props.theme.colors.border.dark};`) || ''}
@ -45,6 +50,7 @@ export const HttpVerb = styled.span.attrs((props: { type: string }) => ({
text-transform: uppercase;
font-family: ${props => props.theme.typography.headings.fontFamily};
margin: 0;
border-radius: 4px;
`;
export const ServersOverlay = styled.div<{ expanded: boolean }>`

View File

@ -78,5 +78,4 @@ export class MediaTypeSamples extends React.Component<PayloadSamplesProps, Media
}
const SamplesWrapper = styled.div`
margin-top: 15px;
`;

View File

@ -25,7 +25,8 @@ export const DropdownLabel = styled.span`
`;
export const DropdownWrapper = styled.div`
position: relative;
visibility: hidden;
margin-bottom: -60px;
`;
export const InvertedSimpleDropdown = styled(StyledDropdown)`

View File

@ -4,7 +4,7 @@ import { OperationModel, RedocNormalizedOptions } from '../../services';
import { PayloadSamples } from '../PayloadSamples/PayloadSamples';
import { SourceCodeWithCopy } from '../SourceCode/SourceCode';
import { RightPanelHeader, Tab, TabList, TabPanel, Tabs } from '../../common-elements';
import { RequestSamplesTabs, RightPanelHeader, Tab, TabList, TabPanel } from '../../common-elements';
import { OptionsContext } from '../OptionsProvider';
export interface RequestSamplesProps {
@ -33,7 +33,7 @@ export class RequestSamples extends React.Component<RequestSamplesProps> {
<div>
<RightPanelHeader> Request samples </RightPanelHeader>
<Tabs defaultIndex={0}>
<RequestSamplesTabs defaultIndex={0}>
<TabList hidden={hideTabList}>
{hasBodySample && <Tab key="payload"> Payload </Tab>}
{samples.map(sample => (
@ -54,7 +54,7 @@ export class RequestSamples extends React.Component<RequestSamplesProps> {
<SourceCodeWithCopy lang={sample.lang} source={sample.source} />
</TabPanel>
))}
</Tabs>
</RequestSamplesTabs>
</div>
)) ||
null

View File

@ -1,11 +1,13 @@
import * as React from 'react';
import { darken } from 'polished';
import styled from '../../styled-components';
import { MenuItemLabel } from '../SideMenu/styled.elements';
export const SearchWrap = styled.div`
padding: 5px 0;
margin: 0 20px;
border-radius: 4px;
border: 1px solid rgb(243, 243, 243);
`;
export const SearchInput = styled.input.attrs(() => ({
@ -17,7 +19,6 @@ export const SearchInput = styled.input.attrs(() => ({
padding: 5px ${props => props.theme.spacing.unit * 2}px 5px
${props => props.theme.spacing.unit * 4}px;
border: 0;
border-bottom: 1px solid ${({ theme }) => darken(0.1, theme.menu.backgroundColor)};
font-family: ${({ theme }) => theme.typography.fontFamily};
font-weight: bold;
font-size: 13px;
@ -41,7 +42,7 @@ export const SearchIcon = styled((props: { className?: string }) => (
className: 'search-icon',
})`
position: absolute;
left: ${props => props.theme.spacing.unit * 4}px;
left: 30px;
height: 1.8em;
width: 0.9em;

View File

@ -319,6 +319,7 @@ export interface ResolvedThemeInterface {
};
codeSample: {
backgroundColor: string;
endpointBackgroundColor: string;
};
extensionsHook?: (name: string, props: any) => string;