From 0fc00b2a1f91cc44e5e40547724982329b305885 Mon Sep 17 00:00:00 2001 From: Javier Mendiara Date: Thu, 17 Nov 2022 19:42:45 +0100 Subject: [PATCH] feat: Custom Extension Components --- src/components/Fields/Extensions.tsx | 51 +++++++++++++++++++++++--- src/services/RedocNormalizedOptions.ts | 5 ++- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/components/Fields/Extensions.tsx b/src/components/Fields/Extensions.tsx index 5a450ce4..ca3d1c69 100644 --- a/src/components/Fields/Extensions.tsx +++ b/src/components/Fields/Extensions.tsx @@ -4,14 +4,21 @@ import { ExtensionValue, FieldLabel } from '../../common-elements/fields'; import styled from '../../styled-components'; -import { OptionsContext } from '../OptionsProvider'; - +import { AppStore } from '../../services'; import { StyledMarkdownBlock } from '../Markdown/styled.elements'; +import { OptionsContext } from '../OptionsProvider'; +import { StoreConsumer } from '../StoreBuilder'; const Extension = styled(StyledMarkdownBlock)` margin: 2px 0; `; +export interface ExtensionComponentMeta { + component: React.ComponentType; + propsSelector: (store?: AppStore) => any; + props?: object; +} + export interface ExtensionsProps { extensions: { [k: string]: any; @@ -19,6 +26,39 @@ export interface ExtensionsProps { } export class Extensions extends React.PureComponent { + renderExtensionComponent(key: string, meta: ExtensionComponentMeta) { + const exts = this.props.extensions; + + return ( + + {store => ( + + )} + + ); + } + + renderSimpleExtension(key: string) { + const exts = this.props.extensions; + + return ( + <> + {key.substring(2)}: {' '} + + {typeof exts[key] === 'string' ? exts[key] : JSON.stringify(exts[key])} + + + ); + } + render() { const exts = this.props.extensions; return ( @@ -28,10 +68,9 @@ export class Extensions extends React.PureComponent { {options.showExtensions && Object.keys(exts).map(key => ( - {key.substring(2)}: {' '} - - {typeof exts[key] === 'string' ? exts[key] : JSON.stringify(exts[key])} - + {options.extensionsComponents[key] + ? this.renderExtensionComponent(key, options.extensionsComponents[key]) + : this.renderSimpleExtension(key)} ))} diff --git a/src/services/RedocNormalizedOptions.ts b/src/services/RedocNormalizedOptions.ts index 4a219eef..45fa9fa9 100644 --- a/src/services/RedocNormalizedOptions.ts +++ b/src/services/RedocNormalizedOptions.ts @@ -1,7 +1,7 @@ import defaultTheme, { ResolvedThemeInterface, resolveTheme, ThemeInterface } from '../theme'; import { querySelector } from '../utils/dom'; import { isArray, isNumeric, mergeObjects } from '../utils/helpers'; - +import { ExtensionComponentMeta } from '../components/Fields/Extensions'; import { setRedocLabels } from './Labels'; import { SideNavStyleEnum } from './types'; import type { LabelsConfigRaw, MDXComponentMeta } from './types'; @@ -30,6 +30,7 @@ export interface RedocRawOptions { hideSingleRequestSampleTab?: boolean | string; menuToggle?: boolean | string; jsonSampleExpandLevel?: number | string | 'all'; + extensionsComponents?: Record; hideSchemaTitles?: boolean | string; simpleOneOfTypeLabel?: boolean | string; payloadSampleIdx?: number; @@ -234,6 +235,7 @@ export class RedocNormalizedOptions { menuToggle: boolean; jsonSampleExpandLevel: number; enumSkipQuotes: boolean; + extensionsComponents: Record; hideSchemaTitles: boolean; simpleOneOfTypeLabel: boolean; payloadSampleIdx: number; @@ -321,6 +323,7 @@ export class RedocNormalizedOptions { this.allowedMdComponents = raw.allowedMdComponents || {}; this.expandDefaultServerVariables = argValueToBoolean(raw.expandDefaultServerVariables); + this.extensionsComponents = raw.extensionsComponents || {}; this.maxDisplayedEnumValues = argValueToNumber(raw.maxDisplayedEnumValues); const ignoreNamedSchemas = isArray(raw.ignoreNamedSchemas) ? raw.ignoreNamedSchemas