Skip to content

Commit b61cb12

Browse files
author
Brendan Abbott
committed
PR feedback, abstract constraints away from UI
1 parent da2e75a commit b61cb12

28 files changed

+570
-772
lines changed

src/components/ArrayProperty/ArrayProperty.js

Lines changed: 0 additions & 53 deletions
This file was deleted.

src/components/NumericProperty/NumericProperty.js

Lines changed: 0 additions & 58 deletions
This file was deleted.

src/components/ObjectProperty/ObjectProperty.js

Lines changed: 0 additions & 48 deletions
This file was deleted.

src/components/Property/Property.js

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,9 @@ import React, { Component } from 'react';
22
import classNames from 'classnames';
33
import PropTypes from 'prop-types';
44

5-
import ArrayProperty from '../ArrayProperty/ArrayProperty';
65
import Description from '../Description/Description';
76
import Indicator from '../Indicator/Indicator';
8-
import NumericProperty from '../NumericProperty/NumericProperty';
9-
import ObjectProperty from '../ObjectProperty/ObjectProperty';
10-
import StringProperty from '../StringProperty/StringProperty';
7+
import PropertyConstraints from '../PropertyConstraints/PropertyConstraints';
118

129
import './Property.scss';
1310

@@ -43,21 +40,15 @@ export default class Property extends Component {
4340
'property--isclickable': isClickable
4441
})}>
4542
<span>{name}</span>
46-
{isClickable &&
47-
<Indicator className="property-indicator" status={status}/>
48-
}
43+
{isClickable && <Indicator className="property-indicator" status={status}/>}
4944
</td>
5045
<td className="property-info">
5146
<span className="property-type">
5247
{!subtype ? type.join(', ') : <span className="property-subtype">{subtype}[]</span>}
5348
{!subtype && constraints && constraints.format &&
5449
<span className="property-format">&lt;{constraints.format}&gt;</span>}
5550
</span>
56-
{isRequired && <span className="property-required">Required</span>}
57-
{['number', 'integer'].some(t => type.includes(t)) && <NumericProperty constraints={constraints} />}
58-
{type.includes('string') && <StringProperty constraints={constraints} />}
59-
{type.includes('array') && <ArrayProperty constraints={constraints} />}
60-
{type.includes('object') && <ObjectProperty constraints={constraints} />}
51+
<PropertyConstraints constraints={constraints} type={type} isRequired={isRequired} />
6152
{enumValues && this.renderEnumValues(enumValues)}
6253
{defaultValue !== undefined && this.renderDefaultValue(defaultValue)}
6354
{description && <Description description={description}/>}
@@ -96,9 +87,8 @@ export default class Property extends Component {
9687
}
9788

9889
return (
99-
<div>
100-
<span>Default: </span>
101-
<span className="default">{displayValue}</span>
90+
<div className="default">
91+
Default: <span>{displayValue}</span>
10292
</div>
10393
);
10494
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import React, { PureComponent } from 'react';
2+
import PropTypes from 'prop-types';
3+
4+
import { getConstraintHints as getArrayHints } from './../../parser/open-api/constraints/array';
5+
import { getConstraintHints as getNumericHints } from './../../parser/open-api/constraints/numeric';
6+
import { getConstraintHints as getObjectHints } from './../../parser/open-api/constraints/object';
7+
import { getConstraintHints as getStringHints } from './../../parser/open-api/constraints/string';
8+
9+
export default class PropertyConstraints extends PureComponent {
10+
render() {
11+
const { type, isRequired, constraints } = this.props;
12+
13+
return (
14+
<span className="property-constraints">
15+
{isRequired && <span className="property-required">required</span>}
16+
{constraints && ['number', 'integer'].some(t => type.includes(t)) && this.renderConstraints(constraints, 'numeric')}
17+
{constraints && type.includes('string') && this.renderConstraints(constraints, 'string')}
18+
{constraints && type.includes('array') && this.renderConstraints(constraints, 'array')}
19+
{constraints && type.includes('object') && this.renderConstraints(constraints, 'object')}
20+
</span>
21+
);
22+
}
23+
24+
/**
25+
* Renders validation hints for the given constraints and type.
26+
*
27+
* @param {object} constraints
28+
* @param {string} type
29+
*/
30+
renderConstraints(constraints, type) {
31+
let validations = [];
32+
33+
switch (type) {
34+
case 'numeric':
35+
validations = getNumericHints(constraints);
36+
break;
37+
case 'object':
38+
validations = getObjectHints(constraints);
39+
break;
40+
case 'array':
41+
validations = getArrayHints(constraints);
42+
break;
43+
case 'string':
44+
default:
45+
validations = getStringHints(constraints);
46+
}
47+
48+
if (!validations.length) {
49+
return null;
50+
}
51+
52+
return (
53+
<span>
54+
{validations.map(constraint =>
55+
<span key={constraint} className={`${type}-constraints`}>{constraint}</span>
56+
)}
57+
</span>
58+
);
59+
}
60+
}
61+
62+
PropertyConstraints.propTypes = {
63+
type: PropTypes.arrayOf(PropTypes.string).isRequired,
64+
isRequired: PropTypes.bool.isRequired,
65+
constraints: PropTypes.shape({
66+
format: PropTypes.string,
67+
exclusiveMinimum: PropTypes.number,
68+
exclusiveMaximum: PropTypes.number,
69+
maximum: PropTypes.number,
70+
maxItems: PropTypes.number,
71+
maxLength: PropTypes.number,
72+
maxProperties: PropTypes.number,
73+
minimum: PropTypes.number,
74+
minItems: PropTypes.number,
75+
minLength: PropTypes.number,
76+
minProperties: PropTypes.number,
77+
multipleOf: PropTypes.number,
78+
pattern: PropTypes.string,
79+
uniqueItems: PropTypes.bool
80+
})
81+
};

src/components/StringProperty/StringProperty.js

Lines changed: 0 additions & 53 deletions
This file was deleted.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Returns an array of hints that relate to the constraints for an array,
3+
* `maxItems`, `minItems` and `uniqueItems`.
4+
*
5+
* @param {object} constraints
6+
* @return {array}
7+
*/
8+
export function getConstraintHints(constraints) {
9+
if (!constraints) {
10+
return [];
11+
}
12+
13+
const { maxItems, minItems, uniqueItems } = constraints;
14+
const validations = [];
15+
16+
if (uniqueItems) {
17+
validations.push('unique items');
18+
}
19+
20+
if (maxItems !== undefined && minItems !== undefined) {
21+
// Be succint if the minItems is the same maxItems
22+
// ie. value can only be of `x` length.
23+
if (maxItems === minItems) {
24+
validations.push(`${minItems} items`);
25+
} else {
26+
validations.push(`${minItems}-${maxItems} items`);
27+
}
28+
} else if (minItems !== undefined) {
29+
validations.push(`at least ${minItems} items`);
30+
} else if (maxItems !== undefined) {
31+
validations.push(`at most ${maxItems} items`);
32+
}
33+
34+
return validations;
35+
}

0 commit comments

Comments
 (0)