Skip to content
This repository was archived by the owner on Nov 28, 2022. It is now read-only.

Commit 8e95e2a

Browse files
authored
If the explorer is disabled, ArrayField components should be addable but uneditable (#259)
* If the explorer is disabled, ArrayFields should be addable but uneditable. * After a user has clicked a readOnly ArrayField, make it unaddable. * Arrays of primitives can no longer be expanded if in read-only mode. * Re-enabling the explorer on the `types` example.
1 parent 70909b5 commit 8e95e2a

File tree

3 files changed

+74
-12
lines changed

3 files changed

+74
-12
lines changed

example/swagger-files/types.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,23 @@
143143
"type": "string"
144144
}
145145
},
146-
"array (with a $ref)": {
146+
"array (of strings, loaded via a $ref)": {
147147
"type": "array",
148148
"items": {
149149
"$ref": "#/components/schemas/string_enum"
150150
}
151151
},
152+
"array (of objects)": {
153+
"type": "array",
154+
"items": {
155+
"type": "object",
156+
"properties": {
157+
"string": {
158+
"type": "string"
159+
}
160+
}
161+
}
162+
},
152163
"object": {
153164
"type": "object",
154165
"description": "This is an object with a description",

packages/api-explorer/__tests__/Params.test.jsx

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -219,16 +219,31 @@ describe('x-explorer-enabled', () => {
219219
const oasWithExplorerDisabled = Object.assign({}, oas, { [extensions.EXPLORER_ENABLED]: false });
220220
const ParamsWithExplorerDisabled = createParams(oasWithExplorerDisabled);
221221

222-
test('array should not show add button', () => {
222+
test('array should still show add button, but sub-elements should not be editable', () => {
223+
const elem = mount(
224+
<ParamsWithExplorerDisabled
225+
{...props}
226+
oas={new Oas(oasWithExplorerDisabled)}
227+
operation={oas.operation('/pet', 'post')}
228+
/>,
229+
);
230+
231+
expect(elem.find('.field-array .array-item-add').length).toBe(2);
232+
233+
elem
234+
.find('.field-array .array-item-add')
235+
.at(0)
236+
.simulate('click');
237+
238+
// Assert that after we've clicked to add array items into the view, everything is still in
239+
// readOnly mode.
240+
expect(elem.find('input').length).toBe(1);
223241
expect(
224-
mount(
225-
<ParamsWithExplorerDisabled
226-
{...props}
227-
oas={new Oas(oasWithExplorerDisabled)}
228-
operation={oas.operation('/pet', 'post')}
229-
/>,
230-
).find('.field-array .array-item-add').length,
231-
).toBe(0);
242+
elem
243+
.find('input')
244+
.at(0)
245+
.props().type,
246+
).toBe('hidden');
232247
});
233248

234249
test('should not render any <input>', () => {

packages/api-explorer/src/form-components/ArrayField.jsx

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,60 @@ const PropTypes = require('prop-types');
33
const extensions = require('@readme/oas-extensions');
44

55
const BaseArrayField = require('react-jsonschema-form/lib/components/fields/ArrayField').default;
6+
const { getDefaultRegistry, retrieveSchema } = require('react-jsonschema-form/lib/utils');
67

78
function createArrayField(oas) {
89
const explorerEnabled = oas[extensions.EXPLORER_ENABLED];
910

11+
function hasPrimitives(props) {
12+
const { schema, registry = getDefaultRegistry() } = props;
13+
const { definitions } = registry;
14+
const itemsSchema = retrieveSchema(schema.items, definitions);
15+
16+
return itemsSchema.type !== 'array' && itemsSchema.type !== 'object';
17+
}
18+
1019
function ArrayField(props) {
1120
let uiSchema;
1221
if (!explorerEnabled) {
13-
// https://github.com/mozilla-services/react-jsonschema-form#addable-option
14-
uiSchema = Object.assign(props.uiSchema, { 'ui:options': { addable: false } });
22+
const uiOptions = {
23+
readOnly: true,
24+
addable: true,
25+
};
26+
27+
// Two scenarios are accounted for here: if the array contains only primitives, and if the
28+
// user has added a new entry within this ArrayField. For both scenarios, we want to disable
29+
// any future entires from being added while the explorer is in readOnly mode.
30+
//
31+
// Why? If the array contains only primitives, expanding the array will result in a less than
32+
// ideal UX of empty whitespace being added into view. As for if the user has already added
33+
// an item into view, we want to disable further items from being added as since the explorer
34+
// is in read-only mode, adding more items into view will just clutter up the view for the
35+
// user.
36+
//
37+
// https://github.com/readmeio/api-explorer/pull/259#pullrequestreview-272110359
38+
if (hasPrimitives(props)) {
39+
uiOptions.addable = false;
40+
} else if (props.formData.length > 0) {
41+
uiOptions.addable = false;
42+
}
43+
44+
uiSchema = Object.assign(props.uiSchema, { 'ui:options': uiOptions });
1545
}
1646

1747
return <BaseArrayField {...props} uiSchema={uiSchema || props.uiSchema} />;
1848
}
1949

2050
ArrayField.propTypes = {
51+
// eslint-disable-next-line react/forbid-prop-types
52+
formData: PropTypes.any,
2153
uiSchema: PropTypes.shape({}).isRequired,
2254
};
2355

56+
ArrayField.defaultProps = {
57+
formData: [],
58+
};
59+
2460
return ArrayField;
2561
}
2662

0 commit comments

Comments
 (0)