diff --git a/src/core/components/auth/scope-display.jsx b/src/core/components/auth/scope-display.jsx
new file mode 100644
index 00000000000..b7f169b0583
--- /dev/null
+++ b/src/core/components/auth/scope-display.jsx
@@ -0,0 +1,130 @@
+import React from "react"
+import PropTypes from "prop-types"
+import ImPropTypes from "react-immutable-proptypes"
+
+export default class ScopeDisplay extends React.Component {
+ static propTypes = {
+ security: ImPropTypes.iterable,
+ authSelectors: PropTypes.object.isRequired,
+ authDefinitions: ImPropTypes.iterable,
+ specSelectors: PropTypes.object.isRequired
+ }
+
+ extractSecurityRequirements = (security) => {
+ if (!security || !security.count()) {
+ return null
+ }
+
+ const requirements = []
+
+ // Each item in security array represents an OR condition
+ security.forEach((requirement) => {
+ const schemes = []
+
+ // Each entry in a requirement represents an AND condition
+ requirement.forEach((scopes, schemeName) => {
+ const schemeData = {
+ name: schemeName,
+ scopes: []
+ }
+
+ // Handle different security scheme types
+ if (scopes && scopes.size > 0) {
+ // For OAuth2, OpenID Connect, or any scheme with scopes
+ schemeData.scopes = scopes.toJS()
+ }
+
+ schemes.push(schemeData)
+ })
+
+ requirements.push(schemes)
+ })
+
+ return requirements
+ }
+
+ formatNonOptionalRequirements = (requirements) => {
+ return requirements.map((requirementGroup, idx) => {
+ const isLastGroup = idx === requirements.length - 1
+
+ return (
+
+ {requirementGroup.map((scheme, schemeIdx) => {
+ const isLastInGroup = schemeIdx === requirementGroup.length - 1
+
+ return (
+
+ {scheme.name}
+ {scheme.scopes.length > 0 && (
+
+ {" ("}
+ {scheme.scopes.map((scope, scopeIdx) => (
+
+
+ {scope}
+
+ {scopeIdx < scheme.scopes.length - 1 ? ", " : ""}
+
+ ))}
+ {")"}
+
+ )}
+ {!isLastInGroup && (
+ +
+ )}
+
+ )
+ })}
+ {!isLastGroup && (
+ OR
+ )}
+
+ )
+ })
+ }
+
+ formatSecurityDisplay = (requirements) => {
+ if (!requirements || requirements.length === 0) {
+ return null
+ }
+
+ // Check if this is optional security (empty object in array)
+ if (requirements.length === 1 && requirements[0].length === 0) {
+ return Optional
+ }
+
+ // Check for optional security pattern (one empty and others with auth)
+ const hasEmptyRequirement = requirements.some(req => req.length === 0)
+ const hasNonEmptyRequirement = requirements.some(req => req.length > 0)
+
+ if (hasEmptyRequirement && hasNonEmptyRequirement) {
+ // Filter out empty requirements and add optional label
+ const nonEmptyRequirements = requirements.filter(req => req.length > 0)
+ return (
+
+ Optional
+ OR
+ {this.formatNonOptionalRequirements(nonEmptyRequirements)}
+
+ )
+ }
+
+ return this.formatNonOptionalRequirements(requirements)
+ }
+
+ render() {
+ const { security } = this.props
+ const requirements = this.extractSecurityRequirements(security)
+ const display = this.formatSecurityDisplay(requirements)
+
+ if (!display) {
+ return null
+ }
+
+ return (
+
+ {display}
+
+ )
+ }
+}
\ No newline at end of file
diff --git a/src/core/components/operation-summary.jsx b/src/core/components/operation-summary.jsx
index d31f56d3f9c..90881f50f4c 100644
--- a/src/core/components/operation-summary.jsx
+++ b/src/core/components/operation-summary.jsx
@@ -16,6 +16,7 @@ export default class OperationSummary extends PureComponent {
getConfigs: PropTypes.func.isRequired,
authActions: PropTypes.object,
authSelectors: PropTypes.object,
+ specSelectors: PropTypes.object,
}
static defaultProps = {
@@ -32,6 +33,7 @@ export default class OperationSummary extends PureComponent {
getComponent,
authActions,
authSelectors,
+ specSelectors,
operationProps,
specPath,
} = this.props
@@ -55,6 +57,7 @@ export default class OperationSummary extends PureComponent {
let security = operationProps.get("security")
const AuthorizeOperationBtn = getComponent("authorizeOperationBtn", true)
+ const ScopeDisplay = getComponent("ScopeDisplay", true)
const OperationSummaryMethod = getComponent("OperationSummaryMethod")
const OperationSummaryPath = getComponent("OperationSummaryPath")
const JumpToPath = getComponent("JumpToPath", true)
@@ -88,13 +91,21 @@ export default class OperationSummary extends PureComponent {
{
allowAnonymous ? null :
- {
- const applicableDefinitions = authSelectors.definitionsForRequirements(security)
- authActions.showDefinitions(applicableDefinitions)
- }}
- />
+
+
+
{
+ const applicableDefinitions = authSelectors.definitionsForRequirements(security)
+ authActions.showDefinitions(applicableDefinitions)
+ }}
+ />
+
}
{/* TODO: use wrapComponents here, swagger-ui doesn't care about jumpToPath */}