Merge branch 'master' into zopflipng

This commit is contained in:
kyle
2018-01-03 18:55:00 -06:00
committed by GitHub
42 changed files with 615 additions and 215 deletions

View File

@@ -1,5 +1,6 @@
import React, { Component } from "react"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
const propStyle = { color: "#999", fontStyle: "italic" }
@@ -12,7 +13,7 @@ export default class ArrayModel extends Component {
name: PropTypes.string,
required: PropTypes.bool,
expandDepth: PropTypes.number,
specPath: PropTypes.array.isRequired,
specPath: ImPropTypes.list.isRequired,
depth: PropTypes.number
}
@@ -48,7 +49,17 @@ export default class ArrayModel extends Component {
!description ? null :
<Markdown source={ description } />
}
<span><Model { ...this.props } getConfigs={ getConfigs } specPath={[...specPath, "items"]} name={null} schema={ items } required={ false } depth={ depth + 1 } /></span>
<span>
<Model
{ ...this.props }
getConfigs={ getConfigs }
specPath={specPath.push("items")}
name={null}
schema={ items }
required={ false }
depth={ depth + 1 }
/>
</span>
]
</ModelCollapse>
</span>

View File

@@ -1,5 +1,6 @@
import React from "react"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
export default class ModelExample extends React.Component {
static propTypes = {
@@ -9,7 +10,7 @@ export default class ModelExample extends React.Component {
example: PropTypes.any.isRequired,
isExecute: PropTypes.bool,
getConfigs: PropTypes.func.isRequired,
specPath: PropTypes.array.isRequired,
specPath: ImPropTypes.list.isRequired,
}
constructor(props, context) {

View File

@@ -1,8 +1,9 @@
import React, { PureComponent } from "react"
import React from "react"
import ImmutablePureComponent from "react-immutable-pure-component"
import ImPropTypes from "react-immutable-proptypes"
import PropTypes from "prop-types"
export default class Model extends PureComponent {
export default class Model extends ImmutablePureComponent {
static propTypes = {
schema: ImPropTypes.orderedMap.isRequired,
getComponent: PropTypes.func.isRequired,
@@ -13,7 +14,7 @@ export default class Model extends PureComponent {
required: PropTypes.bool,
expandDepth: PropTypes.number,
depth: PropTypes.number,
specPath: PropTypes.array.isRequired,
specPath: ImPropTypes.list.isRequired,
}
getModelName =( ref )=> {

View File

@@ -1,4 +1,5 @@
import React, { Component } from "react"
import Im from "immutable"
import PropTypes from "prop-types"
export default class Models extends Component {
@@ -20,7 +21,7 @@ export default class Models extends Component {
const specPathBase = specSelectors.isOAS3() ? ["components", "schemas"] : ["definitions"]
const ModelWrapper = getComponent("ModelWrapper")
const Collapse = getComponent("Collapse")
const Collapse = getComponent("Collapse")
return <section className={ showModels ? "models is-open" : "models"}>
<h4 onClick={() => layoutActions.show("models", !showModels)}>
@@ -37,7 +38,7 @@ export default class Models extends Component {
<ModelWrapper name={ name }
expandDepth={ defaultModelsExpandDepth }
schema={ model }
specPath={[...specPathBase, name]}
specPath={Im.List([...specPathBase, name])}
getComponent={ getComponent }
specSelectors={ specSelectors }
getConfigs = {getConfigs}

View File

@@ -1,6 +1,7 @@
import React, { Component, } from "react"
import PropTypes from "prop-types"
import { List } from "immutable"
import ImPropTypes from "react-immutable-proptypes"
const braceOpen = "{"
const braceClose = "}"
@@ -17,7 +18,7 @@ export default class ObjectModel extends Component {
isRef: PropTypes.bool,
expandDepth: PropTypes.number,
depth: PropTypes.number,
specPath: PropTypes.object.isRequired
specPath: ImPropTypes.list.isRequired
}
render(){
@@ -102,7 +103,7 @@ export default class ObjectModel extends Component {
<Model key={ `object-${name}-${key}_${value}` } { ...otherProps }
required={ isRequired }
getComponent={ getComponent }
specPath={[...specPath, "properties", key]}
specPath={specPath.push("properties", key)}
getConfigs={ getConfigs }
schema={ value }
depth={ depth + 1 } />
@@ -141,7 +142,7 @@ export default class ObjectModel extends Component {
<td>
<Model { ...otherProps } required={ false }
getComponent={ getComponent }
specPath={[...specPath, "additionalProperties"]}
specPath={specPath.push("additionalProperties")}
getConfigs={ getConfigs }
schema={ additionalProperties }
depth={ depth + 1 } />
@@ -156,7 +157,7 @@ export default class ObjectModel extends Component {
{anyOf.map((schema, k) => {
return <div key={k}><Model { ...otherProps } required={ false }
getComponent={ getComponent }
specPath={[...specPath, "anyOf", k]}
specPath={specPath.push("anyOf", k)}
getConfigs={ getConfigs }
schema={ schema }
depth={ depth + 1 } /></div>
@@ -172,7 +173,7 @@ export default class ObjectModel extends Component {
{oneOf.map((schema, k) => {
return <div key={k}><Model { ...otherProps } required={ false }
getComponent={ getComponent }
specPath={[...specPath, "oneOf", k]}
specPath={specPath.push("oneOf", k)}
getConfigs={ getConfigs }
schema={ schema }
depth={ depth + 1 } /></div>
@@ -189,7 +190,7 @@ export default class ObjectModel extends Component {
<Model { ...otherProps }
required={ false }
getComponent={ getComponent }
specPath={[...specPath, "not"]}
specPath={specPath.push("not")}
getConfigs={ getConfigs }
schema={ not }
depth={ depth + 1 } />

View File

@@ -2,11 +2,12 @@ import React, { PureComponent } from "react"
import PropTypes from "prop-types"
import { getList } from "core/utils"
import { getExtensions, sanitizeUrl } from "core/utils"
import { Iterable } from "immutable"
import { Iterable, List } from "immutable"
import ImPropTypes from "react-immutable-proptypes"
export default class Operation extends PureComponent {
static propTypes = {
specPath: PropTypes.array.isRequired,
specPath: ImPropTypes.list.isRequired,
operation: PropTypes.instanceOf(Iterable).isRequired,
response: PropTypes.instanceOf(Iterable),
request: PropTypes.instanceOf(Iterable),
@@ -33,7 +34,7 @@ export default class Operation extends PureComponent {
operation: null,
response: null,
request: null,
specPath: []
specPath: List()
}
render() {
@@ -174,7 +175,7 @@ export default class Operation extends PureComponent {
<Parameters
parameters={parameters}
specPath={[...specPath, "parameters"]}
specPath={specPath.push("parameters")}
operation={operation}
onChangeKey={onChangeKey}
onTryoutClick = { onTryoutClick }
@@ -248,7 +249,7 @@ export default class Operation extends PureComponent {
specActions={ specActions }
produces={ produces }
producesValue={ operation.get("produces_value") }
specPath={[...specPath, "responses"]}
specPath={specPath.push("responses")}
path={ path }
method={ method }
displayRequestDuration={ displayRequestDuration }

View File

@@ -1,5 +1,6 @@
import React from "react"
import PropTypes from "prop-types"
import Im from "immutable"
import { createDeepLinkPath, sanitizeUrl } from "core/utils"
const SWAGGER2_OPERATION_METHODS = [
@@ -119,7 +120,7 @@ export default class Operations extends React.Component {
operations.map( op => {
const path = op.get("path")
const method = op.get("method")
const specPath = ["paths", path, method]
const specPath = Im.List(["paths", path, method])
// FIXME: (someday) this logic should probably be in a selector,

View File

@@ -1,6 +1,7 @@
import React, { Component } from "react"
import { Map } from "immutable"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
import win from "core/window"
import { getExtensions } from "core/utils"
@@ -15,7 +16,7 @@ export default class ParameterRow extends Component {
specSelectors: PropTypes.object.isRequired,
pathMethod: PropTypes.array.isRequired,
getConfigs: PropTypes.func.isRequired,
specPath: PropTypes.array.isRequired,
specPath: ImPropTypes.list.isRequired
}
constructor(props, context) {
@@ -139,7 +140,7 @@ export default class ParameterRow extends Component {
{
bodyParam && schema ? <ModelExample getComponent={ getComponent }
specPath={[...specPath, "schema"]}
specPath={specPath.push("schema")}
getConfigs={ getConfigs }
isExecute={ isExecute }
specSelectors={ specSelectors }

View File

@@ -21,7 +21,7 @@ export default class Parameters extends Component {
onChangeKey: PropTypes.array,
pathMethod: PropTypes.array.isRequired,
getConfigs: PropTypes.func.isRequired,
specPath: PropTypes.array.isRequired,
specPath: ImPropTypes.list.isRequired,
}
@@ -98,7 +98,7 @@ export default class Parameters extends Component {
eachMap(parameters, (parameter, i) => (
<ParameterRow
fn={ fn }
specPath={[...specPath, i]}
specPath={specPath.push(i.toString())}
getComponent={ getComponent }
getConfigs={ getConfigs }
param={ parameter }

View File

@@ -1,7 +1,8 @@
import React from "react"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
import cx from "classnames"
import { fromJS, Seq, Iterable } from "immutable"
import { fromJS, Seq, Iterable, List } from "immutable"
import { getSampleSchema, fromJSOrdered } from "core/utils"
const getExampleComponent = ( sampleResponse, examples, HighlightCode ) => {
@@ -47,7 +48,7 @@ export default class Response extends React.Component {
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
specPath: PropTypes.array.isRequired,
specPath: ImPropTypes.list.isRequired,
fn: PropTypes.object.isRequired,
contentType: PropTypes.string,
controlsAcceptHeader: PropTypes.bool,
@@ -99,7 +100,7 @@ export default class Response extends React.Component {
var schema, specPathWithPossibleSchema
if(isOAS3()) {
const schemaPath = ["content", this.state.responseContentType, "schema"]
const schemaPath = List(["content", this.state.responseContentType, "schema"])
const oas3SchemaForContentType = response.getIn(schemaPath)
sampleResponse = oas3SchemaForContentType ? getSampleSchema(oas3SchemaForContentType.toJS(), this.state.responseContentType, {
includeReadOnly: true
@@ -108,7 +109,7 @@ export default class Response extends React.Component {
specPathWithPossibleSchema = oas3SchemaForContentType ? schemaPath : specPath
} else {
schema = inferSchema(response.toJS()) // TODO: don't convert back and forth. Lets just stick with immutable for inferSchema
specPathWithPossibleSchema = response.has("schema") ? [...specPath, "schema"] : specPath
specPathWithPossibleSchema = response.has("schema") ? specPath.push("schema") : specPath
sampleResponse = schema ? getSampleSchema(schema, contentType, {
includeReadOnly: true,
includeWriteOnly: true // writeOnly has no filtering effect in swagger 2.0

View File

@@ -1,6 +1,7 @@
import React from "react"
import PropTypes from "prop-types"
import { fromJS, Iterable } from "immutable"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
import { defaultStatusCode, getAcceptControllingResponse } from "core/utils"
export default class Responses extends React.Component {
@@ -17,7 +18,7 @@ export default class Responses extends React.Component {
specSelectors: PropTypes.object.isRequired,
specActions: PropTypes.object.isRequired,
oas3Actions: PropTypes.object.isRequired,
specPath: PropTypes.array.isRequired,
specPath: ImPropTypes.list.isRequired,
fn: PropTypes.object.isRequired
}
@@ -120,7 +121,7 @@ export default class Responses extends React.Component {
let className = tryItOutResponse && tryItOutResponse.get("status") == code ? "response_current" : ""
return (
<Response key={ code }
specPath={[...specPath, code]}
specPath={specPath.push(code)}
isDefault={defaultCode === code}
fn={fn}
className={ className }

View File

@@ -1,5 +1,6 @@
import React, { PureComponent } from "react"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
import { helpers } from "swagger-client"
import { Iterable, fromJS } from "immutable"
@@ -31,8 +32,7 @@ export default class OperationContainer extends PureComponent {
request: PropTypes.instanceOf(Iterable),
security: PropTypes.instanceOf(Iterable),
isDeepLinkingEnabled: PropTypes.bool.isRequired,
specPath: PropTypes.array.isRequired,
specPath: ImPropTypes.list.isRequired,
getComponent: PropTypes.func.isRequired,
authActions: PropTypes.object,
oas3Actions: PropTypes.object,

View File

@@ -92,6 +92,20 @@ module.exports = function SwaggerUI(opts) {
}, constructorConfig.initialState)
}
if(constructorConfig.initialState) {
// if the user sets a key as `undefined`, that signals to us that we
// should delete the key entirely.
// known usage: Swagger-Editor validate plugin tests
for (var key in constructorConfig.initialState) {
if(
constructorConfig.initialState.hasOwnProperty(key)
&& constructorConfig.initialState[key] === undefined
) {
delete storeConfigs.state[key]
}
}
}
let inlinePlugin = ()=> {
return {
fn: constructorConfig.fn,
@@ -105,8 +119,6 @@ module.exports = function SwaggerUI(opts) {
var system = store.getSystem()
system.initOAuth = system.authActions.configureAuth
const downloadSpec = (fetchedConfig) => {
if(typeof constructorConfig !== "object") {
return system
@@ -138,6 +150,9 @@ module.exports = function SwaggerUI(opts) {
} else if(mergedConfig.dom_id) {
let domNode = document.querySelector(mergedConfig.dom_id)
system.render(domNode, "App")
} else if(mergedConfig.dom_id === null || mergedConfig.domNode === null) {
// do nothing
// this is useful for testing that does not need to do any rendering
} else {
console.error("Skipped rendering: no `dom_id` or `domNode` was specified")
}

View File

@@ -5,6 +5,10 @@ import * as specWrapActionReplacements from "./spec-wrap-actions"
export default function() {
return {
afterLoad(system) {
this.rootInjects = this.rootInjects || {}
this.rootInjects.initOAuth = system.authActions.configureAuth
},
statePlugins: {
auth: {
reducers,

View File

@@ -1,5 +1,5 @@
import YAML from "js-yaml"
import yamlConfig from "../../../swagger-config.yaml"
import yamlConfig from "root/swagger-config.yaml"
import * as actions from "./actions"
import * as selectors from "./selectors"
import reducers from "./reducers"

View File

@@ -1,26 +1,13 @@
import reduce from "lodash/reduce"
let request = require.context("./transformers/", true, /\.js$/)
let errorTransformers = []
import * as NotOfType from "./transformers/not-of-type"
import * as ParameterOneOf from "./transformers/parameter-oneof"
import * as StripInstance from "./transformers/strip-instance"
request.keys().forEach( function( key ){
if( key === "./hook.js" ) {
return
}
if( !key.match(/js$/) ) {
return
}
if( key.slice(2).indexOf("/") > -1) {
// skip files in subdirs
return
}
errorTransformers.push({
name: toTitleCase(key).replace(".js", "").replace("./", ""),
transform: request(key).transform
})
})
const errorTransformers = [
NotOfType,
ParameterOneOf,
StripInstance
]
export default function transformErrors (errors, system) {
let inputs = {
@@ -47,10 +34,3 @@ export default function transformErrors (errors, system) {
})
}
function toTitleCase(str) {
return str
.split("-")
.map(substr => substr[0].toUpperCase() + substr.slice(1))
.join("")
}

View File

@@ -38,7 +38,7 @@ const RequestBody = ({
expandDepth={1}
isExecute={isExecute}
schema={mediaTypeValue.get("schema")}
specPath={[...specPath, "content", contentType]}
specPath={specPath.push("content", contentType)}
example={<RequestBodyEditor
requestBody={requestBody}
onChange={onChange}

View File

@@ -72,10 +72,10 @@ export const servers = onlyOAS3(createSelector(
export const isOAS3 = (ori, system) => () => {
const spec = system.getSystem().specSelectors.specJson()
return isOAS3Helper(spec)
return isOAS3Helper(Map.isMap(spec) ? spec : Map())
}
export const isSwagger2 = (ori, system) => () => {
const spec = system.getSystem().specSelectors.specJson()
return isSwagger2Helper(spec)
return isSwagger2Helper(Map.isMap(spec) ? spec : Map())
}

View File

@@ -29,7 +29,7 @@ class Parameters extends Component {
fn: PropTypes.object.isRequired,
tryItOutEnabled: PropTypes.bool,
allowTryItOut: PropTypes.bool,
specPath: PropTypes.array.isRequired,
specPath: ImPropTypes.list.isRequired,
onTryoutClick: PropTypes.func,
onCancelClick: PropTypes.func,
onChangeKey: PropTypes.array,
@@ -107,7 +107,7 @@ class Parameters extends Component {
const { isOAS3 } = specSelectors
const requestBody = operation.get("requestBody")
const requestBodySpecPath = [...specPath.slice(0, -1), "requestBody"] // remove the "parameters" part
const requestBodySpecPath = specPath.slice(0, -1).push("requestBody") // remove the "parameters" part
return (
<div className="opblock-section">
@@ -143,7 +143,7 @@ class Parameters extends Component {
eachMap(parameters, (parameter, i) => (
<ParameterRow fn={ fn }
getComponent={ getComponent }
specPath={[...specPath, i]}
specPath={specPath.push(i)}
getConfigs={ getConfigs }
param={ parameter }
key={ parameter.get( "name" ) }

View File

@@ -68,7 +68,7 @@ export const parseToJson = (str) => ({specActions, specSelectors, errActions}) =
line: e.mark && e.mark.line ? e.mark.line + 1 : undefined
})
}
if(json) {
if(json && typeof json === "object") {
return specActions.updateJsonSpec(json)
}
return {}
@@ -105,8 +105,7 @@ export const resolveSpec = (json, url) => ({specActions, specSelectors, errActio
errActions.clear({
type: "thrown"
})
if(errors.length > 0) {
if(Array.isArray(errors) && errors.length > 0) {
let preparedErrors = errors
.map(err => {
console.error(err)

View File

@@ -4,6 +4,10 @@ import { fromJS, Set, Map, OrderedMap, List } from "immutable"
const DEFAULT_TAG = "default"
const OPERATION_METHODS = [
"get", "put", "post", "delete", "options", "head", "patch", "trace"
]
const state = state => {
return state || Map()
}
@@ -95,6 +99,9 @@ export const operations = createSelector(
return {}
}
path.forEach((operation, method) => {
if(OPERATION_METHODS.indexOf(method) < 0) {
return
}
list = list.push(fromJS({
path: pathName,
method,

View File

@@ -1,17 +0,0 @@
import { pascalCaseFilename } from "core/utils"
const request = require.context(".", true, /\.jsx?$/)
request.keys().forEach( function( key ){
if( key === "./index.js" ) {
return
}
// if( key.slice(2).indexOf("/") > -1) {
// // skip files in subdirs
// return
// }
let mod = request(key)
module.exports[pascalCaseFilename(key)] = mod.default ? mod.default : mod
})

View File

@@ -1,5 +1,4 @@
import * as components from "./components"
import SplitPaneMode from "./components/split-pane-mode"
export default function SplitPaneModePlugin() {
return {
// statePlugins: {
@@ -9,6 +8,8 @@ export default function SplitPaneModePlugin() {
// }
// },
components,
components: {
SplitPaneMode
}
}
}

View File

@@ -10,7 +10,7 @@ import auth from "core/plugins/auth"
import util from "core/plugins/util"
import SplitPaneModePlugin from "core/plugins/split-pane-mode"
import downloadUrlPlugin from "core/plugins/download-url"
import configsPlugin from "plugins/configs"
import configsPlugin from "core/plugins/configs"
import deepLinkingPlugin from "core/plugins/deep-linking"
import OperationContainer from "core/containers/OperationContainer"

View File

@@ -68,6 +68,12 @@ export default class Store {
if(rebuild) {
this.buildSystem()
}
const needAnotherRebuild = callAfterLoad.call(this.system, plugins, this.getSystem())
if(needAnotherRebuild) {
this.buildSystem()
}
}
buildSystem(buildReducer=true) {
@@ -170,7 +176,7 @@ export default class Store {
if(!isFn(newAction)) {
throw new TypeError("wrapActions needs to return a function that returns a new function (ie the wrapped action)")
}
return newAction
return wrapWithTryCatch(newAction)
}, action || Function.prototype)
})
}
@@ -250,11 +256,11 @@ export default class Store {
return objMap(obj, (fn) => {
return (...args) => {
let res = fn.apply(null, [getNestedState(), ...args])
let res = wrapWithTryCatch(fn).apply(null, [getNestedState(), ...args])
// If a selector returns a function, give it the system - for advanced usage
if(typeof(res) === "function")
res = res(getSystem())
res = wrapWithTryCatch(res)(getSystem())
return res
}
@@ -320,6 +326,25 @@ function combinePlugins(plugins, toolbox) {
return {}
}
function callAfterLoad(plugins, system, { hasLoaded } = {}) {
let calledSomething = hasLoaded
if(isObject(plugins) && !isArray(plugins)) {
if(typeof plugins.afterLoad === "function") {
calledSomething = true
wrapWithTryCatch(plugins.afterLoad).call(this, system)
}
}
if(isFunc(plugins))
return callAfterLoad.call(this, plugins(system), system, { hasLoaded: calledSomething })
if(isArray(plugins)) {
return plugins.map(plugin => callAfterLoad.call(this, plugin, system, { hasLoaded: calledSomething }))
}
return calledSomething
}
// Wraps deepExtend, to account for certain fields, being wrappers.
// Ie: we need to convert some fields into arrays, and append to them.
// Rather than overwrite
@@ -411,14 +436,36 @@ function makeReducer(reducerObj) {
if(!reducerObj)
return state
let redFn = reducerObj[action.type]
let redFn = (reducerObj[action.type])
if(redFn) {
return redFn(state, action)
const res = wrapWithTryCatch(redFn)(state, action)
// If the try/catch wrapper kicks in, we'll get null back...
// in that case, we want to avoid making any changes to state
return res === null ? state : res
}
return state
}
}
function wrapWithTryCatch(fn, {
logErrors = true
} = {}) {
if(typeof fn !== "function") {
return fn
}
return function(...args) {
try {
return fn.call(this, ...args)
} catch(e) {
if(logErrors) {
console.error(e)
}
return null
}
}
}
function configureStore(rootReducer, initialState, getSystem) {
const store = createStoreWithMiddleware(rootReducer, initialState, getSystem)

View File

@@ -1,17 +1,7 @@
import { pascalCaseFilename } from "js/utils"
import Configs from "./configs"
import Topbar from "./topbar"
const request = require.context(".", true, /\.jsx?$/)
request.keys().forEach( function( key ){
if( key === "./index.js" ) {
return
}
// if( key.slice(2).indexOf("/") > -1) {
// // skip files in subdirs
// return
// }
let mod = request(key)
module.exports[pascalCaseFilename(key)] = mod.default ? mod.default : mod
})
export default {
Configs,
Topbar
}

View File

@@ -1,6 +1,6 @@
import StandaloneLayout from "./layout"
import TopbarPlugin from "plugins/topbar"
import ConfigsPlugin from "plugins/configs"
import ConfigsPlugin from "corePlugins/configs"
// the Standalone preset