From 2dab372883c79e21e35c1254d89ede613e9d8847 Mon Sep 17 00:00:00 2001 From: mathis-m Date: Sat, 6 Mar 2021 01:00:48 +0100 Subject: [PATCH 1/2] feat: basic hierarchical-tags plugin added basic integration into swagger-ui ecosystem Logic will be improved we have recursive rendering in place. Signed-off-by: mathis-m --- src/core/index.js | 6 ++ src/core/plugins/hierarchical-tags/index.js | 11 ++++ .../plugins/hierarchical-tags/selectors.js | 14 +++++ .../hierarchical-tags/spec-extension/index.js | 6 ++ .../spec-extension/selectors.js | 55 +++++++++++++++++++ .../spec-extension/wrap-selectors.js | 8 +++ src/core/presets/base.js | 4 +- 7 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 src/core/plugins/hierarchical-tags/index.js create mode 100644 src/core/plugins/hierarchical-tags/selectors.js create mode 100644 src/core/plugins/hierarchical-tags/spec-extension/index.js create mode 100644 src/core/plugins/hierarchical-tags/spec-extension/selectors.js create mode 100644 src/core/plugins/hierarchical-tags/spec-extension/wrap-selectors.js diff --git a/src/core/index.js b/src/core/index.js index 72a32d3ff03..b4d30a6591a 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -53,6 +53,8 @@ export default function SwaggerUI(opts) { showExtensions: false, showCommonExtensions: false, withCredentials: undefined, + hierarchicalTagsEnabled: true, // TODO: switch to false + hierarchicalTagDelimiter: "|", supportedSubmitMethods: [ "get", "put", @@ -107,6 +109,10 @@ export default function SwaggerUI(opts) { spec: { spec: "", url: constructorConfig.url + }, + hierarchicalTags: { + enabled: constructorConfig.hierarchicalTagsEnabled, + delimiter: constructorConfig.hierarchicalTagDelimiter } }, constructorConfig.initialState) } diff --git a/src/core/plugins/hierarchical-tags/index.js b/src/core/plugins/hierarchical-tags/index.js new file mode 100644 index 00000000000..b4871578068 --- /dev/null +++ b/src/core/plugins/hierarchical-tags/index.js @@ -0,0 +1,11 @@ +import spec from "./spec-extension" +import * as selectors from "./selectors" + +export default () => ({ + statePlugins: { + hierarchicalTags: { + selectors + }, + spec + } +}) diff --git a/src/core/plugins/hierarchical-tags/selectors.js b/src/core/plugins/hierarchical-tags/selectors.js new file mode 100644 index 00000000000..8898f7e8a3a --- /dev/null +++ b/src/core/plugins/hierarchical-tags/selectors.js @@ -0,0 +1,14 @@ +import { createSelector } from "reselect" +import { Map } from "immutable" + +const state = state => state || Map() + +export const isEnabled = createSelector( + state, + state => state.get("enabled", false) +) + +export const getTagDelimiter = createSelector( + state, + state => state.get( "delimiter", "|") +) diff --git a/src/core/plugins/hierarchical-tags/spec-extension/index.js b/src/core/plugins/hierarchical-tags/spec-extension/index.js new file mode 100644 index 00000000000..c095643be04 --- /dev/null +++ b/src/core/plugins/hierarchical-tags/spec-extension/index.js @@ -0,0 +1,6 @@ +import * as selectors from "./selectors" +import * as wrapSelectors from "./wrap-selectors" +export default { + selectors, + wrapSelectors +} diff --git a/src/core/plugins/hierarchical-tags/spec-extension/selectors.js b/src/core/plugins/hierarchical-tags/spec-extension/selectors.js new file mode 100644 index 00000000000..257343dfefe --- /dev/null +++ b/src/core/plugins/hierarchical-tags/spec-extension/selectors.js @@ -0,0 +1,55 @@ +import { taggedOperations } from "../../spec/selectors" +import { OrderedMap } from "immutable" + +export const hierarchicalTaggedOperations = (state) => (system) => { + system = system.getSystem() + const delimiter = system.hierarchicalTagsSelectors.getTagDelimiter() + const filter = system.layoutSelectors.currentFilter() + + let taggedOperationsMap = taggedOperations(state)(system) + + if (filter) { + if (filter !== true && filter !== "true" && filter !== "false") { + taggedOperationsMap = system.fn.opsFilter(taggedOperationsMap, filter) + } + } + + let hierarchicalTaggedOperations = OrderedMap() + + const addTagIn = (nestedTagPath, value) => { + value = value.set("tags", OrderedMap()) + const visitedTags = [] + let currentTag = nestedTagPath.shift() + while(currentTag !== undefined) { + const isRootTag = visitedTags.length === 0 + const isNewRootTag = isRootTag && !hierarchicalTaggedOperations.has(currentTag) + + if(isNewRootTag) { + hierarchicalTaggedOperations = hierarchicalTaggedOperations.set( + currentTag, + value + ) + visitedTags.push(currentTag) + currentTag = nestedTagPath.shift() + continue + } + + const hierarchicalUpdatePath = visitedTags + .reduce((acc, x) => acc.concat([x, "tags"]), []) + hierarchicalUpdatePath.push(currentTag) + + hierarchicalTaggedOperations = hierarchicalTaggedOperations.mergeDeepIn( + hierarchicalUpdatePath, + nestedTagPath.length === 0 ? value : OrderedMap({tags: OrderedMap()}) + ) + + visitedTags.push(currentTag) + currentTag = nestedTagPath.shift() + } + } + + taggedOperationsMap.forEach((v, k) => { + addTagIn(k.split(delimiter), v) + }) + return hierarchicalTaggedOperations +} diff --git a/src/core/plugins/hierarchical-tags/spec-extension/wrap-selectors.js b/src/core/plugins/hierarchical-tags/spec-extension/wrap-selectors.js new file mode 100644 index 00000000000..2e41011c55c --- /dev/null +++ b/src/core/plugins/hierarchical-tags/spec-extension/wrap-selectors.js @@ -0,0 +1,8 @@ +export const taggedOperations = (oriSelector, system) => (...args) => { + const { hierarchicalTagsSelectors, specSelectors } = system.getSystem() + if(!hierarchicalTagsSelectors.isEnabled()) { + return oriSelector(...args) + } + + return specSelectors.hierarchicalTaggedOperations() +} diff --git a/src/core/presets/base.js b/src/core/presets/base.js index 73565cdf7cd..911c7c64d0f 100644 --- a/src/core/presets/base.js +++ b/src/core/presets/base.js @@ -12,6 +12,7 @@ import configsPlugin from "core/plugins/configs" import deepLinkingPlugin from "core/plugins/deep-linking" import filter from "core/plugins/filter" import onComplete from "core/plugins/on-complete" +import hierarchicalTags from "core/plugins/hierarchical-tags" import OperationContainer from "core/containers/OperationContainer" @@ -191,6 +192,7 @@ export default function() { downloadUrlPlugin, deepLinkingPlugin, filter, - onComplete + onComplete, + hierarchicalTags ] } From f3bac5118bdd052f82cbf82c5b9762b20ec9c5bf Mon Sep 17 00:00:00 2001 From: mathis-m Date: Sat, 6 Mar 2021 01:20:50 +0100 Subject: [PATCH 2/2] fix: should use empty tag if not defined Signed-off-by: mathis-m --- .../spec-extension/selectors.js | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/core/plugins/hierarchical-tags/spec-extension/selectors.js b/src/core/plugins/hierarchical-tags/spec-extension/selectors.js index 257343dfefe..7d1cc066425 100644 --- a/src/core/plugins/hierarchical-tags/spec-extension/selectors.js +++ b/src/core/plugins/hierarchical-tags/spec-extension/selectors.js @@ -2,32 +2,39 @@ import { taggedOperations } from "../../spec/selectors" import { OrderedMap } from "immutable" export const hierarchicalTaggedOperations = (state) => (system) => { - system = system.getSystem() - const delimiter = system.hierarchicalTagsSelectors.getTagDelimiter() - const filter = system.layoutSelectors.currentFilter() + const { + hierarchicalTagsSelectors, + layoutSelectors, + fn + } = system = system.getSystem() + const delimiter = hierarchicalTagsSelectors.getTagDelimiter() + const filter = layoutSelectors.currentFilter() let taggedOperationsMap = taggedOperations(state)(system) if (filter) { if (filter !== true && filter !== "true" && filter !== "false") { - taggedOperationsMap = system.fn.opsFilter(taggedOperationsMap, filter) + taggedOperationsMap = fn.opsFilter(taggedOperationsMap, filter) } } let hierarchicalTaggedOperations = OrderedMap() - const addTagIn = (nestedTagPath, value) => { - value = value.set("tags", OrderedMap()) + const addTagIn = (nestedTagPath, targetValue) => { + targetValue = targetValue.set("tags", OrderedMap()) const visitedTags = [] let currentTag = nestedTagPath.shift() while(currentTag !== undefined) { + const isTargetTag = nestedTagPath.length === 0 const isRootTag = visitedTags.length === 0 const isNewRootTag = isRootTag && !hierarchicalTaggedOperations.has(currentTag) + const newTagValue = isTargetTag ? targetValue : OrderedMap({tags: OrderedMap()}) + if(isNewRootTag) { hierarchicalTaggedOperations = hierarchicalTaggedOperations.set( currentTag, - value + newTagValue ) visitedTags.push(currentTag) currentTag = nestedTagPath.shift() @@ -40,7 +47,7 @@ export const hierarchicalTaggedOperations = (state) => (system) => { hierarchicalTaggedOperations = hierarchicalTaggedOperations.mergeDeepIn( hierarchicalUpdatePath, - nestedTagPath.length === 0 ? value : OrderedMap({tags: OrderedMap()}) + newTagValue ) visitedTags.push(currentTag)