From f6b86d2d3370e05241f51cfe535b2a38c9fc0641 Mon Sep 17 00:00:00 2001 From: Josh Ponelat Date: Wed, 18 Oct 2017 13:07:38 +0200 Subject: [PATCH 1/7] Refactor layout .show/.isShown to handle branch nodes --- src/core/plugins/layout/actions.js | 14 -------------- src/core/plugins/layout/reducers.js | 13 +++++++++---- src/core/plugins/layout/selectors.js | 4 ++-- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/core/plugins/layout/actions.js b/src/core/plugins/layout/actions.js index d65d34e3..987395b0 100644 --- a/src/core/plugins/layout/actions.js +++ b/src/core/plugins/layout/actions.js @@ -37,17 +37,3 @@ export function changeMode(thing, mode="") { payload: {thing, mode} } } - - -// export function onlyShow(thing, shown=true) { -// thing = normalizeArray(thing) -// if(thing.length < 2) -// throw new Error("layoutActions.onlyShow only works, when `thing` is an array with length > 1") -// return { -// type: ONLY_SHOW, -// payload: {thing, shown} -// } -// } - - - diff --git a/src/core/plugins/layout/reducers.js b/src/core/plugins/layout/reducers.js index 4b561015..aa067abd 100644 --- a/src/core/plugins/layout/reducers.js +++ b/src/core/plugins/layout/reducers.js @@ -1,3 +1,4 @@ +import { fromJS } from "immutable" import { UPDATE_LAYOUT, UPDATE_FILTER, @@ -12,9 +13,14 @@ export default { [UPDATE_FILTER]: (state, action) => state.set("filter", action.payload), [SHOW]: (state, action) => { - let thing = action.payload.thing - let shown = action.payload.shown - return state.setIn(["shown"].concat(thing), shown) + const isShown = action.payload.shown + // This is one way to serialize an array, another (preferred) is to convert to json-pointer + // TODO: use json-pointer serilization instead of fromJS(...), for performance + const thingToShow = fromJS(action.payload.thing) + // This is a map of paths to bools + // eg: [one, two] => true + // eg: [one] => false + return state.update("shown", fromJS({}), a => a.set(thingToShow, isShown)) }, [UPDATE_MODE]: (state, action) => { @@ -24,4 +30,3 @@ export default { } } - diff --git a/src/core/plugins/layout/selectors.js b/src/core/plugins/layout/selectors.js index 42a3bcbb..7d75d37d 100644 --- a/src/core/plugins/layout/selectors.js +++ b/src/core/plugins/layout/selectors.js @@ -1,5 +1,6 @@ import { createSelector } from "reselect" import { normalizeArray } from "core/utils" +import { fromJS } from "immutable" const state = state => state @@ -9,7 +10,7 @@ export const currentFilter = state => state.get("filter") export const isShown = (state, thing, def) => { thing = normalizeArray(thing) - return Boolean(state.getIn(["shown", ...thing], def)) + return state.get("shown", fromJS({})).get(fromJS(thing), def) } export const whatMode = (state, thing, def="") => { @@ -21,4 +22,3 @@ export const showSummary = createSelector( state, state => !isShown(state, "editor") ) - From 3893cb439615588b9d16904b1ae64ae0a46b741a Mon Sep 17 00:00:00 2001 From: Josh Ponelat Date: Wed, 25 Oct 2017 09:31:43 +0200 Subject: [PATCH 2/7] deep linking for models, operations and tags --- src/core/components/array-model.jsx | 2 +- src/core/components/model-collapse.jsx | 34 ++++++++++++++----- src/core/components/model-wrapper.jsx | 18 +++++++--- src/core/components/models.jsx | 9 +++-- src/core/components/object-model.jsx | 14 ++++++-- .../plugins/deep-linking/spec-wrap-actions.js | 20 +++++------ 6 files changed, 67 insertions(+), 30 deletions(-) diff --git a/src/core/components/array-model.jsx b/src/core/components/array-model.jsx index 6f646bb6..537fe365 100644 --- a/src/core/components/array-model.jsx +++ b/src/core/components/array-model.jsx @@ -38,7 +38,7 @@ export default class ArrayModel extends Component { */ return - expandDepth } collapsedContent="[...]"> + [ { properties.size ? properties.entrySeq().map( ( [ key, v ] ) => ) : null diff --git a/src/core/components/model-collapse.jsx b/src/core/components/model-collapse.jsx index b71096f2..d501d4b1 100644 --- a/src/core/components/model-collapse.jsx +++ b/src/core/components/model-collapse.jsx @@ -4,31 +4,47 @@ import PropTypes from "prop-types" export default class ModelCollapse extends Component { static propTypes = { collapsedContent: PropTypes.any, - collapsed: PropTypes.bool, + expanded: PropTypes.bool, children: PropTypes.any, - title: PropTypes.element + title: PropTypes.element, + modelName: PropTypes.string, + onToggle: PropTypes.func.isRequired } static defaultProps = { collapsedContent: "{...}", - collapsed: true, + expanded: false, title: null } constructor(props, context) { super(props, context) - let { collapsed, collapsedContent } = this.props + let { expanded, collapsedContent } = this.props this.state = { - collapsed: collapsed !== undefined ? collapsed : ModelCollapse.defaultProps.collapsed, + expanded : expanded, collapsedContent: collapsedContent || ModelCollapse.defaultProps.collapsedContent } } + componentWillReceiveProps(nextProps){ + + if(this.props.expanded!= nextProps.expanded){ + this.setState({expanded: nextProps.expanded}) + } + + } + toggleCollapsed=()=>{ + + + if(this.props.onToggle){ + this.props.onToggle(this.props.modelName,!this.state.expanded) + } + this.setState({ - collapsed: !this.state.collapsed + expanded: !this.state.expanded }) } @@ -38,10 +54,10 @@ export default class ModelCollapse extends Component { { title && {title} } - + - { this.state.collapsed ? this.state.collapsedContent : this.props.children } + { this.state.expanded ? this.props.children :this.state.collapsedContent } ) } -} \ No newline at end of file +} diff --git a/src/core/components/model-wrapper.jsx b/src/core/components/model-wrapper.jsx index fa117c2b..cec55295 100644 --- a/src/core/components/model-wrapper.jsx +++ b/src/core/components/model-wrapper.jsx @@ -1,22 +1,32 @@ import React, { Component, } from "react" import PropTypes from "prop-types" +//import layoutActions from "actions/layout" + + +export default class ModelWrapper extends Component { + -export default class ModelComponent extends Component { static propTypes = { schema: PropTypes.object.isRequired, name: PropTypes.string, getComponent: PropTypes.func.isRequired, getConfigs: PropTypes.func.isRequired, specSelectors: PropTypes.object.isRequired, - expandDepth: PropTypes.number + expandDepth: PropTypes.number, + layoutActions: PropTypes.object, + layoutSelectors: PropTypes.object.isRequired + } + + onToggle = (name,isShown) => { + this.props.layoutActions.show(["models", name],isShown) } render(){ let { getComponent, getConfigs } = this.props const Model = getComponent("Model") - + const expanded = this.props.layoutSelectors.isShown(["models",this.props.name]) return
- +
} } diff --git a/src/core/components/models.jsx b/src/core/components/models.jsx index 30d78b26..e404c3bc 100644 --- a/src/core/components/models.jsx +++ b/src/core/components/models.jsx @@ -31,13 +31,16 @@ export default class Models extends Component { { definitions.entrySeq().map( ( [ name, model ])=>{ - return
+ + return
+ specSelectors={ specSelectors } + getConfigs = {getConfigs} + layoutSelectors = {layoutSelectors} + layoutActions = {layoutActions}/>
}).toArray() } diff --git a/src/core/components/object-model.jsx b/src/core/components/object-model.jsx index 83530530..ac3f2133 100644 --- a/src/core/components/object-model.jsx +++ b/src/core/components/object-model.jsx @@ -10,6 +10,8 @@ export default class ObjectModel extends Component { schema: PropTypes.object.isRequired, getComponent: PropTypes.func.isRequired, getConfigs: PropTypes.func.isRequired, + expanded: PropTypes.bool, + onToggle: PropTypes.func.isRequired, specSelectors: PropTypes.object.isRequired, name: PropTypes.string, isRef: PropTypes.bool, @@ -18,8 +20,8 @@ export default class ObjectModel extends Component { } render(){ - let { schema, name, isRef, getComponent, getConfigs, depth, expandDepth, ...otherProps } = this.props - let { specSelectors } = otherProps + let { schema, name, isRef, getComponent, getConfigs, depth, onToggle, expanded, ...otherProps } = this.props + let { specSelectors,expandDepth } = otherProps let { isOAS3 } = specSelectors if(!schema) { @@ -60,7 +62,13 @@ export default class ObjectModel extends Component { return - expandDepth } collapsedContent={ collapsedContent }> + + { braceOpen } { !isRef ? null : diff --git a/src/core/plugins/deep-linking/spec-wrap-actions.js b/src/core/plugins/deep-linking/spec-wrap-actions.js index ebeebe5c..f385d9cb 100644 --- a/src/core/plugins/deep-linking/spec-wrap-actions.js +++ b/src/core/plugins/deep-linking/spec-wrap-actions.js @@ -1,8 +1,7 @@ -import scrollTo from "scroll-to-element" +import zenscroll from "zenscroll" import { escapeDeepLinkPath } from "core/utils" -const SCROLL_OFFSET = -5 -let hasHashBeenParsed = false +let hasHashBeenParsed = false //TODO this forces code to only run once which may prevent scrolling if page not refreshed export const updateResolved = (ori, { layoutActions, getConfigs }) => (...args) => { @@ -12,7 +11,6 @@ export const updateResolved = (ori, { layoutActions, getConfigs }) => (...args) if(!isDeepLinkingEnabled || isDeepLinkingEnabled === "false") { return } - if(window.location.hash && !hasHashBeenParsed ) { let hash = window.location.hash.slice(1) // # is first character @@ -30,21 +28,23 @@ export const updateResolved = (ori, { layoutActions, getConfigs }) => (...args) let [tag, operationId] = hash.split("/") + let swaggerUI = document.querySelector(".swagger-ui") + let myScroller = zenscroll.createScroller(swaggerUI) + if(tag && operationId) { // Pre-expand and scroll to the operation layoutActions.show(["operations-tag", tag], true) layoutActions.show(["operations", tag, operationId], true) - scrollTo(`#operations-${escapeDeepLinkPath(tag)}-${escapeDeepLinkPath(operationId)}`, { - offset: SCROLL_OFFSET - }) + let target = document.getElementById(`#operations-${escapeDeepLinkPath(tag)}-${escapeDeepLinkPath(operationId)}`, { + myScroller.to(target) + } else if(tag) { // Pre-expand and scroll to the tag layoutActions.show(["operations-tag", tag], true) - scrollTo(`#operations-tag-${escapeDeepLinkPath(tag)}`, { - offset: SCROLL_OFFSET - }) + let target = document.getElementById(`#operations-tag-${escapeDeepLinkPath(tag)}`, { + myScroller.to(target) } } From 80ec61048521d1475e39ff069ec1f71cf12f96e5 Mon Sep 17 00:00:00 2001 From: Liam Shaw Date: Wed, 18 Oct 2017 13:12:12 +0100 Subject: [PATCH 3/7] add zen scroll --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 1276ede0..f29ef3d0 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,8 @@ "worker-loader": "^0.7.1", "xml": "1.0.1", "xml-but-prettier": "^1.0.1", - "yaml-js": "0.2.0" + "yaml-js": "0.2.0", + "zenscroll": "4.0.0" }, "devDependencies": { "autoprefixer": "7.1.1", From c260263e4e9e26626af0a18b37b335206168fe96 Mon Sep 17 00:00:00 2001 From: Josh Ponelat Date: Tue, 24 Oct 2017 21:35:00 +0200 Subject: [PATCH 4/7] fix issues with deeplink conflicts --- src/core/plugins/deep-linking/spec-wrap-actions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/plugins/deep-linking/spec-wrap-actions.js b/src/core/plugins/deep-linking/spec-wrap-actions.js index f385d9cb..a90d924c 100644 --- a/src/core/plugins/deep-linking/spec-wrap-actions.js +++ b/src/core/plugins/deep-linking/spec-wrap-actions.js @@ -36,14 +36,14 @@ export const updateResolved = (ori, { layoutActions, getConfigs }) => (...args) layoutActions.show(["operations-tag", tag], true) layoutActions.show(["operations", tag, operationId], true) - let target = document.getElementById(`#operations-${escapeDeepLinkPath(tag)}-${escapeDeepLinkPath(operationId)}`, { + let target = document.getElementById(`operations-${escapeDeepLinkPath(tag)}-${escapeDeepLinkPath(operationId)}`) myScroller.to(target) } else if(tag) { // Pre-expand and scroll to the tag layoutActions.show(["operations-tag", tag], true) - let target = document.getElementById(`#operations-tag-${escapeDeepLinkPath(tag)}`, { + let target = document.getElementById(`operations-tag-${escapeDeepLinkPath(tag)}`) myScroller.to(target) } } From 41ae8242b6719d6bb5c65e052efdf43d4c64d53c Mon Sep 17 00:00:00 2001 From: Josh Ponelat Date: Wed, 25 Oct 2017 14:27:24 +0200 Subject: [PATCH 5/7] fix test --- test/components/models.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/components/models.js b/test/components/models.js index 750a8cf1..44e34d54 100644 --- a/test/components/models.js +++ b/test/components/models.js @@ -42,7 +42,7 @@ describe("", function(){ // Then should render tabs expect(wrapper.find("ModelCollapse").length).toEqual(1) - expect(wrapper.find("ModelComponent").length).toBeGreaterThan(0) + expect(wrapper.find("ModelWrapper").length).toBeGreaterThan(0) wrapper.find("ModelComponent").forEach((modelWrapper) => { expect(modelWrapper.props().expandDepth).toBe(0) }) From 780c5f1b83fd39eaa0f2ee4c05e27fda3d994687 Mon Sep 17 00:00:00 2001 From: Josh Ponelat Date: Fri, 27 Oct 2017 15:01:36 +0200 Subject: [PATCH 6/7] Add conditionals to ModelWrapper testing for layout props --- src/core/components/model-wrapper.jsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/core/components/model-wrapper.jsx b/src/core/components/model-wrapper.jsx index cec55295..24d90209 100644 --- a/src/core/components/model-wrapper.jsx +++ b/src/core/components/model-wrapper.jsx @@ -18,15 +18,24 @@ export default class ModelWrapper extends Component { } onToggle = (name,isShown) => { + // If this prop is present, we'll have deepLinking for it + if(this.props.layoutActions) { this.props.layoutActions.show(["models", name],isShown) + } } render(){ let { getComponent, getConfigs } = this.props const Model = getComponent("Model") - const expanded = this.props.layoutSelectors.isShown(["models",this.props.name]) + + let expanded + if(this.props.layoutSelectors) { + // If this is prop is present, we'll have deepLinking for it + expanded = this.props.layoutSelectors.isShown(["models",this.props.name]) + } + return
- +
} } From af14cc9e788cb4f08449cf84986abf42ffeae39d Mon Sep 17 00:00:00 2001 From: kyle Date: Mon, 11 Dec 2017 19:09:00 -0800 Subject: [PATCH 7/7] Add missing comma --- src/core/components/object-model.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/components/object-model.jsx b/src/core/components/object-model.jsx index 96b59cc8..619e9a95 100644 --- a/src/core/components/object-model.jsx +++ b/src/core/components/object-model.jsx @@ -21,7 +21,7 @@ export default class ObjectModel extends Component { } render(){ - let { schema, name, isRef, getComponent, getConfigs, depth, onToggle, expanded, specPath ...otherProps } = this.props + let { schema, name, isRef, getComponent, getConfigs, depth, onToggle, expanded, specPath, ...otherProps } = this.props let { specSelectors,expandDepth } = otherProps const { isOAS3 } = specSelectors