feat: add maxDisplayedEnumValues config and buttons for show/hide enums (#1322)

This commit is contained in:
Oleksiy Kachynskyy 2020-07-21 16:36:08 +03:00 committed by Roman Hotsiy
parent a96a11a4dc
commit 14e7db9403
No known key found for this signature in database
GPG Key ID: 5CB7B3ACABA57CB0
3 changed files with 59 additions and 4 deletions

View File

@ -26,7 +26,7 @@ const specUrl =
(userUrl && userUrl[1]) || (swagger ? 'swagger.yaml' : big ? 'big-openapi.json' : 'openapi.yaml'); (userUrl && userUrl[1]) || (swagger ? 'swagger.yaml' : big ? 'big-openapi.json' : 'openapi.yaml');
let store; let store;
const options: RedocRawOptions = { nativeScrollbars: false }; const options: RedocRawOptions = { nativeScrollbars: false, maxDisplayedEnumValues: 2 };
async function init() { async function init() {
const spec = await loadAndBundleSpec(specUrl); const spec = await loadAndBundleSpec(specUrl);

View File

@ -3,28 +3,52 @@ import { ExampleValue, FieldLabel } from '../../common-elements/fields';
import { l } from '../../services/Labels'; import { l } from '../../services/Labels';
import { OptionsContext } from '../OptionsProvider'; import { OptionsContext } from '../OptionsProvider';
import styled from '../../styled-components';
import { RedocRawOptions } from '../../services/RedocNormalizedOptions';
export interface EnumValuesProps { export interface EnumValuesProps {
values: string[]; values: string[];
type: string; type: string;
} }
export class EnumValues extends React.PureComponent<EnumValuesProps> { export interface EnumValuesState {
collapsed: boolean;
}
export class EnumValues extends React.PureComponent<EnumValuesProps, EnumValuesState> {
state: EnumValuesState = {
collapsed: true,
};
static contextType = OptionsContext; static contextType = OptionsContext;
private toggle() {
this.setState({ collapsed: !this.state.collapsed });
}
render() { render() {
const { values, type } = this.props; const { values, type } = this.props;
const { enumSkipQuotes } = this.context; const { collapsed } = this.state;
// TODO: provide context interface in more elegant way
const { enumSkipQuotes, maxDisplayedEnumValues } = this.context as RedocRawOptions;
if (!values.length) { if (!values.length) {
return null; return null;
} }
const displayedItems =
this.state.collapsed && maxDisplayedEnumValues
? values.slice(0, maxDisplayedEnumValues)
: values;
return ( return (
<div> <div>
<FieldLabel> <FieldLabel>
{type === 'array' ? l('enumArray') : ''}{' '} {type === 'array' ? l('enumArray') : ''}{' '}
{values.length === 1 ? l('enumSingleValue') : l('enum')}: {values.length === 1 ? l('enumSingleValue') : l('enum')}:
</FieldLabel>{' '} </FieldLabel>{' '}
{values.map((value, idx) => { {displayedItems.map((value, idx) => {
const exampleValue = enumSkipQuotes ? value : JSON.stringify(value); const exampleValue = enumSkipQuotes ? value : JSON.stringify(value);
return ( return (
<React.Fragment key={idx}> <React.Fragment key={idx}>
@ -32,7 +56,25 @@ export class EnumValues extends React.PureComponent<EnumValuesProps> {
</React.Fragment> </React.Fragment>
); );
})} })}
{maxDisplayedEnumValues ? (
<ToggleButton
onClick={() => {
this.toggle();
}}
>
{collapsed ? `${values.length - maxDisplayedEnumValues} more` : 'Hide'}
</ToggleButton>
) : null}
</div> </div>
); );
} }
} }
const ToggleButton = styled.span`
color: ${props => props.theme.colors.primary.main};
vertical-align: middle;
font-size: 13px;
line-height: 20px;
padding: 0 5px;
cursor: pointer;
`;

View File

@ -38,6 +38,7 @@ export interface RedocRawOptions {
enumSkipQuotes?: boolean | string; enumSkipQuotes?: boolean | string;
expandDefaultServerVariables?: boolean; expandDefaultServerVariables?: boolean;
maxDisplayedEnumValues?: number;
} }
function argValueToBoolean(val?: string | boolean, defaultValue?: boolean): boolean { function argValueToBoolean(val?: string | boolean, defaultValue?: boolean): boolean {
@ -50,6 +51,16 @@ function argValueToBoolean(val?: string | boolean, defaultValue?: boolean): bool
return val; return val;
} }
function argValueToNumber(value: number | string | undefined): number | undefined {
if (typeof value === 'string') {
return parseInt(value, 10);
}
if (typeof value === 'number') {
return value;
}
}
export class RedocNormalizedOptions { export class RedocNormalizedOptions {
static normalizeExpandResponses(value: RedocRawOptions['expandResponses']) { static normalizeExpandResponses(value: RedocRawOptions['expandResponses']) {
if (value === 'all') { if (value === 'all') {
@ -177,6 +188,7 @@ export class RedocNormalizedOptions {
allowedMdComponents: Record<string, MDXComponentMeta>; allowedMdComponents: Record<string, MDXComponentMeta>;
expandDefaultServerVariables: boolean; expandDefaultServerVariables: boolean;
maxDisplayedEnumValues?: number;
constructor(raw: RedocRawOptions, defaults: RedocRawOptions = {}) { constructor(raw: RedocRawOptions, defaults: RedocRawOptions = {}) {
raw = { ...defaults, ...raw }; raw = { ...defaults, ...raw };
@ -232,5 +244,6 @@ export class RedocNormalizedOptions {
this.allowedMdComponents = raw.allowedMdComponents || {}; this.allowedMdComponents = raw.allowedMdComponents || {};
this.expandDefaultServerVariables = argValueToBoolean(raw.expandDefaultServerVariables); this.expandDefaultServerVariables = argValueToBoolean(raw.expandDefaultServerVariables);
this.maxDisplayedEnumValues = argValueToNumber(raw.maxDisplayedEnumValues);
} }
} }