feat(swagger-ui-react): rewrite into SSR compatible function component (#9855)

Refs #9243
This commit is contained in:
Vladimír Gorej
2024-04-22 13:49:20 +02:00
committed by GitHub
parent fee426b6aa
commit 351191bc57

View File

@@ -1,93 +1,121 @@
import React from "react" /**
* @prettier
*/
"use client"
import React, { useEffect, useCallback, useState } from "react"
import PropTypes from "prop-types" import PropTypes from "prop-types"
import SwaggerUIConstructor from "#swagger-ui" import SwaggerUIConstructor from "#swagger-ui"
class SwaggerUI extends React.Component { const SwaggerUI = ({
constructor (props) { spec = SwaggerUIConstructor.defaultOptions.spec,
super(props) url = SwaggerUIConstructor.defaultOptions.url,
this.SwaggerUIComponent = null layout = SwaggerUIConstructor.defaultOptions.layout,
this.system = null requestInterceptor = SwaggerUIConstructor.defaultOptions.requestInterceptor,
} responseInterceptor = SwaggerUIConstructor.defaultOptions.responseInterceptor,
supportedSubmitMethods = SwaggerUIConstructor.defaultOptions
.supportedSubmitMethods,
queryConfigEnabled = SwaggerUIConstructor.defaultOptions.queryConfigEnabled,
plugins = SwaggerUIConstructor.defaultOptions.plugins,
displayOperationId = SwaggerUIConstructor.defaultOptions.displayOperationId,
showMutatedRequest = SwaggerUIConstructor.defaultOptions.showMutatedRequest,
docExpansion = SwaggerUIConstructor.defaultOptions.docExpansion,
defaultModelExpandDepth = SwaggerUIConstructor.defaultOptions
.defaultModelExpandDepth,
defaultModelsExpandDepth = SwaggerUIConstructor.defaultOptions
.defaultModelsExpandDepth,
defaultModelRendering = SwaggerUIConstructor.defaultOptions
.defaultModelRendering,
presets = SwaggerUIConstructor.defaultOptions.presets,
deepLinking = SwaggerUIConstructor.defaultOptions.deepLinking,
showExtensions = SwaggerUIConstructor.defaultOptions.showExtensions,
showCommonExtensions = SwaggerUIConstructor.defaultOptions
.showCommonExtensions,
filter = SwaggerUIConstructor.defaultOptions.filter,
requestSnippetsEnabled = SwaggerUIConstructor.defaultOptions
.requestSnippetsEnabled,
requestSnippets = SwaggerUIConstructor.defaultOptions.requestSnippets,
tryItOutEnabled = SwaggerUIConstructor.defaultOptions.tryItOutEnabled,
displayRequestDuration = SwaggerUIConstructor.defaultOptions
.displayRequestDuration,
withCredentials = SwaggerUIConstructor.defaultOptions.withCredentials,
persistAuthorization = SwaggerUIConstructor.defaultOptions
.persistAuthorization,
oauth2RedirectUrl = SwaggerUIConstructor.defaultOptions.oauth2RedirectUrl,
onComplete = null,
}) => {
const [system, setSystem] = useState(null)
const SwaggerUIComponent = system?.getComponent("App", "root")
componentDidMount() { const handleComplete = useCallback(() => {
const ui = SwaggerUIConstructor({ if (typeof onComplete === "function") {
plugins: this.props.plugins, onComplete()
spec: this.props.spec, }
url: this.props.url, }, [onComplete])
useEffect(() => {
setSystem(
SwaggerUIConstructor({
plugins,
spec,
url,
dom_id: null, dom_id: null,
domNode: null, domNode: null,
layout: this.props.layout, layout,
defaultModelsExpandDepth: this.props.defaultModelsExpandDepth, defaultModelsExpandDepth,
defaultModelRendering: this.props.defaultModelRendering, defaultModelRendering,
presets: [SwaggerUIConstructor.presets.apis, ...this.props.presets], presets: [SwaggerUIConstructor.presets.apis, ...presets],
requestInterceptor: this.props.requestInterceptor, requestInterceptor,
responseInterceptor: this.props.responseInterceptor, responseInterceptor,
onComplete: this.onComplete, onComplete: handleComplete,
docExpansion: this.props.docExpansion, docExpansion,
supportedSubmitMethods: this.props.supportedSubmitMethods, supportedSubmitMethods,
queryConfigEnabled: this.props.queryConfigEnabled, queryConfigEnabled,
defaultModelExpandDepth: this.props.defaultModelExpandDepth, defaultModelExpandDepth,
displayOperationId: this.props.displayOperationId, displayOperationId,
tryItOutEnabled: this.props.tryItOutEnabled, tryItOutEnabled,
displayRequestDuration: this.props.displayRequestDuration, displayRequestDuration,
requestSnippetsEnabled: this.props.requestSnippetsEnabled, requestSnippetsEnabled,
requestSnippets: this.props.requestSnippets, requestSnippets,
showMutatedRequest: this.props.showMutatedRequest, showMutatedRequest,
deepLinking: this.props.deepLinking, deepLinking,
showExtensions: this.props.showExtensions, showExtensions,
showCommonExtensions: this.props.showCommonExtensions, showCommonExtensions,
filter: this.props.filter, filter,
persistAuthorization: this.props.persistAuthorization, persistAuthorization,
withCredentials: this.props.withCredentials, withCredentials,
...(typeof this.props.oauth2RedirectUrl === "string" ? { oauth2RedirectUrl: this.props.oauth2RedirectUrl} : {}) ...(typeof oauth2RedirectUrl === "string"
? { oauth2RedirectUrl: oauth2RedirectUrl }
: {}),
}) })
)
}, [])
this.system = ui useEffect(() => {
this.SwaggerUIComponent = ui.getComponent("App", "root") if (system) {
const prevStateUrl = system.specSelectors.url()
this.forceUpdate() if (url !== prevStateUrl) {
} system.specActions.updateSpec("")
if (url) {
render() { system.specActions.updateUrl(url)
return this.SwaggerUIComponent ? <this.SwaggerUIComponent /> : null system.specActions.download(url)
}
componentDidUpdate(prevProps) {
const prevStateUrl = this.system.specSelectors.url()
if(this.props.url !== prevStateUrl || this.props.url !== prevProps.url) {
// flush current content
this.system.specActions.updateSpec("")
if(this.props.url) {
// update the internal URL
this.system.specActions.updateUrl(this.props.url)
// trigger remote definition fetch
this.system.specActions.download(this.props.url)
} }
} }
const prevStateSpec = this.system.specSelectors.specStr() const prevStateSpec = system.specSelectors.specStr()
if(this.props.spec && (this.props.spec !== prevStateSpec || this.props.spec !== prevProps.spec)) { if (spec && spec !== prevStateSpec) {
if(typeof this.props.spec === "object") { const updatedSpec =
this.system.specActions.updateSpec(JSON.stringify(this.props.spec)) typeof spec === "object" ? JSON.stringify(spec) : spec
} else { system.specActions.updateSpec(updatedSpec)
this.system.specActions.updateSpec(this.props.spec)
}
} }
} }
}, [url, spec])
onComplete = () => { return SwaggerUIComponent ? <SwaggerUIComponent /> : null
if (typeof this.props.onComplete === "function") {
return this.props.onComplete(this.system)
}
}
} }
SwaggerUI.propTypes = { SwaggerUI.propTypes = {
spec: PropTypes.oneOfType([ spec: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
PropTypes.string,
PropTypes.object,
]),
url: PropTypes.string, url: PropTypes.string,
layout: PropTypes.string, layout: PropTypes.string,
requestInterceptor: PropTypes.func, requestInterceptor: PropTypes.func,
@@ -95,7 +123,16 @@ SwaggerUI.propTypes = {
onComplete: PropTypes.func, onComplete: PropTypes.func,
docExpansion: PropTypes.oneOf(["list", "full", "none"]), docExpansion: PropTypes.oneOf(["list", "full", "none"]),
supportedSubmitMethods: PropTypes.arrayOf( supportedSubmitMethods: PropTypes.arrayOf(
PropTypes.oneOf(["get", "put", "post", "delete", "options", "head", "patch", "trace"]) PropTypes.oneOf([
"get",
"put",
"post",
"delete",
"options",
"head",
"patch",
"trace",
])
), ),
queryConfigEnabled: PropTypes.bool, queryConfigEnabled: PropTypes.bool,
plugins: PropTypes.oneOfType([ plugins: PropTypes.oneOfType([
@@ -112,10 +149,7 @@ SwaggerUI.propTypes = {
deepLinking: PropTypes.bool, deepLinking: PropTypes.bool,
showExtensions: PropTypes.bool, showExtensions: PropTypes.bool,
showCommonExtensions: PropTypes.bool, showCommonExtensions: PropTypes.bool,
filter: PropTypes.oneOfType([ filter: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
PropTypes.string,
PropTypes.bool,
]),
requestSnippetsEnabled: PropTypes.bool, requestSnippetsEnabled: PropTypes.bool,
requestSnippets: PropTypes.object, requestSnippets: PropTypes.object,
tryItOutEnabled: PropTypes.bool, tryItOutEnabled: PropTypes.bool,
@@ -125,37 +159,9 @@ SwaggerUI.propTypes = {
oauth2RedirectUrl: PropTypes.string, oauth2RedirectUrl: PropTypes.string,
} }
SwaggerUI.defaultProps = {
spec: SwaggerUIConstructor.defaultOptions.spec,
url: SwaggerUIConstructor.defaultOptions.url,
layout: SwaggerUIConstructor.defaultOptions.layout,
requestInterceptor: SwaggerUIConstructor.defaultOptions.requestInterceptor,
responseInterceptor: SwaggerUIConstructor.defaultOptions.responseInterceptor,
supportedSubmitMethods: SwaggerUIConstructor.defaultOptions.supportedSubmitMethods,
queryConfigEnabled: SwaggerUIConstructor.defaultOptions.queryConfigEnabled,
plugins: SwaggerUIConstructor.defaultOptions.plugins,
displayOperationId: SwaggerUIConstructor.defaultOptions.displayOperationId,
showMutatedRequest: SwaggerUIConstructor.defaultOptions.showMutatedRequest,
docExpansion: SwaggerUIConstructor.defaultOptions.docExpansion,
defaultModelExpandDepth: SwaggerUIConstructor.defaultOptions.defaultModelExpandDepth,
defaultModelsExpandDepth: SwaggerUIConstructor.defaultOptions.defaultModelsExpandDepth,
defaultModelRendering: SwaggerUIConstructor.defaultOptions.defaultModelRendering,
presets: SwaggerUIConstructor.defaultOptions.presets,
deepLinking: SwaggerUIConstructor.defaultOptions.deepLinking,
showExtensions: SwaggerUIConstructor.defaultOptions.showExtensions,
showCommonExtensions: SwaggerUIConstructor.defaultOptions.showCommonExtensions,
filter: SwaggerUIConstructor.defaultOptions.filter,
requestSnippetsEnabled: SwaggerUIConstructor.defaultOptions.requestSnippetsEnabled,
requestSnippets: SwaggerUIConstructor.defaultOptions.requestSnippets,
tryItOutEnabled: SwaggerUIConstructor.defaultOptions.tryItOutEnabled,
displayRequestDuration: SwaggerUIConstructor.defaultOptions.displayRequestDuration,
withCredentials: SwaggerUIConstructor.defaultOptions.withCredentials,
persistAuthorization: SwaggerUIConstructor.defaultOptions.persistAuthorization,
oauth2RedirectUrl: undefined,
}
SwaggerUI.System = SwaggerUIConstructor.System SwaggerUI.System = SwaggerUIConstructor.System
SwaggerUI.presets = SwaggerUIConstructor.presets SwaggerUI.presets = SwaggerUIConstructor.presets
SwaggerUI.plugins = SwaggerUIConstructor.plugins SwaggerUI.plugins = SwaggerUIConstructor.plugins
SwaggerUI.defaultOptions = SwaggerUIConstructor.defaultOptions
export default SwaggerUI export default SwaggerUI