Skip to content

Commit

Permalink
enable nested map and remove custom converter
Browse files Browse the repository at this point in the history
  • Loading branch information
YingXue committed Mar 10, 2023
1 parent 3deab0f commit 25364af
Show file tree
Hide file tree
Showing 16 changed files with 753 additions and 775 deletions.
624 changes: 624 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
"@fluentui/react": "8.101.2",
"@microsoft/applicationinsights-web": "2.8.4",
"@rjsf/fluent-ui": "5.2.1",
"@rjsf/material-ui": "5.2.1",
"@rjsf/validator-ajv8": "5.2.1",
"azure-iot-common": "1.12.14",
"azure-iothub": "1.16.1",
Expand Down
4 changes: 2 additions & 2 deletions src/app/api/models/interfaceJsonParserOutput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
* Licensed under the MIT License
**********************************************************/
export interface ParsedJsonSchema {
required: string[];
required?: string[];

additionalProperties?: boolean; // use this props as a workaround to indicate whether parsed property is map type
additionalProperties?: ParsedJsonSchema;
default?: {};
definitions?: any; // tslint:disable-line: no-any
description?: string;
Expand Down
2 changes: 1 addition & 1 deletion src/app/devices/deviceEvents/components/eventsContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ export const EventsContent: React.FC<EventsContentProps> = ({showSystemPropertie
};

const renderMessageBodyWithValueValidation = (eventBody: any, schema: ParsedJsonSchema, key: string) => { // tslint:disable-line:no-any
const errors = getSchemaValidationErrors(eventBody[key], schema, true);
const errors = getSchemaValidationErrors(eventBody[key], schema);

return (
<div className="column-value-text col-sm4">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,29 +107,13 @@ exports[`components/devices/deviceProperties matches snapshot with one twinWithS
"definitions": Object {},
"properties": Object {
"interfaces": Object {
"additionalProperties": true,
"items": Object {
"description": "Key of the map is: name",
"properties": Object {
"name": Object {
"pattern": "^[a-zA-Z](?:[a-zA-Z0-9_]*[a-zA-Z0-9])?$",
"type": "string",
},
"schema": Object {
"required": Array [],
"title": "schema",
"type": "string",
},
},
"required": Array [
"name",
"schema",
],
"type": "object",
"additionalProperties": Object {
"required": Array [],
"type": "string",
},
"required": Array [],
"description": "key's name: name, value's name: schema",
"title": "interfaces",
"type": "array",
"type": "object",
},
"modelId": Object {
"required": Array [],
Expand Down
2 changes: 1 addition & 1 deletion src/app/devices/pnp/sagas/invokeCommandSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,6 @@ export function* notifyMethodInvoked(toastId: number, action: Action<InvokeComma
}

const getValidationResult = (response: any, schema: ParsedJsonSchema) => { // tslint:disable-line:no-any
const errors = getSchemaValidationErrors(response?.payload, schema, true);
const errors = getSchemaValidationErrors(response?.payload, schema);
return errors.length !== 0 ? errors.map(element => element.message).join(', ') : null;
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ exports[`complexReportedFormPanel matches snapshot without twinWithSchema 1`] =
isLightDismiss={true}
isOpen={false}
onDismiss={[MockFunction]}
type={3}
type={4}
>
<div
className="panel-title"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ exports[`dataForm matches snapshot with simple type 1`] = `
schema={
Object {
"description": "Brightness Level / The brightness level for the light on the device. Can be specified as 1 (high), 2 (medium), 3 (low)",
"required": null,
"required": Array [],
"title": "brightness",
"type": "number",
}
Expand Down Expand Up @@ -3532,32 +3532,3 @@ exports[`dataForm matches snapshot with simple type 1`] = `
</ErrorBoundary>
</Fragment>
`;

exports[`dataForm matches snapshot with unsupported type 1`] = `
<Fragment>
<form
className="json-editor"
>
<LabelWithTooltip
tooltipText="notifications.interfaceSchemaNotSupported"
>
deviceContent.value
</LabelWithTooltip>
<JSONEditor
className="json-editor"
content="123"
onChange={[Function]}
/>
<CustomizedPrimaryButton
className="submit-button"
disabled={false}
iconProps={
Object {
"iconName": "CloudUpload",
}
}
text="text"
/>
</form>
</Fragment>
`;
65 changes: 34 additions & 31 deletions src/app/devices/shared/components/complexReportedFormPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,15 @@
import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { Label, Panel, PanelType } from '@fluentui/react';
import Form from '@rjsf/fluent-ui';
import { Form as MaterialForm } from '@rjsf/material-ui';
import { Form as FluentForm } from '@rjsf/fluent-ui';
import validator from '@rjsf/validator-ajv8';
import { ResourceKeys } from '../../../../localization/resourceKeys';
import { ParsedJsonSchema } from '../../../api/models/interfaceJsonParserOutput';
import { twinToFormDataConverter } from '../../../shared/utils/twinAndJsonSchemaDataConverter';
import { PropertyContent } from '../../../api/models/modelDefinition';
import { ErrorBoundary } from './errorBoundary';
import { getLocalizedData } from '../../../api/dataTransforms/modelDefinitionTransform';
import { JSONEditor } from '../../../shared/components/jsonEditor';
import { getSchemaType } from '../../../shared/utils/jsonSchemaAdaptor';
import { containsMapsInSchema } from './dataForm';

export interface ReportedFormDataProps {
showPanel: boolean;
Expand All @@ -29,11 +28,7 @@ export interface ReportedFormActionProps {

export const ComplexReportedFormPanel: React.FC<ReportedFormDataProps & ReportedFormActionProps> = (props: ReportedFormDataProps & ReportedFormActionProps) => {
const { t } = useTranslation();

const { schema, modelDefinition, showPanel } = props;
const twinData = twinToFormDataConverter(props.formData, schema);
const formData = twinData.formData;
const parsingSchemaFailed = React.useMemo(() => twinData.error || !schema || (!schema.type && !schema.$ref), [twinData, schema]);
const { modelDefinition, showPanel, formData } = props;

const createTitle = () => {
const displayName = getLocalizedData(modelDefinition.displayName);
Expand All @@ -46,38 +41,46 @@ export const ComplexReportedFormPanel: React.FC<ReportedFormDataProps & Reported
};

const createForm = () => {
if (parsingSchemaFailed) { // Not able to parse interface definition, render raw json editor instead
return createJsonEditor();
const uiSchema: any = {'ui:description': props.schema?.description, 'ui:disabled': true}; // tslint:disable-line: no-any
let form: JSX.Element;
if (containsMapsInSchema(props.schema)) { // FluentForm does not support map (additionalProperties yet)
form = (
<MaterialForm
formData={formData}
liveValidate={true}
schema={props.schema as any} // tslint:disable-line: no-any
showErrorList={false}
uiSchema={uiSchema}
validator={validator}
>
<br/>
</MaterialForm>
);
}
else {
return (
<ErrorBoundary error={t(ResourceKeys.errorBoundary.text)}>
<Form
formData={formData}
liveValidate={true}
schema={props.schema as any} // tslint:disable-line: no-any
showErrorList={false}
uiSchema={{'ui:description': props.schema.description, 'ui:disabled': true}}
validator={validator}
>
<br/>
</Form>
</ErrorBoundary>
form = (
<FluentForm
formData={formData}
liveValidate={true}
schema={props.schema as any} // tslint:disable-line: no-any
showErrorList={false}
uiSchema={uiSchema}
validator={validator}
>
<br/>
</FluentForm>
);
}
};

const createJsonEditor = () => {
return (
<form>
<Label>{t(ResourceKeys.deviceProperties.editor.label, {schema: getSchemaType(modelDefinition.schema)})}</Label>
<JSONEditor className="json-editor" content={JSON.stringify(formData, null, '\t')}/>
</form>
<ErrorBoundary error={t(ResourceKeys.errorBoundary.text)}>
{form}
</ErrorBoundary>
);
};

return (
<Panel isOpen={showPanel} onDismiss={props.handleDismiss} type={PanelType.medium} isLightDismiss={true}>
<Panel isOpen={showPanel} onDismiss={props.handleDismiss} type={PanelType.large} isLightDismiss={true}>
{createTitle()}
{createForm()}
</Panel>
Expand Down
12 changes: 1 addition & 11 deletions src/app/devices/shared/components/dataForm.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ describe('dataForm', () => {
const formData = 123;
const settingSchema = {
description: 'Brightness Level / The brightness level for the light on the device. Can be specified as 1 (high), 2 (medium), 3 (low)',
required: null,
required: [],
title: 'brightness',
type: 'number'
};
Expand All @@ -25,7 +25,6 @@ describe('dataForm', () => {
};

const dataFormDispatchProps: DataFormActionProps = {
craftPayload: jest.fn(),
handleSave: jest.fn()
};

Expand All @@ -45,13 +44,4 @@ describe('dataForm', () => {
const wrapper = mount(getComponent());
expect(wrapper.find(Form)).toBeDefined();
});

it('matches snapshot with unsupported type', () => {
expect(shallow(getComponent({
settingSchema: undefined
}))).toMatchSnapshot();

const wrapper = mount(getComponent());
expect(wrapper.find('div.json-editor')).toBeDefined();
});
});
Loading

0 comments on commit 25364af

Please sign in to comment.