Skip to content

Commit c7dd597

Browse files
committed
Handle recursive oneOf-based schemas.
* Re-structure combinator renderers, so that subschemas are passed to sub-sequent JsonForms calls * Fix path of oneOf renderer * Use title property if available for displaying oneOf subschemas * Consistent usage of schema & rootSchema, remove scopedSchema prop * Refactor mapStateToFieldProps
1 parent 8b04d3c commit c7dd597

File tree

63 files changed

+1836
-1425
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1836
-1425
lines changed

packages/angular-material/src/other/master-detail/master.ts

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@ import { Component } from '@angular/core';
44
import { JsonFormsControl } from '@jsonforms/angular';
55
import { NgRedux } from '@angular-redux/store';
66
import {
7+
ArrayControlProps,
78
ControlElement,
8-
ControlProps,
99
JsonFormsState,
1010
mapDispatchToArrayControlProps,
11+
mapStateToArrayControlProps,
1112
RankedTester,
1213
rankWith,
13-
resolveSchema,
14-
toDataPath,
1514
uiTypeIs
1615
} from '@jsonforms/core';
1716

@@ -109,7 +108,8 @@ export class MasterListComponent extends JsonFormsControl {
109108
masterItems: any[];
110109
selectedItem: any;
111110
selectedItemIdx: number;
112-
addItem: (path: string) => () => void;
111+
addItem: (path: string, value: any) => () => void;
112+
createDefaultValue: () => void;
113113
removeItems: (path: string, toDelete: any[]) => () => void;
114114
propsPath: string;
115115
highlightedIdx: number;
@@ -129,29 +129,21 @@ export class MasterListComponent extends JsonFormsControl {
129129
ngOnInit() {
130130
super.ngOnInit();
131131
const { addItem, removeItems } = mapDispatchToArrayControlProps(
132-
this.ngRedux.dispatch,
133-
{
134-
uischema: this.uischema as ControlElement,
135-
schema: this.schema
136-
}
132+
this.ngRedux.dispatch
137133
);
138134
this.addItem = addItem;
139135
this.removeItems = removeItems;
140136
}
141137

142-
mapAdditionalProps(props: ControlProps) {
143-
const { data, schema, uischema } = props;
138+
mapAdditionalProps(props: ArrayControlProps) {
139+
const { data, path, schema, uischema, createDefaultValue } = props;
144140
const controlElement = uischema as ControlElement;
145-
const instancePath = toDataPath(`${controlElement.scope}/items`);
146141
this.propsPath = props.path;
147-
const resolvedSchema = resolveSchema(
148-
schema,
149-
`${controlElement.scope}/items`
150-
);
142+
this.createDefaultValue = createDefaultValue;
151143
const detailUISchema =
152144
controlElement.options.detail ||
153145
props.findUISchema(
154-
resolvedSchema,
146+
schema,
155147
`${controlElement.scope}/items`,
156148
props.path,
157149
'VerticalLayout'
@@ -164,8 +156,8 @@ export class MasterListComponent extends JsonFormsControl {
164156
const masterItem = {
165157
label: get(d, labelRefInstancePath),
166158
data: d,
167-
path: `${instancePath}.${index}`,
168-
schema: resolvedSchema,
159+
path: `${path}.${index}`,
160+
schema,
169161
uischema: detailUISchema
170162
};
171163
return masterItem;
@@ -210,12 +202,18 @@ export class MasterListComponent extends JsonFormsControl {
210202
}
211203

212204
onAddClick() {
213-
this.addItem(this.propsPath)();
205+
this.addItem(this.propsPath, this.createDefaultValue())();
214206
}
215207

216208
onDeleteClick(item: any) {
217209
this.removeItems(this.propsPath, [item.data])();
218210
}
211+
212+
protected mapToProps(state: JsonFormsState): ArrayControlProps {
213+
const props = mapStateToArrayControlProps(state, this.getOwnProps());
214+
const dispatch = mapDispatchToArrayControlProps(this.ngRedux.dispatch);
215+
return { ...props, ...dispatch };
216+
}
219217
}
220218

221219
export const masterDetailTester: RankedTester = rankWith(

packages/angular-material/src/other/object.renderer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export class ObjectControlRenderer extends JsonFormsControl {
5454
}
5555
mapAdditionalProps(props: ControlProps) {
5656
this.detailUiSchema = props.findUISchema(
57-
props.scopedSchema,
57+
props.schema,
5858
undefined,
5959
props.path
6060
);

packages/angular-material/test/master-detail.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ describe('Master detail', () => {
469469
title: 'Carrots'
470470
},
471471
path: 'orders.0',
472-
schema: undefined,
472+
schema: schema.definitions.order,
473473
uischema: {
474474
type: 'VerticalLayout',
475475
elements: [

packages/angular/src/control.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ import {
99
JsonSchema,
1010
mapDispatchToControlProps,
1111
mapStateToControlProps,
12-
OwnPropsOfControl,
13-
Resolve
12+
OwnPropsOfControl
1413
} from '@jsonforms/core';
1514
import { Input, OnDestroy, OnInit } from '@angular/core';
1615
import { NgRedux } from '@angular-redux/store';
@@ -37,6 +36,7 @@ export class JsonFormsControl extends JsonFormsBaseRenderer<ControlElement>
3736
description: string;
3837
error: string | null;
3938
scopedSchema: JsonSchema;
39+
rootSchema: JsonSchema;
4040
enabled: boolean;
4141
hidden: boolean;
4242

@@ -74,7 +74,7 @@ export class JsonFormsControl extends JsonFormsBaseRenderer<ControlElement>
7474
label,
7575
required,
7676
schema,
77-
uischema,
77+
rootSchema,
7878
visible
7979
} = props;
8080
this.label = computeLabel(
@@ -86,7 +86,8 @@ export class JsonFormsControl extends JsonFormsBaseRenderer<ControlElement>
8686
this.enabled = enabled;
8787
this.enabled ? this.form.enable() : this.form.disable();
8888
this.hidden = !visible;
89-
this.scopedSchema = Resolve.schema(schema, uischema.scope);
89+
this.scopedSchema = schema;
90+
this.rootSchema = rootSchema;
9091
this.description =
9192
this.scopedSchema !== undefined ? this.scopedSchema.description : '';
9293
this.id = props.id;

packages/core/src/testers/index.ts

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,7 @@ export type RankedTester = (
5959
) => number;
6060

6161
export const isControl = (uischema: any): uischema is ControlElement =>
62-
!isEmpty(uischema) &&
63-
uischema.scope !== undefined &&
64-
uischema.scope !== undefined;
62+
!isEmpty(uischema) && uischema.scope !== undefined;
6563

6664
/**
6765
* Only applicable for Controls.
@@ -79,13 +77,16 @@ export const schemaMatches = (
7977
if (isEmpty(uischema) || !isControl(uischema)) {
8078
return false;
8179
}
80+
if (isEmpty(schema)) {
81+
return false;
82+
}
8283
const schemaPath = uischema.scope;
8384
if (isEmpty(schemaPath)) {
8485
return false;
8586
}
86-
let currentDataSchema: JsonSchema = resolveSchema(schema, schemaPath);
87-
while (!isEmpty(currentDataSchema) && !isEmpty(currentDataSchema.$ref)) {
88-
currentDataSchema = resolveSchema(schema, currentDataSchema.$ref);
87+
let currentDataSchema = schema;
88+
if (schema.type === 'object') {
89+
currentDataSchema = resolveSchema(schema, schemaPath);
8990
}
9091
if (currentDataSchema === undefined) {
9192
return false;
@@ -102,12 +103,9 @@ export const schemaSubPathMatches = (
102103
return false;
103104
}
104105
const schemaPath = uischema.scope;
105-
if (isEmpty(schemaPath)) {
106-
return false;
107-
}
108-
let currentDataSchema: JsonSchema = resolveSchema(schema, `${schemaPath}`);
109-
while (!isEmpty(currentDataSchema.$ref)) {
110-
currentDataSchema = resolveSchema(schema, currentDataSchema.$ref);
106+
let currentDataSchema: JsonSchema;
107+
if (schema.type === 'object') {
108+
currentDataSchema = resolveSchema(schema, schemaPath);
111109
}
112110
currentDataSchema = get(currentDataSchema, subPath);
113111

@@ -422,10 +420,7 @@ export const isObjectArrayWithNesting = (
422420
return false;
423421
}
424422
wantedNestingByType[val.type] = typeCount - 1;
425-
if (wantedNestingByType[val.type] === 0) {
426-
return true;
427-
}
428-
return false;
423+
return wantedNestingByType[val.type] === 0;
429424
})
430425
) {
431426
return true;
@@ -457,13 +452,14 @@ export const isArrayObjectControl = isObjectArrayControl;
457452
*/
458453
export const isPrimitiveArrayControl = and(
459454
uiTypeIs('Control'),
460-
schemaMatches(
461-
schema =>
455+
schemaMatches(schema => {
456+
return (
462457
!isEmpty(schema) &&
463458
schema.type === 'array' &&
464459
!isEmpty(schema.items) &&
465-
!Array.isArray(schema.items) // we don't care about tuples
466-
),
460+
!Array.isArray(schema.items)
461+
); // we don't care about tuples
462+
}),
467463
schemaSubPathMatches('items', schema =>
468464
includes(['integer', 'number', 'boolean', 'string'], schema.type)
469465
)

packages/core/src/util/field.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,14 @@ import isEmpty from 'lodash/isEmpty';
2626
import has from 'lodash/has';
2727
import cloneDeep from 'lodash/cloneDeep';
2828
import merge from 'lodash/merge';
29-
import { ControlElement } from '../models/uischema';
30-
import { findUISchema, getConfig, getData, getErrorAt } from '../reducers';
3129
import {
32-
composeWithUi,
30+
findUISchema,
31+
getConfig,
32+
getData,
33+
getErrorAt,
34+
getSchema
35+
} from '../reducers';
36+
import {
3337
isEnabled,
3438
isVisible,
3539
OwnPropsOfControl,
@@ -42,6 +46,7 @@ import { DispatchPropsOfControl, mapDispatchToControlProps } from './renderer';
4246
import { JsonFormsState } from '../store';
4347
import { AnyAction, Dispatch } from 'redux';
4448
import { JsonFormsFieldRendererRegistryEntry } from '../reducers/fields';
49+
import { JsonSchema } from '..';
4550

4651
export { JsonFormsFieldRendererRegistryEntry };
4752

@@ -54,6 +59,7 @@ export interface OwnPropsOfField extends OwnPropsOfControl {
5459
*/
5560
export interface StatePropsOfField extends StatePropsOfScopedRenderer {
5661
isValid: boolean;
62+
rootSchema: JsonSchema;
5763
}
5864

5965
export interface OwnPropsOfEnumField extends OwnPropsOfField, OwnPropsOfEnum {}
@@ -99,7 +105,7 @@ export const mapStateToFieldProps = (
99105
state: JsonFormsState,
100106
ownProps: OwnPropsOfField
101107
): StatePropsOfField => {
102-
const path = composeWithUi(ownProps.uischema, ownProps.path);
108+
const { id, schema, path, uischema } = ownProps;
103109
const visible = has(ownProps, 'visible')
104110
? ownProps.visible
105111
: isVisible(ownProps, state);
@@ -108,27 +114,23 @@ export const mapStateToFieldProps = (
108114
: isEnabled(ownProps, state);
109115
const errors = getErrorAt(path)(state).map(error => error.message);
110116
const isValid = isEmpty(errors);
111-
const controlElement = ownProps.uischema as ControlElement;
112-
const id = ownProps.id;
113117
const defaultConfig = cloneDeep(getConfig(state));
114118
const config = merge(defaultConfig, ownProps.uischema.options);
119+
const rootSchema = getSchema(state);
115120

116121
return {
117-
data:
118-
ownProps.data !== undefined
119-
? Resolve.data(ownProps.data, path)
120-
: Resolve.data(getData(state), path),
122+
data: Resolve.data(getData(state), path),
121123
visible,
122124
enabled,
123125
id,
124126
path,
125127
errors,
126128
isValid,
127-
scopedSchema: Resolve.schema(ownProps.schema, controlElement.scope),
128-
uischema: ownProps.uischema,
129-
schema: ownProps.schema,
129+
schema,
130+
uischema,
130131
config,
131-
findUISchema: findUISchema(state)
132+
findUISchema: findUISchema(state),
133+
rootSchema
132134
};
133135
};
134136

@@ -160,7 +162,7 @@ export const defaultMapStateToEnumFieldProps = (
160162
): StatePropsOfEnumField => {
161163
const props: StatePropsOfField = mapStateToFieldProps(state, ownProps);
162164
const options =
163-
ownProps.options !== undefined ? ownProps.options : props.scopedSchema.enum;
165+
ownProps.options !== undefined ? ownProps.options : props.schema.enum;
164166
return {
165167
...props,
166168
options

packages/core/src/util/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,11 @@ export const formatErrorMessage = (errors: string[]) => {
6161
* Convenience wrapper around resolveData and resolveSchema.
6262
*/
6363
const Resolve: {
64-
schema(schema: JsonSchema, schemaPath: string): JsonSchema;
64+
schema(
65+
schema: JsonSchema,
66+
schemaPath: string,
67+
rootSchema?: JsonSchema
68+
): JsonSchema;
6569
data(data: any, path: string): any;
6670
} = {
6771
schema: resolveSchema,

0 commit comments

Comments
 (0)