fix: fix Download button url when spec as object was provided

+ do not output huge base64 encoded link when SSR, instead use button handler

fixes #462
related #540
This commit is contained in:
Roman Hotsiy 2018-07-17 12:17:06 +03:00
parent edc77a2017
commit c35925a332
No known key found for this signature in database
GPG Key ID: 5CB7B3ACABA57CB0
6 changed files with 26 additions and 26 deletions

View File

@ -20,9 +20,16 @@ export interface ApiInfoProps {
@observer @observer
export class ApiInfo extends React.Component<ApiInfoProps> { export class ApiInfo extends React.Component<ApiInfoProps> {
handleDownloadClick = e => {
if (!e.target.href) {
e.target.href = this.props.store.spec.info.downloadLink;
}
};
render() { render() {
const { store } = this.props; const { store } = this.props;
const { info, externalDocs } = store.spec; const { info, externalDocs } = store.spec;
const hideDownloadButton = store.options.hideDownloadButton;
const downloadFilename = info.downloadFileName; const downloadFilename = info.downloadFileName;
const downloadLink = info.downloadLink; const downloadLink = info.downloadLink;
@ -68,10 +75,15 @@ export class ApiInfo extends React.Component<ApiInfoProps> {
<ApiHeader> <ApiHeader>
{info.title} <span>({info.version})</span> {info.title} <span>({info.version})</span>
</ApiHeader> </ApiHeader>
{downloadLink && ( {!hideDownloadButton && (
<p> <p>
Download OpenAPI specification: Download OpenAPI specification:
<DownloadButton download={downloadFilename} target="_blank" href={downloadLink}> <DownloadButton
download={downloadFilename}
target="_blank"
href={downloadLink || '#'}
onClick={this.handleDownloadClick}
>
Download Download
</DownloadButton> </DownloadButton>
</p> </p>

View File

@ -15,7 +15,7 @@ export interface StoreState {
activeItemIdx: number; activeItemIdx: number;
}; };
spec: { spec: {
url: string; url?: string;
data: any; data: any;
}; };
searchIndex: any; searchIndex: any;

View File

@ -39,7 +39,7 @@ class RefCounter {
* Loads and keeps spec. Provides raw spec operations * Loads and keeps spec. Provides raw spec operations
*/ */
export class OpenAPIParser { export class OpenAPIParser {
@observable specUrl: string; @observable specUrl?: string;
@observable.ref spec: OpenAPISpec; @observable.ref spec: OpenAPISpec;
private _refCounter: RefCounter = new RefCounter(); private _refCounter: RefCounter = new RefCounter();
@ -57,8 +57,6 @@ export class OpenAPIParser {
const href = IS_BROWSER ? window.location.href : ''; const href = IS_BROWSER ? window.location.href : '';
if (typeof specUrl === 'string') { if (typeof specUrl === 'string') {
this.specUrl = urlResolve(href, specUrl); this.specUrl = urlResolve(href, specUrl);
} else {
this.specUrl = href;
} }
} }

View File

@ -22,7 +22,7 @@ export class SpecStore {
@computed @computed
get info(): ApiInfoModel { get info(): ApiInfoModel {
return new ApiInfoModel(this.parser, this.options); return new ApiInfoModel(this.parser);
} }
@computed @computed

View File

@ -11,29 +11,20 @@ export class ApiInfoModel implements OpenAPIInfo {
contact?: OpenAPIContact; contact?: OpenAPIContact;
license?: OpenAPILicense; license?: OpenAPILicense;
constructor(private parser: OpenAPIParser, private options: RedocNormalizedOptions) { constructor(private parser: OpenAPIParser) {
Object.assign(this, parser.spec.info); Object.assign(this, parser.spec.info);
} }
get downloadLink() { get downloadLink(): string | undefined {
if (this.options.hideDownloadButton) {
return undefined;
}
if (this.parser.specUrl) { if (this.parser.specUrl) {
return this.parser.specUrl; return this.parser.specUrl;
} }
if (IS_BROWSER && window.Blob && window.URL) { if (IS_BROWSER && window.Blob && window.URL && window.URL.createObjectURL) {
const blob = new Blob([JSON.stringify(this.parser.spec, null, 2)], { const blob = new Blob([JSON.stringify(this.parser.spec, null, 2)], {
type: 'application/json', type: 'application/json',
}); });
return window.URL.createObjectURL(blob); return window.URL.createObjectURL(blob);
} else if (!IS_BROWSER) {
return (
'data:application/octet-stream;base64,' +
new Buffer(JSON.stringify(this.parser.spec, null, 2)).toString('base64')
);
} }
} }

View File

@ -11,6 +11,7 @@ import { OpenAPIExternalDocumentation, OpenAPIServer } from '../../types';
import { import {
getOperationSummary, getOperationSummary,
getStatusCodeType, getStatusCodeType,
IS_BROWSER,
isAbsolutePath, isAbsolutePath,
isStatusCode, isStatusCode,
JsonPointer, JsonPointer,
@ -148,25 +149,23 @@ export class OperationModel implements IMenuItem {
} }
} }
function isNumeric(n) { function normalizeServers(specUrl: string | undefined, servers: OpenAPIServer[]): OpenAPIServer[] {
return !isNaN(parseFloat(n)) && isFinite(n); const baseUrl = specUrl === undefined ? (IS_BROWSER ? window.location.href : '') : specUrl;
}
function normalizeServers(specUrl: string, servers: OpenAPIServer[]): OpenAPIServer[] {
if (servers.length === 0) { if (servers.length === 0) {
return [ return [
{ {
url: specUrl, url: baseUrl,
}, },
]; ];
} }
function normalizeUrl(url: string): string { function normalizeUrl(url: string): string {
url = isAbsolutePath(url) ? url : joinPaths(specUrl, url); url = isAbsolutePath(url) ? url : joinPaths(baseUrl, url);
return stripTrailingSlash(url.startsWith('//') ? `${specProtocol}${url}` : url); return stripTrailingSlash(url.startsWith('//') ? `${specProtocol}${url}` : url);
} }
const { protocol: specProtocol } = urlParse(specUrl); const { protocol: specProtocol } = urlParse(baseUrl);
return servers.map(server => { return servers.map(server => {
return { return {