Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
253573200a | ||
|
|
024b7db81e | ||
|
|
5b1dbec9b0 | ||
|
|
64f99356a5 | ||
|
|
b3e80cc500 | ||
|
|
53ea2003c1 | ||
|
|
a037c7205b | ||
|
|
63d5f164c6 | ||
|
|
2e816e0440 | ||
|
|
0818882a90 | ||
|
|
0751022b77 | ||
|
|
fc070408f6 | ||
|
|
a47da98b54 | ||
|
|
12a9fbc0ca | ||
|
|
bd41b736a8 | ||
|
|
a8f204181e | ||
|
|
67d472acc7 | ||
|
|
aebcfe8e5d | ||
|
|
71c0742735 | ||
|
|
8e4f94b33f | ||
|
|
a9ea10da2c | ||
|
|
8f3535b5ff | ||
|
|
0ca0b8120f | ||
|
|
603c436427 | ||
|
|
c601f9b0ca | ||
|
|
c742df9573 | ||
|
|
ecfda531de | ||
|
|
b749ea737d | ||
|
|
248aeca0db | ||
|
|
adf03e49ae | ||
|
|
9bad35ed85 | ||
|
|
ccc3b109a7 | ||
|
|
56caeec8c8 | ||
|
|
9d48c4751a | ||
|
|
8c4b511227 |
@@ -0,0 +1,7 @@
|
||||
/.git
|
||||
/.github
|
||||
/dev-helpers
|
||||
/docs
|
||||
/src
|
||||
/swagger-ui-dist-package
|
||||
/test
|
||||
@@ -18,7 +18,7 @@ or anything that violates the specifications.
|
||||
<!--- Provide a general summary of the issue in the title above -->
|
||||
|
||||
<!---
|
||||
If you aren't sure what Swagger-UI version, see this guide: https://github.com/swagger-api/swagger-ui/blob/master/docs/version-detection.md
|
||||
If you aren't sure what Swagger-UI version, see this guide: https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/version-detection.md
|
||||
--->
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
!package.json
|
||||
!dist/swagger-ui.js
|
||||
!dist/swagger-ui.js.map
|
||||
!dist/swagger-ui-standalone-preset.js
|
||||
!dist/swagger-ui-standalone-preset.js.map
|
||||
!dist/swagger-ui.css
|
||||
!dist/swagger-ui.css.map
|
||||
!dist/oauth2-redirect.html
|
||||
|
||||
@@ -52,3 +52,7 @@ _Adapted from [How to Write a Git Commit Message](https://chris.beams.io/posts/g
|
||||
- **Don't** include any changes to files in the `dist/` directory - we update those files only during releases.
|
||||
- **Don't** mention maintainers in your original PR body - we probably would've seen it anyway, so it just increases the noise in our inboxes. Do feel free to ping maintainers if a week has passed and you've heard nothing from us.
|
||||
- **Don't** open PRs for custom functionality that only serves a small subset of our users - custom functionality should be implemented outside of our codebase, via a plugin.
|
||||
|
||||
#### Merging pull requests
|
||||
- **Do** use GitHub's `Squash and merge` strategy.
|
||||
- **Do** follow the [Conventional Commits](https://conventionalcommits.org) standard format for your squash commit.
|
||||
|
||||
@@ -12,7 +12,7 @@ ENV OAUTH_REALM "**None**"
|
||||
ENV OAUTH_APP_NAME "**None**"
|
||||
ENV OAUTH_ADDITIONAL_PARAMS "**None**"
|
||||
ENV SWAGGER_JSON "/app/swagger.json"
|
||||
ENV PORT 80
|
||||
ENV PORT 8080
|
||||
ENV BASE_URL ""
|
||||
|
||||
RUN apk add --update nginx
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright 2017 SmartBear Software
|
||||
Copyright 2018 SmartBear Software
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -22,7 +22,7 @@ The OpenAPI Specification has undergone 5 revisions since initial creation in 20
|
||||
|
||||
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes
|
||||
------------------ | ------------ | -------------------------- | -----
|
||||
3.8.0 | 2017-12-15 | 2.0, 3.0 | [tag v3.8.0](https://github.com/swagger-api/swagger-ui/tree/v3.8.0)
|
||||
3.9.1 | 2018-01-12 | 2.0, 3.0 | [tag v3.9.1](https://github.com/swagger-api/swagger-ui/tree/v3.9.1)
|
||||
3.0.21 | 2017-07-26 | 2.0 | [tag v3.0.21](https://github.com/swagger-api/swagger-ui/tree/v3.0.21)
|
||||
2.2.10 | 2017-01-04 | 1.1, 1.2, 2.0 | [tag v2.2.10](https://github.com/swagger-api/swagger-ui/tree/v2.2.10)
|
||||
2.1.5 | 2016-07-20 | 1.1, 1.2, 2.0 | [tag v2.1.5](https://github.com/swagger-api/swagger-ui/tree/v2.1.5)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
set -e
|
||||
|
||||
BASE_URL=${BASE_URL:-/}
|
||||
NGINX_ROOT=/usr/share/nginx/html
|
||||
INDEX_FILE=$NGINX_ROOT/index.html
|
||||
|
||||
@@ -22,13 +23,7 @@ replace_or_delete_in_index () {
|
||||
}
|
||||
|
||||
if [ "${BASE_URL}" ]; then
|
||||
NGINX_WITH_BASE_URL="${NGINX_ROOT}${BASE_URL}"
|
||||
|
||||
mkdir -p ${NGINX_WITH_BASE_URL}
|
||||
mv ${NGINX_ROOT}/*.* ${NGINX_WITH_BASE_URL}/
|
||||
|
||||
INDEX_FILE=$NGINX_WITH_BASE_URL/index.html
|
||||
NGINX_ROOT=$NGINX_WITH_BASE_URL
|
||||
sed -i "s|location .* {|location $BASE_URL {|g" /etc/nginx/nginx.conf
|
||||
fi
|
||||
|
||||
replace_in_index myApiKeyXXXX123456789 $API_KEY
|
||||
@@ -41,7 +36,7 @@ if [ "$OAUTH_ADDITIONAL_PARAMS" != "**None**" ]; then
|
||||
fi
|
||||
|
||||
if [[ -f $SWAGGER_JSON ]]; then
|
||||
cp $SWAGGER_JSON $NGINX_ROOT
|
||||
cp -s $SWAGGER_JSON $NGINX_ROOT
|
||||
REL_PATH="./$(basename $SWAGGER_JSON)"
|
||||
sed -i "s|http://petstore.swagger.io/v2/swagger.json|$REL_PATH|g" $INDEX_FILE
|
||||
sed -i "s|http://example.com/api|$REL_PATH|g" $INDEX_FILE
|
||||
@@ -58,4 +53,7 @@ if [[ -n "$VALIDATOR_URL" ]]; then
|
||||
unset TMP_VU
|
||||
fi
|
||||
|
||||
# replace the PORT that nginx listens on if supplied
|
||||
if [[ -n "${PORT}" ]]; then sed -i "s|8080|${PORT}|g" /etc/nginx/nginx.conf; fi
|
||||
|
||||
exec nginx -g 'daemon off;'
|
||||
|
||||
@@ -19,7 +19,8 @@ A plugin return value may contain any of these keys, where `myStateKey` is a nam
|
||||
},
|
||||
components: {},
|
||||
wrapComponents: {},
|
||||
afterLoad: (system) => {}
|
||||
rootInjects: {},
|
||||
afterLoad: (system) => {},
|
||||
fn: {},
|
||||
}
|
||||
```
|
||||
@@ -364,11 +365,30 @@ const MyWrapComponentPlugin = function(system) {
|
||||
}
|
||||
```
|
||||
|
||||
##### `rootInjects`
|
||||
|
||||
The `rootInjects` interface allows you to inject values at the top level of the system.
|
||||
|
||||
This interface takes an object, which will be merged in with the top-level system object at runtime.
|
||||
|
||||
```js
|
||||
const MyRootInjectsPlugin = function(system) {
|
||||
return {
|
||||
rootInjects: {
|
||||
myConstant: 123,
|
||||
myMethod: (...params) => console.log(...params)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
##### `afterLoad`
|
||||
|
||||
The `afterLoad` plugin method allows you to get a reference to the system after your plugin has been registered with the system.
|
||||
The `afterLoad` plugin method allows you to get a reference to the system after your plugin has been registered.
|
||||
|
||||
This interface is used in the core code to attach methods that are driven by bound selectors or actions directly to the system.
|
||||
This interface is used in the core code to attach methods that are driven by bound selectors or actions. You can also use it to execute logic that requires your plugin to already be ready, for example fetching initial data from a remote endpoint and passing it to an action your plugin creates.
|
||||
|
||||
The plugin context, which is bound to `this`, is undocumented, but below is an example of how to attach a bound action as a top-level method:
|
||||
|
||||
```javascript
|
||||
const MyMethodProvidingPlugin = function() {
|
||||
@@ -376,7 +396,8 @@ const MyMethodProvidingPlugin = function() {
|
||||
afterLoad(system) {
|
||||
// at this point in time, your actions have been bound into the system
|
||||
// so you can do things with them
|
||||
system.myMethod = system.exampleActions.updateFavoriteColor
|
||||
this.rootInjects = this.rootInjects || {}
|
||||
this.rootInjects.myMethod = system.exampleActions.updateFavoriteColor
|
||||
},
|
||||
statePlugins: {
|
||||
example: {
|
||||
|
||||
|
Before Width: | Height: | Size: 390 KiB After Width: | Height: | Size: 168 KiB |
|
Before Width: | Height: | Size: 297 KiB After Width: | Height: | Size: 126 KiB |
@@ -37,7 +37,7 @@ app.listen(3000)
|
||||
```
|
||||
|
||||
The module also exports `SwaggerUIBundle` and `SwaggerUIStandalonePreset`, so
|
||||
if you're in a JavaScript project that can't handle a tranditional npm module,
|
||||
if you're in a JavaScript project that can't handle a traditional npm module,
|
||||
you could do something like this:
|
||||
|
||||
```js
|
||||
|
||||
@@ -15,10 +15,11 @@ http {
|
||||
server {
|
||||
listen 8080;
|
||||
server_name localhost;
|
||||
index index.html index.htm;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
alias /usr/share/nginx/html/;
|
||||
|
||||
if ($request_method = 'OPTIONS') {
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "swagger-ui",
|
||||
"version": "3.8.0",
|
||||
"version": "3.9.1",
|
||||
"main": "dist/swagger-ui.js",
|
||||
"repository": "git@github.com:swagger-api/swagger-ui.git",
|
||||
"contributors": [
|
||||
@@ -67,6 +67,7 @@
|
||||
"react-height": "^2.0.0",
|
||||
"react-hot-loader": "1.3.1",
|
||||
"react-immutable-proptypes": "2.1.0",
|
||||
"react-immutable-pure-component": "^1.1.1",
|
||||
"react-markdown": "^2.5.0",
|
||||
"react-motion": "^0.5.2",
|
||||
"react-object-inspector": "0.2.1",
|
||||
@@ -81,7 +82,7 @@
|
||||
"scroll-to-element": "^2.0.0",
|
||||
"serialize-error": "2.0.0",
|
||||
"shallowequal": "0.2.2",
|
||||
"swagger-client": "^3.4.2",
|
||||
"swagger-client": "^3.4.5",
|
||||
"url-parse": "^1.1.8",
|
||||
"whatwg-fetch": "0.11.1",
|
||||
"worker-loader": "^0.7.1",
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -57,6 +57,9 @@ export class Col extends React.Component {
|
||||
let classesAr = []
|
||||
|
||||
for (let device in DEVICES) {
|
||||
if (!DEVICES.hasOwnProperty(device)) {
|
||||
continue
|
||||
}
|
||||
let deviceClass = DEVICES[device]
|
||||
if(device in this.props) {
|
||||
let val = this.props[device]
|
||||
|
||||
@@ -8,13 +8,14 @@ export default class ModelCollapse extends Component {
|
||||
children: PropTypes.any,
|
||||
title: PropTypes.element,
|
||||
modelName: PropTypes.string,
|
||||
onToggle: PropTypes.func.isRequired
|
||||
onToggle: PropTypes.func
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
collapsedContent: "{...}",
|
||||
expanded: false,
|
||||
title: null
|
||||
title: null,
|
||||
onToggle: () => {}
|
||||
}
|
||||
|
||||
constructor(props, context) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 )=> {
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 = "}"
|
||||
@@ -11,13 +12,13 @@ export default class ObjectModel extends Component {
|
||||
getComponent: PropTypes.func.isRequired,
|
||||
getConfigs: PropTypes.func.isRequired,
|
||||
expanded: PropTypes.bool,
|
||||
onToggle: PropTypes.func.isRequired,
|
||||
onToggle: PropTypes.func,
|
||||
specSelectors: PropTypes.object.isRequired,
|
||||
name: PropTypes.string,
|
||||
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 } />
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
@@ -107,6 +108,34 @@ export default class ParameterRow extends Component {
|
||||
let value = parameter ? parameter.get("value") : ""
|
||||
let extensions = getExtensions(param)
|
||||
|
||||
|
||||
let paramItems // undefined
|
||||
let paramItemsEnum // undefined
|
||||
let isDisplayParamItemsEnum = false
|
||||
if ( param !== undefined ) {
|
||||
paramItems = param.get("items")
|
||||
}
|
||||
if ( paramItems !== undefined ) {
|
||||
paramItemsEnum = param.get("items").get("enum")
|
||||
}
|
||||
if ( paramItemsEnum !== undefined ) {
|
||||
if (paramItemsEnum.size > 0) {
|
||||
isDisplayParamItemsEnum = true
|
||||
}
|
||||
}
|
||||
|
||||
// Default and Example Value for readonly doc
|
||||
let paramDefaultValue // undefined
|
||||
let paramExample // undefined
|
||||
if ( param !== undefined ) {
|
||||
paramDefaultValue = param.get("default")
|
||||
paramExample = param.get("example")
|
||||
}
|
||||
|
||||
if (isDisplayParamItemsEnum) { // if we have an array, default value is in "items"
|
||||
paramDefaultValue = paramItems.get("default")
|
||||
}
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td className="col parameters-col_name">
|
||||
@@ -124,6 +153,25 @@ export default class ParameterRow extends Component {
|
||||
|
||||
<td className="col parameters-col_description">
|
||||
<Markdown source={ param.get("description") }/>
|
||||
|
||||
{ (bodyParam || !isExecute) && isDisplayParamItemsEnum ?
|
||||
<Markdown source={
|
||||
"<i>Available values</i> : " + paramItemsEnum.map(function(item) {
|
||||
return item
|
||||
}).toArray()}/>
|
||||
: null
|
||||
}
|
||||
|
||||
{ (bodyParam || !isExecute) && paramDefaultValue !== undefined ?
|
||||
<Markdown source={"<i>Default value</i> : " + paramDefaultValue}/>
|
||||
: null
|
||||
}
|
||||
|
||||
{ (bodyParam || !isExecute) && paramExample !== undefined ?
|
||||
<Markdown source={"<i>Example</i> : " + paramExample}/>
|
||||
: null
|
||||
}
|
||||
|
||||
{(isFormData && !isFormDataSupported) && <div>Error: your browser does not support FormData</div>}
|
||||
|
||||
{ bodyParam || !isExecute ? null
|
||||
@@ -139,7 +187,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 }
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import formatXml from "xml-but-prettier"
|
||||
import lowerCase from "lodash/lowerCase"
|
||||
import { extractFileNameFromContentDispositionHeader } from "core/utils"
|
||||
|
||||
export default class ResponseBody extends React.Component {
|
||||
|
||||
@@ -70,12 +71,13 @@ export default class ResponseBody extends React.Component {
|
||||
let fileName = url.substr(url.lastIndexOf("/") + 1)
|
||||
let download = [type, fileName, href].join(":")
|
||||
|
||||
// Use filename from response header
|
||||
// Use filename from response header,
|
||||
// First check if filename is quoted (e.g. contains space), if no, fallback to not quoted check
|
||||
let disposition = headers["content-disposition"] || headers["Content-Disposition"]
|
||||
if (typeof disposition !== "undefined") {
|
||||
let responseFilename = /filename=([^;]*);?/i.exec(disposition)
|
||||
if (responseFilename !== null && responseFilename.length > 1) {
|
||||
download = responseFilename[1]
|
||||
let responseFilename = extractFileNameFromContentDispositionHeader(disposition)
|
||||
if (responseFilename !== null) {
|
||||
download = responseFilename
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -6,7 +6,8 @@ import * as specWrapActionReplacements from "./spec-wrap-actions"
|
||||
export default function() {
|
||||
return {
|
||||
afterLoad(system) {
|
||||
system.initOAuth = system.authActions.configureAuth
|
||||
this.rootInjects = this.rootInjects || {}
|
||||
this.rootInjects.initOAuth = system.authActions.configureAuth
|
||||
},
|
||||
statePlugins: {
|
||||
auth: {
|
||||
|
||||
@@ -26,7 +26,7 @@ export default function downloadUrlPlugin (toolbox) {
|
||||
function next(res) {
|
||||
if(res instanceof Error || res.status >= 400) {
|
||||
specActions.updateLoadingStatus("failed")
|
||||
return errActions.newThrownErr( new Error(res.statusText + " " + url) )
|
||||
return errActions.newThrownErr( new Error((res.message || res.statusText) + " " + url) )
|
||||
}
|
||||
specActions.updateLoadingStatus("success")
|
||||
specActions.updateSpec(res.text)
|
||||
|
||||
@@ -7,10 +7,10 @@ export const NEW_SPEC_ERR_BATCH = "err_new_spec_err_batch"
|
||||
export const NEW_AUTH_ERR = "err_new_auth_err"
|
||||
export const CLEAR = "err_clear"
|
||||
|
||||
export function newThrownErr(err, action) {
|
||||
export function newThrownErr(err) {
|
||||
return {
|
||||
type: NEW_THROWN_ERR,
|
||||
payload: { action, error: serializeError(err) }
|
||||
payload: serializeError(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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" ) }
|
||||
|
||||
@@ -181,6 +181,9 @@ export const sampleXmlFromSchema = (schema, config={}) => {
|
||||
example = example || {}
|
||||
|
||||
for (let propName in props) {
|
||||
if (!props.hasOwnProperty(propName)) {
|
||||
continue
|
||||
}
|
||||
if ( props[propName].readOnly && !includeReadOnly ) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ function createStoreWithMiddleware(rootReducer, initialState, getSystem) {
|
||||
// createLogger( {
|
||||
// stateTransformer: state => state && state.toJS()
|
||||
// } ),
|
||||
// errorLog(getSystem), Need to properly handle errors that occur during a render. Ie: let them be...
|
||||
systemThunkMiddleware( getSystem )
|
||||
]
|
||||
|
||||
@@ -68,13 +67,11 @@ export default class Store {
|
||||
if(rebuild) {
|
||||
this.buildSystem()
|
||||
}
|
||||
|
||||
if(Array.isArray(plugins)) {
|
||||
plugins.forEach(plugin => {
|
||||
if(plugin.afterLoad) {
|
||||
plugin.afterLoad(this.getSystem())
|
||||
}
|
||||
})
|
||||
|
||||
const needAnotherRebuild = callAfterLoad.call(this.system, plugins, this.getSystem())
|
||||
|
||||
if(needAnotherRebuild) {
|
||||
this.buildSystem()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +175,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)
|
||||
})
|
||||
}
|
||||
@@ -258,11 +255,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
|
||||
}
|
||||
@@ -328,6 +325,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
|
||||
@@ -419,14 +435,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)
|
||||
|
||||
|
||||
@@ -126,15 +126,6 @@ export function systemThunkMiddleware(getSystem) {
|
||||
}
|
||||
}
|
||||
|
||||
export const errorLog = getSystem => () => next => action => {
|
||||
try{
|
||||
next( action )
|
||||
}
|
||||
catch( e ) {
|
||||
getSystem().errActions.newThrownErr( e, action )
|
||||
}
|
||||
}
|
||||
|
||||
export function defaultStatusCode ( responses ) {
|
||||
let codes = responses.keySeq()
|
||||
return codes.contains(DEFAULT_REPONSE_KEY) ? DEFAULT_REPONSE_KEY : codes.filter( key => (key+"")[0] === "2").sort().first()
|
||||
@@ -351,6 +342,17 @@ export function mapToList(map, keyNames="key", collectedKeys=Im.Map()) {
|
||||
return list
|
||||
}
|
||||
|
||||
export function extractFileNameFromContentDispositionHeader(value){
|
||||
let responseFilename = /filename="([^;]*);?"/i.exec(value)
|
||||
if (responseFilename === null) {
|
||||
responseFilename = /filename=([^;]*);?/i.exec(value)
|
||||
}
|
||||
if (responseFilename !== null && responseFilename.length > 1) {
|
||||
return responseFilename[1]
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// PascalCase, aka UpperCamelCase
|
||||
export function pascalCase(str) {
|
||||
return upperFirst(camelCase(str))
|
||||
@@ -442,6 +444,7 @@ export const validateDateTime = (val) => {
|
||||
}
|
||||
|
||||
export const validateGuid = (val) => {
|
||||
val = val.toString().toLowerCase()
|
||||
if (!/^[{(]?[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}[)}]?$/.test(val)) {
|
||||
return "Value must be a Guid"
|
||||
}
|
||||
@@ -616,6 +619,9 @@ export const parseSearch = () => {
|
||||
let params = search.substr(1).split("&")
|
||||
|
||||
for (let i in params) {
|
||||
if (!params.hasOwnProperty(i)) {
|
||||
continue
|
||||
}
|
||||
i = params[i].split("=")
|
||||
map[decodeURIComponent(i[0])] = decodeURIComponent(i[1])
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 770 B After Width: | Height: | Size: 458 B |
|
Before Width: | Height: | Size: 770 B After Width: | Height: | Size: 458 B |
@@ -1,6 +1,8 @@
|
||||
// Promise global, Used ( at least ) by 'whatwg-fetch'. And required by IE 11
|
||||
|
||||
if(typeof Promise === "undefined") {
|
||||
import win from "core/window"
|
||||
|
||||
if(typeof win.Promise === "undefined") {
|
||||
require("core-js/fn/promise")
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ export default class StandaloneLayout extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
let { getComponent, specSelectors } = this.props
|
||||
let { getComponent, specSelectors, errSelectors } = this.props
|
||||
|
||||
let Container = getComponent("Container")
|
||||
let Row = getComponent("Row")
|
||||
@@ -27,6 +27,8 @@ export default class StandaloneLayout extends React.Component {
|
||||
const OnlineValidatorBadge = getComponent("onlineValidatorBadge", true)
|
||||
|
||||
const loadingStatus = specSelectors.loadingStatus()
|
||||
const lastErr = errSelectors.lastError()
|
||||
const lastErrMsg = lastErr ? lastErr.get("message") : ""
|
||||
|
||||
return (
|
||||
|
||||
@@ -43,12 +45,16 @@ export default class StandaloneLayout extends React.Component {
|
||||
<div className="info">
|
||||
<div className="loading-container">
|
||||
<h4 className="title">Failed to load API definition.</h4>
|
||||
</div>
|
||||
<p>{lastErrMsg}</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
{ loadingStatus === "failedConfig" &&
|
||||
<div className="info" style={{ maxWidth: "880px", marginLeft: "auto", marginRight: "auto", textAlign: "center" }}>
|
||||
<h4 className="title">Failed to load remote configuration.</h4>
|
||||
<div className="loading-container">
|
||||
<h4 className="title">Failed to load remote configuration.</h4>
|
||||
<p>{lastErrMsg}</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
{ !loadingStatus || loadingStatus === "success" && <BaseLayout /> }
|
||||
|
||||
@@ -657,6 +657,8 @@
|
||||
min-height: 1px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
.loading
|
||||
{
|
||||
|
||||
@@ -84,15 +84,6 @@ table
|
||||
|
||||
.parameters-col_description
|
||||
{
|
||||
p
|
||||
{
|
||||
font-size: 14px;
|
||||
|
||||
margin: 0;
|
||||
|
||||
@include text_body();
|
||||
}
|
||||
|
||||
input[type=text]
|
||||
{
|
||||
width: 100%;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from "react"
|
||||
import expect from "expect"
|
||||
import { shallow } from "enzyme"
|
||||
import { fromJS } from "immutable"
|
||||
import { fromJS, List } from "immutable"
|
||||
import ObjectModel from "components/object-model"
|
||||
import ModelExample from "components/model-example"
|
||||
import Immutable from "immutable"
|
||||
@@ -25,7 +25,7 @@ describe("<ObjectModel />", function() {
|
||||
}
|
||||
},
|
||||
isRef : false,
|
||||
specPath: [],
|
||||
specPath: List(),
|
||||
schema: Immutable.fromJS(
|
||||
{
|
||||
"properties": {
|
||||
|
||||
@@ -571,126 +571,16 @@ describe("bound system", function(){
|
||||
// Then
|
||||
expect(renderedComponent.text()).toEqual("This came from mapStateToProps and this came from the system and this came from my own props")
|
||||
})
|
||||
|
||||
it("should catch errors thrown inside of React Component Class render methods", function() {
|
||||
// Given
|
||||
// eslint-disable-next-line react/require-render-return
|
||||
class BrokenComponent extends React.Component {
|
||||
render() {
|
||||
throw new Error("This component is broken")
|
||||
}
|
||||
}
|
||||
const system = new System({
|
||||
plugins: [
|
||||
ViewPlugin,
|
||||
{
|
||||
components: {
|
||||
BrokenComponent
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// When
|
||||
var Component = system.getSystem().getComponent("BrokenComponent")
|
||||
const renderedComponent = render(<Component />)
|
||||
|
||||
// Then
|
||||
expect(renderedComponent.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
|
||||
})
|
||||
|
||||
it("should catch errors thrown inside of pure component render methods", function() {
|
||||
// Given
|
||||
// eslint-disable-next-line react/require-render-return
|
||||
class BrokenComponent extends PureComponent {
|
||||
render() {
|
||||
throw new Error("This component is broken")
|
||||
}
|
||||
}
|
||||
|
||||
const system = new System({
|
||||
plugins: [
|
||||
ViewPlugin,
|
||||
{
|
||||
components: {
|
||||
BrokenComponent
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// When
|
||||
var Component = system.getSystem().getComponent("BrokenComponent")
|
||||
const renderedComponent = render(<Component />)
|
||||
|
||||
// Then
|
||||
expect(renderedComponent.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
|
||||
})
|
||||
|
||||
it("should catch errors thrown inside of stateless component functions", function() {
|
||||
// Given
|
||||
// eslint-disable-next-line react/require-render-return
|
||||
let BrokenComponent = function BrokenComponent() { throw new Error("This component is broken") }
|
||||
const system = new System({
|
||||
plugins: [
|
||||
ViewPlugin,
|
||||
{
|
||||
components: {
|
||||
BrokenComponent
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// When
|
||||
var Component = system.getSystem().getComponent("BrokenComponent")
|
||||
const renderedComponent = render(<Component />)
|
||||
|
||||
// Then
|
||||
expect(renderedComponent.text().startsWith("😱 Could not render")).toEqual(true)
|
||||
})
|
||||
|
||||
it("should catch errors thrown inside of container components", function() {
|
||||
// Given
|
||||
// eslint-disable-next-line react/require-render-return
|
||||
class BrokenComponent extends React.Component {
|
||||
render() {
|
||||
throw new Error("This component is broken")
|
||||
}
|
||||
}
|
||||
|
||||
const system = new System({
|
||||
plugins: [
|
||||
ViewPlugin,
|
||||
{
|
||||
components: {
|
||||
BrokenComponent
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// When
|
||||
var Component = system.getSystem().getComponent("BrokenComponent", true)
|
||||
const renderedComponent = render(
|
||||
<Provider store={system.getStore()}>
|
||||
<Component />
|
||||
</Provider>
|
||||
)
|
||||
|
||||
// Then
|
||||
expect(renderedComponent.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
|
||||
})
|
||||
})
|
||||
|
||||
describe("afterLoad", function() {
|
||||
it("should call an plugin's `afterLoad` method after the plugin is loaded", function() {
|
||||
it("should call a plugin's `afterLoad` method after the plugin is loaded", function() {
|
||||
// Given
|
||||
const system = new System({
|
||||
plugins: [
|
||||
{
|
||||
afterLoad(system) {
|
||||
system.wow = system.dogeSelectors.wow
|
||||
this.rootInjects.wow = system.dogeSelectors.wow
|
||||
},
|
||||
statePlugins: {
|
||||
doge: {
|
||||
@@ -709,5 +599,383 @@ describe("bound system", function(){
|
||||
var res = system.getSystem().wow()
|
||||
expect(res).toEqual("so selective")
|
||||
})
|
||||
it("should call a preset plugin's `afterLoad` method after the plugin is loaded", function() {
|
||||
// Given
|
||||
const MyPlugin = {
|
||||
afterLoad(system) {
|
||||
this.rootInjects.wow = system.dogeSelectors.wow
|
||||
},
|
||||
statePlugins: {
|
||||
doge: {
|
||||
selectors: {
|
||||
wow: () => (system) => {
|
||||
return "so selective"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const system = new System({
|
||||
plugins: [
|
||||
[MyPlugin]
|
||||
]
|
||||
})
|
||||
|
||||
// When
|
||||
var res = system.getSystem().wow()
|
||||
expect(res).toEqual("so selective")
|
||||
})
|
||||
it("should call a function preset plugin's `afterLoad` method after the plugin is loaded", function() {
|
||||
// Given
|
||||
const MyPlugin = {
|
||||
afterLoad(system) {
|
||||
this.rootInjects.wow = system.dogeSelectors.wow
|
||||
},
|
||||
statePlugins: {
|
||||
doge: {
|
||||
selectors: {
|
||||
wow: () => (system) => {
|
||||
return "so selective"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const system = new System({
|
||||
plugins: [
|
||||
() => {
|
||||
return [MyPlugin]
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// When
|
||||
var res = system.getSystem().wow()
|
||||
expect(res).toEqual("so selective")
|
||||
})
|
||||
it("should call a registered plugin's `afterLoad` method after the plugin is loaded", function() {
|
||||
// Given
|
||||
const MyPlugin = {
|
||||
afterLoad(system) {
|
||||
this.rootInjects.wow = system.dogeSelectors.wow
|
||||
},
|
||||
statePlugins: {
|
||||
doge: {
|
||||
selectors: {
|
||||
wow: () => (system) => {
|
||||
return "so selective"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const system = new System({
|
||||
plugins: []
|
||||
})
|
||||
|
||||
system.register([MyPlugin])
|
||||
|
||||
// When
|
||||
var res = system.getSystem().wow()
|
||||
expect(res).toEqual("so selective")
|
||||
})
|
||||
})
|
||||
|
||||
describe("error catching", function() {
|
||||
it("should encapsulate thrown errors in an afterLoad method", function() {
|
||||
// Given
|
||||
const ThrowyPlugin = {
|
||||
afterLoad(system) {
|
||||
throw new Error("afterLoad BREAKS STUFF!")
|
||||
},
|
||||
statePlugins: {
|
||||
doge: {
|
||||
selectors: {
|
||||
wow: () => (system) => {
|
||||
return "so selective"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const system = new System({
|
||||
plugins: []
|
||||
})
|
||||
|
||||
|
||||
// When
|
||||
expect(function() {
|
||||
system.register([ThrowyPlugin])
|
||||
// var resSystem = system.getSystem()
|
||||
}).toNotThrow()
|
||||
})
|
||||
|
||||
it("should encapsulate thrown errors in an action creator", function(){
|
||||
|
||||
// Given
|
||||
const system = new System({
|
||||
plugins: {
|
||||
statePlugins: {
|
||||
throw: {
|
||||
actions: {
|
||||
func() {
|
||||
throw new Error("this action creator THROWS!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
expect(function() {
|
||||
// TODO: fix existing action error catcher that creates THROWN ERR actions
|
||||
system.getSystem().throwActions.func()
|
||||
}).toNotThrow()
|
||||
})
|
||||
|
||||
it("should encapsulate thrown errors in a reducer", function(){
|
||||
|
||||
// Given
|
||||
const system = new System({
|
||||
plugins: {
|
||||
statePlugins: {
|
||||
throw: {
|
||||
actions: {
|
||||
func: () => {
|
||||
return {
|
||||
type: "THROW_FUNC",
|
||||
payload: "BOOM!"
|
||||
}
|
||||
}
|
||||
},
|
||||
reducers: {
|
||||
"THROW_FUNC": (state, action) => {
|
||||
throw new Error("this reducer EXPLODES!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
expect(function() {
|
||||
system.getSystem().throwActions.func()
|
||||
}).toNotThrow()
|
||||
})
|
||||
|
||||
it("should encapsulate thrown errors in a selector", function(){
|
||||
|
||||
// Given
|
||||
const system = new System({
|
||||
plugins: {
|
||||
statePlugins: {
|
||||
throw: {
|
||||
selectors: {
|
||||
func: (state, arg1) => {
|
||||
throw new Error("this selector THROWS!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
expect(system.getSystem().throwSelectors.func).toNotThrow()
|
||||
})
|
||||
|
||||
it("should encapsulate thrown errors in a complex selector", function(){
|
||||
|
||||
// Given
|
||||
const system = new System({
|
||||
plugins: {
|
||||
statePlugins: {
|
||||
throw: {
|
||||
selectors: {
|
||||
func: (state, arg1) => system => {
|
||||
throw new Error("this selector THROWS!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
expect(system.getSystem().throwSelectors.func).toNotThrow()
|
||||
})
|
||||
|
||||
it("should encapsulate thrown errors in a wrapAction", function(){
|
||||
|
||||
// Given
|
||||
const system = new System({
|
||||
plugins: {
|
||||
statePlugins: {
|
||||
throw: {
|
||||
actions: {
|
||||
func: () => {
|
||||
return {
|
||||
type: "THROW_FUNC",
|
||||
payload: "this original action does NOT throw"
|
||||
}
|
||||
}
|
||||
},
|
||||
wrapActions: {
|
||||
func: (ori) => (...args) => {
|
||||
throw new Error("this wrapAction UNRAVELS EVERYTHING!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
expect(system.getSystem().throwActions.func).toNotThrow()
|
||||
})
|
||||
|
||||
it("should encapsulate thrown errors in a wrapSelector", function(){
|
||||
|
||||
// Given
|
||||
const system = new System({
|
||||
plugins: {
|
||||
statePlugins: {
|
||||
throw: {
|
||||
selectors: {
|
||||
func: (state, arg1) => {
|
||||
return 123
|
||||
}
|
||||
},
|
||||
wrapSelectors: {
|
||||
func: (ori) => (...props) => {
|
||||
return ori(...props)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
expect(system.getSystem().throwSelectors.func).toNotThrow()
|
||||
})
|
||||
|
||||
describe("components", function() {
|
||||
it("should catch errors thrown inside of React Component Class render methods", function() {
|
||||
// Given
|
||||
// eslint-disable-next-line react/require-render-return
|
||||
class BrokenComponent extends React.Component {
|
||||
render() {
|
||||
throw new Error("This component is broken")
|
||||
}
|
||||
}
|
||||
const system = new System({
|
||||
plugins: [
|
||||
ViewPlugin,
|
||||
{
|
||||
components: {
|
||||
BrokenComponent
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// When
|
||||
var Component = system.getSystem().getComponent("BrokenComponent")
|
||||
const renderedComponent = render(<Component />)
|
||||
|
||||
// Then
|
||||
expect(renderedComponent.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
|
||||
})
|
||||
|
||||
it("should catch errors thrown inside of pure component render methods", function() {
|
||||
// Given
|
||||
// eslint-disable-next-line react/require-render-return
|
||||
class BrokenComponent extends PureComponent {
|
||||
render() {
|
||||
throw new Error("This component is broken")
|
||||
}
|
||||
}
|
||||
|
||||
const system = new System({
|
||||
plugins: [
|
||||
ViewPlugin,
|
||||
{
|
||||
components: {
|
||||
BrokenComponent
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// When
|
||||
var Component = system.getSystem().getComponent("BrokenComponent")
|
||||
const renderedComponent = render(<Component />)
|
||||
|
||||
// Then
|
||||
expect(renderedComponent.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
|
||||
})
|
||||
|
||||
it("should catch errors thrown inside of stateless component functions", function() {
|
||||
// Given
|
||||
// eslint-disable-next-line react/require-render-return
|
||||
let BrokenComponent = function BrokenComponent() { throw new Error("This component is broken") }
|
||||
const system = new System({
|
||||
plugins: [
|
||||
ViewPlugin,
|
||||
{
|
||||
components: {
|
||||
BrokenComponent
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// When
|
||||
var Component = system.getSystem().getComponent("BrokenComponent")
|
||||
const renderedComponent = render(<Component />)
|
||||
|
||||
// Then
|
||||
expect(renderedComponent.text().startsWith("😱 Could not render")).toEqual(true)
|
||||
})
|
||||
|
||||
it("should catch errors thrown inside of container components", function() {
|
||||
// Given
|
||||
// eslint-disable-next-line react/require-render-return
|
||||
class BrokenComponent extends React.Component {
|
||||
render() {
|
||||
throw new Error("This component is broken")
|
||||
}
|
||||
}
|
||||
|
||||
const system = new System({
|
||||
plugins: [
|
||||
ViewPlugin,
|
||||
{
|
||||
components: {
|
||||
BrokenComponent
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// When
|
||||
var Component = system.getSystem().getComponent("BrokenComponent", true)
|
||||
const renderedComponent = render(
|
||||
<Provider store={system.getStore()}>
|
||||
<Component />
|
||||
</Provider>
|
||||
)
|
||||
|
||||
// Then
|
||||
expect(renderedComponent.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -18,7 +18,8 @@ import {
|
||||
getAcceptControllingResponse,
|
||||
createDeepLinkPath,
|
||||
escapeDeepLinkPath,
|
||||
sanitizeUrl
|
||||
sanitizeUrl,
|
||||
extractFileNameFromContentDispositionHeader
|
||||
} from "core/utils"
|
||||
import win from "core/window"
|
||||
|
||||
@@ -90,6 +91,26 @@ describe("utils", function() {
|
||||
|
||||
})
|
||||
|
||||
describe("extractFileNameFromContentDispositionHeader", function(){
|
||||
it("should extract quoted filename", function(){
|
||||
let cdHeader = "attachment; filename=\"file name.jpg\""
|
||||
let expectedResult = "file name.jpg"
|
||||
expect(extractFileNameFromContentDispositionHeader(cdHeader)).toEqual(expectedResult)
|
||||
})
|
||||
|
||||
it("should extract filename", function(){
|
||||
let cdHeader = "attachment; filename=filename.jpg"
|
||||
let expectedResult = "filename.jpg"
|
||||
expect(extractFileNameFromContentDispositionHeader(cdHeader)).toEqual(expectedResult)
|
||||
})
|
||||
|
||||
it("should not extract filename and return null", function(){
|
||||
let cdHeader = "attachment; no file name provided"
|
||||
let expectedResult = null
|
||||
expect(extractFileNameFromContentDispositionHeader(cdHeader)).toEqual(expectedResult)
|
||||
})
|
||||
})
|
||||
|
||||
describe("validateMaximum", function() {
|
||||
let errorMessage = "Value must be less than Maximum"
|
||||
|
||||
@@ -238,6 +259,7 @@ describe("utils", function() {
|
||||
it("doesn't return for valid guid", function() {
|
||||
expect(validateGuid("8ce4811e-cec5-4a29-891a-15d1917153c1")).toBeFalsy()
|
||||
expect(validateGuid("{8ce4811e-cec5-4a29-891a-15d1917153c1}")).toBeFalsy()
|
||||
expect(validateGuid("8CE4811E-CEC5-4A29-891A-15D1917153C1")).toBeFalsy()
|
||||
})
|
||||
|
||||
it("returns a message for invalid input'", function() {
|
||||
|
||||
@@ -67,6 +67,7 @@ module.exports = require("./make-webpack-config")(rules, {
|
||||
publicPath: "/",
|
||||
noInfo: true,
|
||||
hot: true,
|
||||
disableHostCheck: true, // for development within VMs
|
||||
stats: {
|
||||
colors: true
|
||||
},
|
||||
|
||||