Merge branch 'master' into feature/2926-click-model-name-to-toggle
This commit is contained in:
@@ -13,8 +13,13 @@ export default class BaseLayout extends React.Component {
|
||||
getComponent: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
onFilterChange =(e) => {
|
||||
let {target: {value}} = e
|
||||
this.props.layoutActions.updateFilter(value)
|
||||
}
|
||||
|
||||
render() {
|
||||
let { specSelectors, specActions, getComponent } = this.props
|
||||
let { specSelectors, specActions, getComponent, layoutSelectors } = this.props
|
||||
|
||||
let info = specSelectors.info()
|
||||
let url = specSelectors.url()
|
||||
@@ -31,6 +36,15 @@ export default class BaseLayout extends React.Component {
|
||||
let Row = getComponent("Row")
|
||||
let Col = getComponent("Col")
|
||||
let Errors = getComponent("errors", true)
|
||||
|
||||
let isLoading = specSelectors.loadingStatus() === "loading"
|
||||
let isFailed = specSelectors.loadingStatus() === "failed"
|
||||
let filter = layoutSelectors.currentFilter()
|
||||
|
||||
let inputStyle = {}
|
||||
if(isFailed) inputStyle.color = "red"
|
||||
if(isLoading) inputStyle.color = "#aaa"
|
||||
|
||||
const Schemes = getComponent("schemes")
|
||||
|
||||
const isSpecEmpty = !specSelectors.specStr()
|
||||
@@ -57,6 +71,7 @@ export default class BaseLayout extends React.Component {
|
||||
{ schemes && schemes.size ? (
|
||||
<Schemes schemes={ schemes } specActions={ specActions } />
|
||||
) : null }
|
||||
|
||||
{ securityDefinitions ? (
|
||||
<AuthorizeBtn />
|
||||
) : null }
|
||||
@@ -64,6 +79,15 @@ export default class BaseLayout extends React.Component {
|
||||
</div>
|
||||
) : null }
|
||||
|
||||
{
|
||||
filter === null || filter === false ? null :
|
||||
<div className="filter-container">
|
||||
<Col className="filter wrapper" mobile={12}>
|
||||
<input className="operation-filter-input" placeholder="Filter by tag" type="text" onChange={this.onFilterChange} value={filter === true || filter === "true" ? "" : filter} disabled={isLoading} style={inputStyle} />
|
||||
</Col>
|
||||
</div>
|
||||
}
|
||||
|
||||
<Row>
|
||||
<Col mobile={12} desktop={12} >
|
||||
<Operations/>
|
||||
|
||||
@@ -116,7 +116,8 @@ export default class Operation extends PureComponent {
|
||||
specActions,
|
||||
specSelectors,
|
||||
authActions,
|
||||
authSelectors
|
||||
authSelectors,
|
||||
getConfigs
|
||||
} = this.props
|
||||
|
||||
let summary = operation.get("summary")
|
||||
@@ -141,6 +142,10 @@ export default class Operation extends PureComponent {
|
||||
const Markdown = getComponent( "Markdown" )
|
||||
const Schemes = getComponent( "schemes" )
|
||||
|
||||
const { deepLinking } = getConfigs()
|
||||
|
||||
const isDeepLinkingEnabled = deepLinking && deepLinking !== "false"
|
||||
|
||||
// Merge in Live Response
|
||||
if(response && response.size > 0) {
|
||||
let notDocumented = !responses.get(String(response.get("status")))
|
||||
@@ -152,13 +157,18 @@ export default class Operation extends PureComponent {
|
||||
let onChangeKey = [ path, method ] // Used to add values to _this_ operation ( indexed by path and method )
|
||||
|
||||
return (
|
||||
<div className={deprecated ? "opblock opblock-deprecated" : shown ? `opblock opblock-${method} is-open` : `opblock opblock-${method}`} id={isShownKey} >
|
||||
<div className={deprecated ? "opblock opblock-deprecated" : shown ? `opblock opblock-${method} is-open` : `opblock opblock-${method}`} id={isShownKey.join("-")} >
|
||||
<div className={`opblock-summary opblock-summary-${method}`} onClick={this.toggleShown} >
|
||||
<span className="opblock-summary-method">{method.toUpperCase()}</span>
|
||||
<span className={ deprecated ? "opblock-summary-path__deprecated" : "opblock-summary-path" } >
|
||||
<span>{path}</span>
|
||||
<JumpToPath path={jumpToKey} />
|
||||
</span>
|
||||
<span className="opblock-summary-method">{method.toUpperCase()}</span>
|
||||
<span className={ deprecated ? "opblock-summary-path__deprecated" : "opblock-summary-path" } >
|
||||
<a
|
||||
className="nostyle"
|
||||
onClick={(e) => e.preventDefault()}
|
||||
href={ isDeepLinkingEnabled ? `#/${isShownKey[1]}/${isShownKey[2]}` : ""} >
|
||||
<span>{path}</span>
|
||||
</a>
|
||||
<JumpToPath path={jumpToKey} />
|
||||
</span>
|
||||
|
||||
{ !showSummary ? null :
|
||||
<div className="opblock-summary-description">
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import { helpers } from "swagger-client"
|
||||
|
||||
const { opId } = helpers
|
||||
|
||||
export default class Operations extends React.Component {
|
||||
|
||||
@@ -33,7 +36,29 @@ export default class Operations extends React.Component {
|
||||
const Collapse = getComponent("Collapse")
|
||||
|
||||
let showSummary = layoutSelectors.showSummary()
|
||||
let { docExpansion, displayOperationId, displayRequestDuration } = getConfigs()
|
||||
let {
|
||||
docExpansion,
|
||||
displayOperationId,
|
||||
displayRequestDuration,
|
||||
maxDisplayedTags,
|
||||
deepLinking
|
||||
} = getConfigs()
|
||||
|
||||
const isDeepLinkingEnabled = deepLinking && deepLinking !== "false"
|
||||
|
||||
let filter = layoutSelectors.currentFilter()
|
||||
|
||||
if (filter) {
|
||||
if (filter !== true) {
|
||||
taggedOps = taggedOps.filter((tagObj, tag) => {
|
||||
return tag.indexOf(filter) !== -1
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (maxDisplayedTags && !isNaN(maxDisplayedTags) && maxDisplayedTags >= 0) {
|
||||
taggedOps = taggedOps.slice(0, maxDisplayedTags)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -48,8 +73,16 @@ export default class Operations extends React.Component {
|
||||
return (
|
||||
<div className={showTag ? "opblock-tag-section is-open" : "opblock-tag-section"} key={"operation-" + tag}>
|
||||
|
||||
<h4 onClick={() => layoutActions.show(isShownKey, !showTag)} className={!tagDescription ? "opblock-tag no-desc" : "opblock-tag" }>
|
||||
<span>{tag}</span>
|
||||
<h4
|
||||
onClick={() => layoutActions.show(isShownKey, !showTag)}
|
||||
className={!tagDescription ? "opblock-tag no-desc" : "opblock-tag" }
|
||||
id={isShownKey.join("-")}>
|
||||
<a
|
||||
className="nostyle"
|
||||
onClick={(e) => e.preventDefault()}
|
||||
href={ isDeepLinkingEnabled ? `#/${tag}` : ""}>
|
||||
<span>{tag}</span>
|
||||
</a>
|
||||
{ !tagDescription ? null :
|
||||
<small>
|
||||
{ tagDescription }
|
||||
@@ -67,11 +100,14 @@ export default class Operations extends React.Component {
|
||||
{
|
||||
operations.map( op => {
|
||||
|
||||
const isShownKey = ["operations", op.get("id"), tag]
|
||||
const path = op.get("path", "")
|
||||
const method = op.get("method", "")
|
||||
const jumpToKey = `paths.${path}.${method}`
|
||||
|
||||
const operationId =
|
||||
op.getIn(["operation", "operationId"]) || op.getIn(["operation", "__originalOperationId"]) || opId(op.get("operation"), path, method) || op.get("id")
|
||||
const isShownKey = ["operations", tag, operationId]
|
||||
|
||||
const allowTryItOut = specSelectors.allowTryItOutFor(op.get("path"), op.get("method"))
|
||||
const response = specSelectors.responseFor(op.get("path"), op.get("method"))
|
||||
const request = specSelectors.requestFor(op.get("path"), op.get("method"))
|
||||
|
||||
@@ -18,10 +18,12 @@ function Markdown({ source }) {
|
||||
return null
|
||||
}
|
||||
|
||||
return <Remarkable
|
||||
options={{html: true, typographer: true, linkify: true, linkTarget: "_blank"}}
|
||||
source={sanitized}
|
||||
></Remarkable>
|
||||
return <div className="markdown">
|
||||
<Remarkable
|
||||
options={{html: true, typographer: true, breaks: true, linkify: true, linkTarget: "_blank"}}
|
||||
source={sanitized}
|
||||
></Remarkable>
|
||||
</div>
|
||||
}
|
||||
|
||||
Markdown.propTypes = {
|
||||
|
||||
@@ -6,17 +6,46 @@ import ApisPreset from "core/presets/apis"
|
||||
import * as AllPlugins from "core/plugins/all"
|
||||
import { parseSeach, filterConfigs } from "core/utils"
|
||||
|
||||
const CONFIGS = [ "url", "urls", "urls.primaryName", "spec", "validatorUrl", "onComplete", "onFailure", "authorizations", "docExpansion",
|
||||
"apisSorter", "operationsSorter", "supportedSubmitMethods", "dom_id", "defaultModelRendering", "oauth2RedirectUrl",
|
||||
"showRequestHeaders", "custom", "modelPropertyMacro", "parameterMacro", "displayOperationId" , "displayRequestDuration"]
|
||||
const CONFIGS = [
|
||||
"url",
|
||||
"urls",
|
||||
"urls.primaryName",
|
||||
"spec",
|
||||
"validatorUrl",
|
||||
"onComplete",
|
||||
"onFailure",
|
||||
"authorizations",
|
||||
"docExpansion",
|
||||
"tagsSorter",
|
||||
"maxDisplayedTags",
|
||||
"filter",
|
||||
"operationsSorter",
|
||||
"supportedSubmitMethods",
|
||||
"dom_id",
|
||||
"defaultModelRendering",
|
||||
"oauth2RedirectUrl",
|
||||
"showRequestHeaders",
|
||||
"custom",
|
||||
"modelPropertyMacro",
|
||||
"parameterMacro",
|
||||
"displayOperationId",
|
||||
"displayRequestDuration",
|
||||
"deepLinking",
|
||||
]
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const { GIT_DIRTY, GIT_COMMIT, PACKAGE_VERSION } = buildInfo
|
||||
const { GIT_DIRTY, GIT_COMMIT, PACKAGE_VERSION, HOSTNAME, BUILD_TIME } = buildInfo
|
||||
|
||||
module.exports = function SwaggerUI(opts) {
|
||||
|
||||
win.versions = win.versions || {}
|
||||
win.versions.swaggerUi = `${PACKAGE_VERSION}/${GIT_COMMIT || "unknown"}${GIT_DIRTY ? "-dirty" : ""}`
|
||||
win.versions.swaggerUi = {
|
||||
version: PACKAGE_VERSION,
|
||||
gitRevision: GIT_COMMIT,
|
||||
gitDirty: GIT_DIRTY,
|
||||
buildTimestamp: BUILD_TIME,
|
||||
machine: HOSTNAME
|
||||
}
|
||||
|
||||
const defaults = {
|
||||
// Some general settings, that we floated to the top
|
||||
@@ -26,11 +55,14 @@ module.exports = function SwaggerUI(opts) {
|
||||
urls: null,
|
||||
layout: "BaseLayout",
|
||||
docExpansion: "list",
|
||||
maxDisplayedTags: null,
|
||||
filter: null,
|
||||
validatorUrl: "https://online.swagger.io/validator",
|
||||
configs: {},
|
||||
custom: {},
|
||||
displayOperationId: false,
|
||||
displayRequestDuration: false,
|
||||
deepLinking: false,
|
||||
|
||||
// Initial set of plugins ( TODO rename this, or refactor - we don't need presets _and_ plugins. Its just there for performance.
|
||||
// Instead, we can compile the first plugin ( it can be a collection of plugins ), then batch the rest.
|
||||
@@ -50,7 +82,9 @@ module.exports = function SwaggerUI(opts) {
|
||||
store: { },
|
||||
}
|
||||
|
||||
const constructorConfig = deepExtend({}, defaults, opts)
|
||||
let queryConfig = parseSeach()
|
||||
|
||||
const constructorConfig = deepExtend({}, defaults, opts, queryConfig)
|
||||
|
||||
const storeConfigs = deepExtend({}, constructorConfig.store, {
|
||||
system: {
|
||||
@@ -59,7 +93,8 @@ module.exports = function SwaggerUI(opts) {
|
||||
plugins: constructorConfig.presets,
|
||||
state: {
|
||||
layout: {
|
||||
layout: constructorConfig.layout
|
||||
layout: constructorConfig.layout,
|
||||
filter: constructorConfig.filter
|
||||
},
|
||||
spec: {
|
||||
spec: "",
|
||||
@@ -80,7 +115,6 @@ module.exports = function SwaggerUI(opts) {
|
||||
store.register([constructorConfig.plugins, inlinePlugin])
|
||||
|
||||
var system = store.getSystem()
|
||||
let queryConfig = parseSeach()
|
||||
|
||||
system.initOAuth = system.authActions.configureAuth
|
||||
|
||||
|
||||
1
src/core/plugins/deep-linking/README.md
Normal file
1
src/core/plugins/deep-linking/README.md
Normal file
@@ -0,0 +1 @@
|
||||
See `docs/deep-linking.md`.
|
||||
7
src/core/plugins/deep-linking/helpers.js
Normal file
7
src/core/plugins/deep-linking/helpers.js
Normal file
@@ -0,0 +1,7 @@
|
||||
export const setHash = (value) => {
|
||||
if(value) {
|
||||
return history.pushState(null, null, `#${value}`)
|
||||
} else {
|
||||
return window.location.hash = ""
|
||||
}
|
||||
}
|
||||
18
src/core/plugins/deep-linking/index.js
Normal file
18
src/core/plugins/deep-linking/index.js
Normal file
@@ -0,0 +1,18 @@
|
||||
// import reducers from "./reducers"
|
||||
// import * as actions from "./actions"
|
||||
// import * as selectors from "./selectors"
|
||||
import * as specWrapActions from "./spec-wrap-actions"
|
||||
import * as layoutWrapActions from "./layout-wrap-actions"
|
||||
|
||||
export default function() {
|
||||
return {
|
||||
statePlugins: {
|
||||
spec: {
|
||||
wrapActions: specWrapActions
|
||||
},
|
||||
layout: {
|
||||
wrapActions: layoutWrapActions
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
src/core/plugins/deep-linking/layout-wrap-actions.js
Normal file
36
src/core/plugins/deep-linking/layout-wrap-actions.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import { setHash } from "./helpers"
|
||||
|
||||
export const show = (ori, { getConfigs }) => (...args) => {
|
||||
ori(...args)
|
||||
|
||||
const isDeepLinkingEnabled = getConfigs().deepLinking
|
||||
if(!isDeepLinkingEnabled || isDeepLinkingEnabled === "false") {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
let [thing, shown] = args
|
||||
let [type] = thing
|
||||
|
||||
if(type === "operations-tag" || type === "operations") {
|
||||
if(!shown) {
|
||||
return setHash("/")
|
||||
}
|
||||
|
||||
if(type === "operations") {
|
||||
let [, tag, operationId] = thing
|
||||
setHash(`/${tag}/${operationId}`)
|
||||
}
|
||||
|
||||
if(type === "operations-tag") {
|
||||
let [, tag] = thing
|
||||
setHash(`/${tag}`)
|
||||
}
|
||||
}
|
||||
|
||||
} catch(e) {
|
||||
// This functionality is not mission critical, so if something goes wrong
|
||||
// we'll just move on
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
51
src/core/plugins/deep-linking/spec-wrap-actions.js
Normal file
51
src/core/plugins/deep-linking/spec-wrap-actions.js
Normal file
@@ -0,0 +1,51 @@
|
||||
import scrollTo from "scroll-to-element"
|
||||
|
||||
const SCROLL_OFFSET = -5
|
||||
let hasHashBeenParsed = false
|
||||
|
||||
|
||||
export const updateResolved = (ori, { layoutActions, getConfigs }) => (...args) => {
|
||||
ori(...args)
|
||||
|
||||
const isDeepLinkingEnabled = getConfigs().deepLinking
|
||||
if(!isDeepLinkingEnabled || isDeepLinkingEnabled === "false") {
|
||||
return
|
||||
}
|
||||
|
||||
if(window.location.hash && !hasHashBeenParsed ) {
|
||||
let hash = window.location.hash.slice(1) // # is first character
|
||||
|
||||
if(hash[0] === "!") {
|
||||
// Parse UI 2.x shebangs
|
||||
hash = hash.slice(1)
|
||||
}
|
||||
|
||||
if(hash[0] === "/") {
|
||||
// "/pet/addPet" => "pet/addPet"
|
||||
// makes the split result cleaner
|
||||
// also handles forgotten leading slash
|
||||
hash = hash.slice(1)
|
||||
}
|
||||
|
||||
let [tag, operationId] = hash.split("/")
|
||||
|
||||
if(tag && operationId) {
|
||||
// Pre-expand and scroll to the operation
|
||||
layoutActions.show(["operations-tag", tag], true)
|
||||
layoutActions.show(["operations", tag, operationId], true)
|
||||
|
||||
scrollTo(`#operations-${tag}-${operationId}`, {
|
||||
offset: SCROLL_OFFSET
|
||||
})
|
||||
} else if(tag) {
|
||||
// Pre-expand and scroll to the tag
|
||||
layoutActions.show(["operations-tag", tag], true)
|
||||
|
||||
scrollTo(`#operations-tag-${tag}`, {
|
||||
offset: SCROLL_OFFSET
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
hasHashBeenParsed = true
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { normalizeArray } from "core/utils"
|
||||
|
||||
export const UPDATE_LAYOUT = "layout_update_layout"
|
||||
export const UPDATE_FILTER = "layout_update_filter"
|
||||
export const UPDATE_MODE = "layout_update_mode"
|
||||
export const SHOW = "layout_show"
|
||||
|
||||
@@ -13,6 +14,13 @@ export function updateLayout(layout) {
|
||||
}
|
||||
}
|
||||
|
||||
export function updateFilter(filter) {
|
||||
return {
|
||||
type: UPDATE_FILTER,
|
||||
payload: filter
|
||||
}
|
||||
}
|
||||
|
||||
export function show(thing, shown=true) {
|
||||
thing = normalizeArray(thing)
|
||||
return {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
UPDATE_LAYOUT,
|
||||
UPDATE_FILTER,
|
||||
UPDATE_MODE,
|
||||
SHOW
|
||||
} from "./actions"
|
||||
@@ -8,6 +9,8 @@ export default {
|
||||
|
||||
[UPDATE_LAYOUT]: (state, action) => state.set("layout", action.payload),
|
||||
|
||||
[UPDATE_FILTER]: (state, action) => state.set("filter", action.payload),
|
||||
|
||||
[SHOW]: (state, action) => {
|
||||
let thing = action.payload.thing
|
||||
let shown = action.payload.shown
|
||||
|
||||
@@ -5,6 +5,8 @@ const state = state => state
|
||||
|
||||
export const current = state => state.get("layout")
|
||||
|
||||
export const currentFilter = state => state.get("filter")
|
||||
|
||||
export const isShown = (state, thing, def) => {
|
||||
thing = normalizeArray(thing)
|
||||
return Boolean(state.getIn(["shown", ...thing], def))
|
||||
|
||||
@@ -200,15 +200,22 @@ export const operationsWithTags = createSelector(
|
||||
}
|
||||
)
|
||||
|
||||
export const taggedOperations = ( state ) =>( { getConfigs } ) => {
|
||||
let { operationsSorter }= getConfigs()
|
||||
export const taggedOperations = (state) => ({ getConfigs }) => {
|
||||
let { tagsSorter, operationsSorter } = getConfigs()
|
||||
return operationsWithTags(state)
|
||||
.sortBy(
|
||||
(val, key) => key, // get the name of the tag to be passed to the sorter
|
||||
(tagA, tagB) => {
|
||||
let sortFn = (typeof tagsSorter === "function" ? tagsSorter : sorters.tagsSorter[ tagsSorter ])
|
||||
return (!sortFn ? null : sortFn(tagA, tagB))
|
||||
}
|
||||
)
|
||||
.map((ops, tag) => {
|
||||
let sortFn = (typeof operationsSorter === "function" ? operationsSorter : sorters.operationsSorter[ operationsSorter ])
|
||||
let operations = (!sortFn ? ops : ops.sort(sortFn))
|
||||
|
||||
return operationsWithTags(state).map((ops, tag) => {
|
||||
let sortFn = typeof operationsSorter === "function" ? operationsSorter
|
||||
: sorters.operationsSorter[operationsSorter]
|
||||
let operations = !sortFn ? ops : ops.sort(sortFn)
|
||||
|
||||
return Map({tagDetails: tagDetails(state, tag), operations: operations})})
|
||||
return Map({ tagDetails: tagDetails(state, tag), operations: operations })
|
||||
})
|
||||
}
|
||||
|
||||
export const responses = createSelector(
|
||||
@@ -277,12 +284,13 @@ export function parametersIncludeType(parameters, typeValue="") {
|
||||
export function contentTypeValues(state, pathMethod) {
|
||||
let op = spec(state).getIn(["paths", ...pathMethod], fromJS({}))
|
||||
const parameters = op.get("parameters") || new List()
|
||||
const requestContentType = (
|
||||
parametersIncludeType(parameters, "file") ? "multipart/form-data"
|
||||
: parametersIncludeIn(parameters, "formData") ? "application/x-www-form-urlencoded"
|
||||
: op.get("consumes_value")
|
||||
)
|
||||
|
||||
const requestContentType = (
|
||||
op.get("consumes_value") ? op.get("consumes_value")
|
||||
: parametersIncludeType(parameters, "file") ? "multipart/form-data"
|
||||
: parametersIncludeType(parameters, "formData") ? "application/x-www-form-urlencoded"
|
||||
: undefined
|
||||
)
|
||||
|
||||
return fromJS({
|
||||
requestContentType,
|
||||
|
||||
@@ -10,6 +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 deepLinkingPlugin from "core/plugins/deep-linking"
|
||||
|
||||
import App from "core/components/app"
|
||||
import AuthorizationPopup from "core/components/auth/authorization-popup"
|
||||
@@ -131,6 +132,7 @@ export default function() {
|
||||
auth,
|
||||
ast,
|
||||
SplitPaneModePlugin,
|
||||
downloadUrlPlugin
|
||||
downloadUrlPlugin,
|
||||
deepLinkingPlugin
|
||||
]
|
||||
}
|
||||
|
||||
@@ -228,13 +228,13 @@ export function highlight (el) {
|
||||
|
||||
var reset = function(el) {
|
||||
var text = el.textContent,
|
||||
pos = 0, // current position
|
||||
pos = 0, // current position
|
||||
next1 = text[0], // next character
|
||||
chr = 1, // current character
|
||||
prev1, // previous character
|
||||
prev2, // the one before the previous
|
||||
token = // current token content
|
||||
el.innerHTML = "", // (and cleaning the node)
|
||||
chr = 1, // current character
|
||||
prev1, // previous character
|
||||
prev2, // the one before the previous
|
||||
token = // current token content
|
||||
el.innerHTML = "", // (and cleaning the node)
|
||||
|
||||
// current token type:
|
||||
// 0: anything else (whitespaces / newlines)
|
||||
@@ -274,11 +274,11 @@ export function highlight (el) {
|
||||
(tokenType > 8 && chr == "\n") ||
|
||||
[ // finalize conditions for other token types
|
||||
// 0: whitespaces
|
||||
/\S/[test](chr), // merged together
|
||||
/\S/[test](chr), // merged together
|
||||
// 1: operators
|
||||
1, // consist of a single character
|
||||
1, // consist of a single character
|
||||
// 2: braces
|
||||
1, // consist of a single character
|
||||
1, // consist of a single character
|
||||
// 3: (key)word
|
||||
!/[$\w]/[test](chr),
|
||||
// 4: regex
|
||||
@@ -341,12 +341,12 @@ export function highlight (el) {
|
||||
// condition)
|
||||
tokenType = 11
|
||||
while (![
|
||||
1, // 0: whitespace
|
||||
1, // 0: whitespace
|
||||
// 1: operator or braces
|
||||
/[\/{}[(\-+*=<>:;|\\.,?!&@~]/[test](chr), // eslint-disable-line no-useless-escape
|
||||
/[\])]/[test](chr), // 2: closing brace
|
||||
/[$\w]/[test](chr), // 3: (key)word
|
||||
chr == "/" && // 4: regex
|
||||
/[\/{}[(\-+*=<>:;|\\.,?!&@~]/[test](chr), // eslint-disable-line no-useless-escape
|
||||
/[\])]/[test](chr), // 2: closing brace
|
||||
/[$\w]/[test](chr), // 3: (key)word
|
||||
chr == "/" && // 4: regex
|
||||
// previous token was an
|
||||
// opening brace or an
|
||||
// operator (otherwise
|
||||
@@ -355,13 +355,13 @@ export function highlight (el) {
|
||||
// workaround for xml
|
||||
// closing tags
|
||||
prev1 != "<",
|
||||
chr == "\"", // 5: string with "
|
||||
chr == "'", // 6: string with '
|
||||
chr == "\"", // 5: string with "
|
||||
chr == "'", // 6: string with '
|
||||
// 7: xml comment
|
||||
chr+next1+text[pos+1]+text[pos+2] == "<!--",
|
||||
chr+next1 == "/*", // 8: multiline comment
|
||||
chr+next1 == "//", // 9: single-line comment
|
||||
chr == "#" // 10: hash-style comment
|
||||
chr+next1 == "/*", // 8: multiline comment
|
||||
chr+next1 == "//", // 9: single-line comment
|
||||
chr == "#" // 10: hash-style comment
|
||||
][--tokenType]);
|
||||
}
|
||||
|
||||
@@ -451,13 +451,13 @@ export const propChecker = (props, nextProps, objectList=[], ignoreList=[]) => {
|
||||
}
|
||||
|
||||
export const validateNumber = ( val ) => {
|
||||
if ( !/^-?\d+(\.?\d+)?$/.test(val)) {
|
||||
if (!/^-?\d+(\.?\d+)?$/.test(val)) {
|
||||
return "Value must be a number"
|
||||
}
|
||||
}
|
||||
|
||||
export const validateInteger = ( val ) => {
|
||||
if ( !/^-?\d+$/.test(val)) {
|
||||
if (!/^-?\d+$/.test(val)) {
|
||||
return "Value must be an integer"
|
||||
}
|
||||
}
|
||||
@@ -485,6 +485,10 @@ export const validateParam = (param, isXml) => {
|
||||
return errors
|
||||
}
|
||||
|
||||
if ( value === null || value === undefined ) {
|
||||
return errors
|
||||
}
|
||||
|
||||
if ( type === "number" ) {
|
||||
let err = validateNumber(value)
|
||||
if (!err) return errors
|
||||
@@ -574,6 +578,9 @@ export const sorters = {
|
||||
operationsSorter: {
|
||||
alpha: (a, b) => a.get("path").localeCompare(b.get("path")),
|
||||
method: (a, b) => a.get("method").localeCompare(b.get("method"))
|
||||
},
|
||||
tagsSorter: {
|
||||
alpha: (a, b) => a.localeCompare(b)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,10 @@ import Logo from "./logo_small.png"
|
||||
|
||||
export default class Topbar extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
layoutActions: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = { url: props.specSelectors.url(), selectedIndex: 0 }
|
||||
@@ -80,6 +84,11 @@ export default class Topbar extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
onFilterChange =(e) => {
|
||||
let {target: {value}} = e
|
||||
this.props.layoutActions.updateFilter(value)
|
||||
}
|
||||
|
||||
render() {
|
||||
let { getComponent, specSelectors, getConfigs } = this.props
|
||||
const Button = getComponent("Button")
|
||||
|
||||
@@ -29,7 +29,7 @@ export default class StandaloneLayout extends React.Component {
|
||||
return (
|
||||
|
||||
<Container className='swagger-ui'>
|
||||
{ Topbar ? <Topbar/> : null }
|
||||
{ Topbar ? <Topbar /> : null }
|
||||
{ loadingStatus === "loading" &&
|
||||
<div className="info">
|
||||
<h4 className="title">Loading...</h4>
|
||||
@@ -45,7 +45,7 @@ export default class StandaloneLayout extends React.Component {
|
||||
<h4 className="title">Failed to load config.</h4>
|
||||
</div>
|
||||
}
|
||||
{ !loadingStatus || loadingStatus === "success" && <BaseLayout/> }
|
||||
{ !loadingStatus || loadingStatus === "success" && <BaseLayout /> }
|
||||
<Row>
|
||||
<Col>
|
||||
<OnlineValidatorBadge />
|
||||
|
||||
@@ -45,6 +45,7 @@ body
|
||||
.opblock-tag
|
||||
{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
padding: 10px 20px 10px 10px;
|
||||
|
||||
@@ -53,8 +54,6 @@ body
|
||||
|
||||
border-bottom: 1px solid rgba(#3b4151, .3);
|
||||
|
||||
align-items: center;
|
||||
|
||||
&:hover
|
||||
{
|
||||
background: rgba(#000,.02);
|
||||
@@ -106,9 +105,10 @@ body
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
|
||||
flex: 1;
|
||||
|
||||
padding: 0 10px;
|
||||
|
||||
flex: 1;
|
||||
@include text_body();
|
||||
}
|
||||
}
|
||||
@@ -134,6 +134,8 @@ body
|
||||
transition: all .5s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.opblock
|
||||
{
|
||||
margin: 0 0 15px 0;
|
||||
@@ -154,24 +156,23 @@ body
|
||||
.opblock-section-header
|
||||
{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
padding: 8px 20px;
|
||||
|
||||
background: rgba(#fff,.8);
|
||||
box-shadow: 0 1px 2px rgba(#000,.1);
|
||||
|
||||
align-items: center;
|
||||
|
||||
label
|
||||
{
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
margin: 0;
|
||||
|
||||
align-items: center;
|
||||
@include text_headline();
|
||||
|
||||
span
|
||||
@@ -184,9 +185,10 @@ body
|
||||
{
|
||||
font-size: 14px;
|
||||
|
||||
flex: 1;
|
||||
|
||||
margin: 0;
|
||||
|
||||
flex: 1;
|
||||
@include text_headline();
|
||||
}
|
||||
}
|
||||
@@ -215,11 +217,11 @@ body
|
||||
font-size: 16px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
padding: 0 10px;
|
||||
|
||||
@include text_code();
|
||||
align-items: center;
|
||||
|
||||
.view-line-link
|
||||
{
|
||||
@@ -258,18 +260,18 @@ body
|
||||
font-size: 13px;
|
||||
|
||||
flex: 1;
|
||||
|
||||
@include text_body();
|
||||
}
|
||||
|
||||
.opblock-summary
|
||||
{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
padding: 5px;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&.opblock-post
|
||||
@@ -316,12 +318,24 @@ body
|
||||
|
||||
.opblock-schemes
|
||||
{
|
||||
padding: 8px 20px;
|
||||
padding: 8px 20px;
|
||||
|
||||
.schemes-title
|
||||
{
|
||||
padding: 0 10px 0 0;
|
||||
}
|
||||
.schemes-title
|
||||
{
|
||||
padding: 0 10px 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.filter
|
||||
{
|
||||
.operation-filter-input
|
||||
{
|
||||
width: 100%;
|
||||
margin: 20px 0;
|
||||
padding: 10px 10px;
|
||||
|
||||
border: 2px solid #d8dde7;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,13 +512,11 @@ body
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
|
||||
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
word-break: break-word;
|
||||
hyphens: auto;
|
||||
white-space: pre-wrap;
|
||||
|
||||
|
||||
border-radius: 4px;
|
||||
background: #41444e;
|
||||
@@ -533,10 +545,9 @@ body
|
||||
.schemes
|
||||
{
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
|
||||
> label
|
||||
> label
|
||||
{
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
@@ -624,3 +635,25 @@ body
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
section
|
||||
{
|
||||
h3
|
||||
{
|
||||
@include text_headline();
|
||||
}
|
||||
}
|
||||
|
||||
a.nostyle {
|
||||
text-decoration: inherit;
|
||||
color: inherit;
|
||||
cursor: auto;
|
||||
display: inline;
|
||||
|
||||
&:visited {
|
||||
text-decoration: inherit;
|
||||
color: inherit;
|
||||
cursor: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,10 @@
|
||||
border-radius: 4px;
|
||||
background: rgba(#000,.7);
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 0 1em 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
margin: 0;
|
||||
|
||||
border: 2px solid #547f00;
|
||||
border-radius: 4px 0 0 4px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user