From 1706d075bf55aae0154a813e76683446d2eeaa11 Mon Sep 17 00:00:00 2001 From: Amirhossein Alibakhshi Date: Fri, 21 Jun 2024 19:42:38 +0330 Subject: [PATCH] fix: implement enum --- src/components/AddFieldModal.tsx | 15 +++++- src/components/FieldPreview.tsx | 9 ++++ src/components/SchemaPreview.tsx | 71 ++++++++++++++------------- src/fields/JsonSchemaField.ts | 55 ++++++++++++++++++++- src/stories/SchemaBuilder.stories.tsx | 15 ++++++ src/utils.ts | 2 +- 6 files changed, 128 insertions(+), 39 deletions(-) diff --git a/src/components/AddFieldModal.tsx b/src/components/AddFieldModal.tsx index 9d46d37..3cff384 100644 --- a/src/components/AddFieldModal.tsx +++ b/src/components/AddFieldModal.tsx @@ -1,4 +1,15 @@ -import {Box, Button, Dialog, FormControl, IconButton, InputLabel, MenuItem, Stack, TextField,} from "@mui/material"; +import { + Box, + Button, + Dialog, + FormControl, + IconButton, + InputLabel, + MenuItem, + Stack, + TextField, + Tooltip, +} from "@mui/material"; import Form from "@rjsf/mui"; import validator from "@rjsf/validator-ajv8"; @@ -61,7 +72,7 @@ const AddFieldModal = ({ parentPath }) => { return ( <> - setOpen(true)}> + setOpen(true)}> setOpen(false)}>

{step !== 0 && }Adding Field

diff --git a/src/components/FieldPreview.tsx b/src/components/FieldPreview.tsx index 7148571..1026a1a 100644 --- a/src/components/FieldPreview.tsx +++ b/src/components/FieldPreview.tsx @@ -76,6 +76,15 @@ FieldPreview.String = function String({schema, data, name}: DataVisualizationTyp ); }; +FieldPreview.Enum = function Enum({schema, data, name}: DataVisualizationType) { + return ( + + {schema?.title} + {data || '-'} + + ); +}; + FieldPreview.Number = function Number({schema, name, data}: DataVisualizationType) { return ( diff --git a/src/components/SchemaPreview.tsx b/src/components/SchemaPreview.tsx index 574d2b3..7e8a47e 100644 --- a/src/components/SchemaPreview.tsx +++ b/src/components/SchemaPreview.tsx @@ -20,9 +20,9 @@ import { IconButton, ListItem, ListItemIcon, - ListItemText, Stack, + ListItemText, Paper, Stack, Tooltip, - Typography + Typography, useTheme } from "@mui/material"; import {generatePath, getFieldId, getSchemaFormatFromSchema} from "../utils"; import {DataVisualizationType} from "../types"; @@ -148,16 +148,14 @@ const handleEdit = (dispatch: React.Dispatch, name: string, schema const SchemaPreview = ({schema, data, name, path}: Props) => { const FormPreview = getSchemaFormatFromSchema(schema, SchemaPreview) return ( -
-
) }; SchemaPreview.String = function String({schema, path, data, name}: DataVisualizationType) { const {dispatch} = useSchema(); return ( -
+ {renderHeader({ description: schema.description, name, @@ -166,15 +164,15 @@ SchemaPreview.String = function String({schema, path, data, name}: DataVisualiza icon: , onDelete: () => handleDelete(dispatch, path) })} -
+ ); }; -SchemaPreview.Enum = function String({schema, path, data, name}: DataVisualizationType) { +SchemaPreview.Enum = function Enum({schema, path, data, name}: DataVisualizationType) { const {dispatch} = useSchema(); const enums = schema.enum return ( -
+ {renderHeader({ description: <>{schema.description} Options: {enums.map(e => ( ))}, @@ -184,14 +182,14 @@ SchemaPreview.Enum = function String({schema, path, data, name}: DataVisualizati icon: , onDelete: () => handleDelete(dispatch, path) })} -
+ ); }; SchemaPreview.Number = function Number({schema, path, name}: DataVisualizationType) { const {dispatch} = useSchema(); return ( -
+ {renderHeader({ description: schema.description, name, @@ -200,14 +198,14 @@ SchemaPreview.Number = function Number({schema, path, name}: DataVisualizationTy icon: , onDelete: () => handleDelete(dispatch, path) })} -
+ ); }; SchemaPreview.Boolean = function BooleanVisualization({schema, path, name}: DataVisualizationType) { const {dispatch} = useSchema(); return ( -
+ {renderHeader({ description: schema.description, name, @@ -216,7 +214,7 @@ SchemaPreview.Boolean = function BooleanVisualization({schema, path, name}: Data icon: , onDelete: () => handleDelete(dispatch, path) })} -
+ ); }; @@ -230,8 +228,10 @@ SchemaPreview.Object = function ObjectVisualization({schema, path, data, name}: setOpen(!open); }; + const theme = useTheme(); + return ( - + {renderHeader({ description: schema.description, name, @@ -242,7 +242,7 @@ SchemaPreview.Object = function ObjectVisualization({schema, path, data, name}: onCollapse: handleCollapse, onDelete: () => handleDelete(dispatch, path) })} - + Properties @@ -252,30 +252,32 @@ SchemaPreview.Object = function ObjectVisualization({schema, path, data, name}: }} - {properties?.length > 0 ? properties?.map((property) => ( - <> - - - )) : ( - - Click on button to add properties - - )} + + {properties?.length > 0 ? properties?.map((property) => ( + <> + + + )) : ( + + Click on button to add properties + + )} + - - + + ); }; SchemaPreview.Array = function ArrayVisualization({schema, path, data, name}: DataVisualizationType) { const {dispatch} = useSchema(); + const theme = useTheme(); return ( - <> - + {renderHeader({ description: schema.description, name, @@ -284,11 +286,12 @@ SchemaPreview.Array = function ArrayVisualization({schema, path, data, name}: Da icon: , onDelete: () => handleDelete(dispatch, path) })} + - - +
+ ); }; diff --git a/src/fields/JsonSchemaField.ts b/src/fields/JsonSchemaField.ts index a270016..7f42801 100644 --- a/src/fields/JsonSchemaField.ts +++ b/src/fields/JsonSchemaField.ts @@ -17,6 +17,11 @@ export class JsonSchemaField { protected writeOnly?: boolean; + protected enum?: string[]; + + protected enumNames?: string[]; + + constructor(name: string) { this.name = name; this.type = 'object'; @@ -46,6 +51,16 @@ export class JsonSchemaField { return this; } + setEnum(_enum: string[]): this { + this.enum = _enum; + return this; + } + + setEnumNames(enumNames: string[]): this { + this.enumNames = enumNames; + return this; + } + private setDefault(value: unknown): JsonSchemaField { this.default = value; return this; @@ -66,7 +81,12 @@ export class JsonSchemaField { return this; } - public setSchema(schema: SchemaAnnotation & { isRequired?: boolean }): void { + public setSchema(schema: SchemaAnnotation & { + isRequired?: boolean, options: { + enum: string; + enumNames: string; + }[] + }): void { if (schema.type) this.setType(schema.type) if (schema.title) this.setTitle(schema.title) if (schema.description) this.setDescription(schema.description) @@ -74,6 +94,14 @@ export class JsonSchemaField { if (schema.readOnly) this.setReadOnly(schema.readOnly) if (schema.writeOnly) this.setWriteOnly(schema.writeOnly) if (schema.isRequired) this.setIsRequired(schema.isRequired) + + const options = { + enum: schema.options?.map((option) => option.enum) || [], + enumNames: schema.options?.map((option) => option.enumNames) || [], + } + + if (options.enum?.length > 0) this.setEnum(options.enum) + if (options.enumNames?.length > 0) this.setEnumNames(options.enumNames) } @@ -84,7 +112,9 @@ export class JsonSchemaField { description: this.description, default: this.default, readOnly: this.readOnly, - writeOnly: this.writeOnly + writeOnly: this.writeOnly, + enum: this.enum, + enumNames: this.enumNames }; } @@ -121,6 +151,27 @@ export class JsonSchemaField { isRequired: { type: 'boolean', title: 'Field is required' + }, + options: { + type: "array", + title: "Options", + description: "Here you can add options for the select field", + items: { + type: "object", + properties: { + enum: { + type: this.getSchema()?.type || 'string', + title: "Value of the option", + description: "The value that is going to be in the form", + }, + enumNames: { + type: "string", + title: "Title of the option", + description: "The title that is going to be shown to user", + }, + }, + required: ["enum", "enumNames"], + } } }, required: ['title', 'type'], diff --git a/src/stories/SchemaBuilder.stories.tsx b/src/stories/SchemaBuilder.stories.tsx index f1843e0..6cfc26b 100644 --- a/src/stories/SchemaBuilder.stories.tsx +++ b/src/stories/SchemaBuilder.stories.tsx @@ -36,6 +36,21 @@ const sampleSchema: RJSFSchema = { "type": "number", "minimum": 0 }, + "location": { + "title": "Location", + "description": "The coordination.", + "type": "object", + properties: { + lat: { + type: 'number', + title: "latitude" + }, + long: { + type: 'number', + title: "longitude" + }, + } + }, "tags": { "title": "Tags", "description": "Tags associated with the item.", diff --git a/src/utils.ts b/src/utils.ts index 2d36833..f3d8ea4 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -22,6 +22,7 @@ export const getSchemaFormatFromSchema = ( Unknown({schema, data}: DataVisualizationType): JSX.Element; }, ) => { + if (schema?.enum?.length > 0) return SchemaFormat.Enum; if (schema?.type === 'boolean') return SchemaFormat.Boolean; // if (schema?.type === 'string' && schema?.format === 'image-url') return SchemaFormat.Image; // if (schema?.type === 'string' && schema?.format === 'video-url') return SchemaFormat.Video; @@ -30,7 +31,6 @@ export const getSchemaFormatFromSchema = ( // if (schema?.type === 'string' && schema?.ui?.widget === 'color') return SchemaFormat.Color; // if (schema?.format === 'date') return SchemaFormat.Date; // if (schema?.format === 'date-time') return SchemaFormat.DateTime; - if (schema?.type === 'string' && schema?.enum?.length > 0) return SchemaFormat.Enum; if (schema?.type === 'string') return SchemaFormat.String; if (schema?.type === 'number' || schema?.type === 'integer') return SchemaFormat.Number; if (schema?.type === 'object' && schema?.format === 'map') return SchemaFormat.Map;