Skip to content

Commit

Permalink
Merge pull request #11 from amir78729/fix/ui
Browse files Browse the repository at this point in the history
Fix/UI
  • Loading branch information
amir78729 authored Jun 21, 2024
2 parents b8cc53b + 1706d07 commit 27fbca6
Show file tree
Hide file tree
Showing 10 changed files with 288 additions and 47 deletions.
15 changes: 13 additions & 2 deletions src/components/AddFieldModal.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -61,7 +72,7 @@ const AddFieldModal = ({ parentPath }) => {

return (
<>
<IconButton onClick={() => setOpen(true)}><Add /></IconButton>
<Tooltip title="Add Property" arrow placement="left"><IconButton onClick={() => setOpen(true)}><Add /></IconButton></Tooltip>
<Dialog fullWidth open={open} onClose={() => setOpen(false)}>
<Box p={3} key={JSON.stringify(fields)}>
<h1>{step !== 0 && <Button onClick={() => setStep(0)}>back</Button>}Adding Field</h1>
Expand Down
9 changes: 9 additions & 0 deletions src/components/FieldPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ FieldPreview.String = function String({schema, data, name}: DataVisualizationTyp
);
};

FieldPreview.Enum = function Enum({schema, data, name}: DataVisualizationType) {
return (
<TableRow>
<TableCell>{schema?.title}</TableCell>
<TableCell>{data || '-'}</TableCell>
</TableRow>
);
};

FieldPreview.Number = function Number({schema, name, data}: DataVisualizationType) {
return (
<TableRow>
Expand Down
132 changes: 92 additions & 40 deletions src/components/SchemaPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {RJSFSchema} from "@rjsf/utils";
import AddFieldModal from "./AddFieldModal";
import Numbers from '@mui/icons-material/Numbers';
import {
Add,
Add, Checklist,
DataArray,
DataObject,
Delete,
Expand All @@ -20,9 +20,9 @@ import {
IconButton,
ListItem,
ListItemIcon,
ListItemText,
ListItemText, Paper, Stack,
Tooltip,
Typography
Typography, useTheme
} from "@mui/material";
import {generatePath, getFieldId, getSchemaFormatFromSchema} from "../utils";
import {DataVisualizationType} from "../types";
Expand All @@ -39,10 +39,12 @@ type Props = {
}

// TODO: refactor
const renderHeader = ({icon, schema, onDelete, name, path}: {
const renderHeader = ({icon, schema, onDelete, name, path, description}: {
icon?: React.ReactNode,
schema: RJSFSchema,
name: string,
description?: React.ReactNode,
path: string,
name?: string,
onDelete?: () => void,
collapse?: boolean;
onCollapse?: () => void
Expand Down Expand Up @@ -107,8 +109,8 @@ const renderHeader = ({icon, schema, onDelete, name, path}: {
label={`${schema?.type}${schema?.format ? `: ${schema?.format}` : ''}`}
/>
</Typography>
{schema?.description && (
<Typography variant="caption">{schema?.description}</Typography>
{description && (
<Typography variant="caption">{description}</Typography>
)}
</>
)}
Expand Down Expand Up @@ -146,36 +148,73 @@ const handleEdit = (dispatch: React.Dispatch<SchemaAction>, name: string, schema
const SchemaPreview = ({schema, data, name, path}: Props) => {
const FormPreview = getSchemaFormatFromSchema(schema, SchemaPreview)
return (
<div>
<FormPreview {...{schema, data, name, path}} />
</div>
)
};

SchemaPreview.String = function String({schema, path, data, name}: DataVisualizationType) {
const {dispatch} = useSchema();
return (
<div>
{renderHeader({name, path, schema, icon: <TextSnippet/>, onDelete: () => handleDelete(dispatch, path)})}
</div>
<Paper>
{renderHeader({
description: schema.description,
name,
path,
schema,
icon: <TextSnippet/>,
onDelete: () => handleDelete(dispatch, path)
})}
</Paper>
);
};

SchemaPreview.Enum = function Enum({schema, path, data, name}: DataVisualizationType) {
const {dispatch} = useSchema();
const enums = schema.enum
return (
<Paper>
{renderHeader({
description: <>{schema.description} <Typography variant="caption">Options:</Typography> <Box gap={1} display="flex" flexDirection='row'>{enums.map(e => (
<Chip size="small" label={schema?.enumNames[enums.indexOf(e)] || e}/>))}</Box></>,
name,
path,
schema,
icon: <Checklist/>,
onDelete: () => handleDelete(dispatch, path)
})}
</Paper>
);
};

SchemaPreview.Number = function Number({schema, path, name}: DataVisualizationType) {
const {dispatch} = useSchema();
return (
<div>
{renderHeader({name, path, schema, icon: <Numbers/>, onDelete: () => handleDelete(dispatch, path)})}
</div>
<Paper>
{renderHeader({
description: schema.description,
name,
path,
schema,
icon: <Numbers/>,
onDelete: () => handleDelete(dispatch, path)
})}
</Paper>
);
};

SchemaPreview.Boolean = function BooleanVisualization({schema, path, name}: DataVisualizationType) {
const {dispatch} = useSchema();
return (
<div>
{renderHeader({name, path, schema, icon: <ToggleOn/>, onDelete: () => handleDelete(dispatch, path)})}
</div>
<Paper>
{renderHeader({
description: schema.description,
name,
path,
schema,
icon: <ToggleOn/>,
onDelete: () => handleDelete(dispatch, path)
})}
</Paper>
);
};

Expand All @@ -189,9 +228,12 @@ SchemaPreview.Object = function ObjectVisualization({schema, path, data, name}:
setOpen(!open);
};

const theme = useTheme();

return (
<Card sx={{p: 2, m: 2}}>
<Paper>
{renderHeader({
description: schema.description,
name,
path,
schema,
Expand All @@ -200,7 +242,7 @@ SchemaPreview.Object = function ObjectVisualization({schema, path, data, name}:
onCollapse: handleCollapse,
onDelete: () => handleDelete(dispatch, path)
})}
<Card sx={{p: 2, m: 2}}>
<Paper sx={{ p: 1 }}>
<Box
px={2} display="flex" justifyContent="space-between">
<Typography flex={1}>Properties</Typography>
Expand All @@ -210,36 +252,46 @@ SchemaPreview.Object = function ObjectVisualization({schema, path, data, name}:
<ExpandLess fontSize="small"/>}</IconButton>}
</Box>
<Collapse in={open} timeout="auto" unmountOnExit>
{properties?.length > 0 ? properties?.map((property) => (
<>
<SchemaPreview
name={property}
schema={schema.properties[property]}
path={generatePath(path, generatePath('properties', property))}
/>
</>
)) : (
<Typography alignItems="center" textAlign="center" p={3}>
Click on <Add fontSize="small"/> button to add properties
</Typography>
)}
<Stack gap={2}>
{properties?.length > 0 ? properties?.map((property) => (
<>
<SchemaPreview
name={property}
schema={schema.properties[property]}
path={generatePath(path, generatePath('properties', property))}
/>
</>
)) : (
<Typography alignItems="center" textAlign="center" p={3}>
Click on <Add fontSize="small"/> button to add properties
</Typography>
)}
</Stack>
</Collapse>
</Card>
</Card>
</Paper>
</Paper>
);
};

SchemaPreview.Array = function ArrayVisualization({schema, path, data, name}: DataVisualizationType) {
const {dispatch} = useSchema();
const theme = useTheme();
return (
<>
<Card sx={{p: 2, m: 2}}>
{renderHeader({name,path, schema, icon: <DataArray/>, onDelete: () => handleDelete(dispatch, path)})}
<Paper sx={{ p: 1 }}>
{renderHeader({
description: schema.description,
name,
path,
schema,
icon: <DataArray/>,
onDelete: () => handleDelete(dispatch, path)
})}
<Box>
<SchemaPreview
{...{schema: schema.items, name, path: generatePath(path, 'items')}}
/>
</Card>
</>
</Box>
</Paper>
);
};

Expand Down
7 changes: 7 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {TimeField} from "./fields/widgets/TimeField";
import {DateTimeField} from "./fields/widgets/DateTimeField";
import {FaqWidget} from "./fields/patterns/FaqWidget";
import {FieldConfig} from "./types";
import {SelectField} from "./fields/widgets/SelectField";

export const PRIMITIVE_PROPERTIES: FieldConfig[] = [
{
Expand Down Expand Up @@ -72,6 +73,12 @@ export const STRING_WIDGETS: FieldConfig[] = [
title: 'Time Field',
description: 'a time field',
Class: TimeField,
},
{
id: 'SELECT',
title: 'Select Field',
description: 'a select field with a list of options',
Class: SelectField,
}
];

Expand Down
55 changes: 53 additions & 2 deletions src/fields/JsonSchemaField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
Expand All @@ -66,14 +81,27 @@ 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)
if (schema.default) this.setDefault(schema.default)
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)
}


Expand All @@ -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
};

}
Expand Down Expand Up @@ -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'],
Expand Down
1 change: 0 additions & 1 deletion src/fields/primitives/NumberField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,4 @@ export class NumberField extends JsonSchemaField {
if (schema.exclusiveMaximum) this.setExclusiveMaximum(schema.exclusiveMaximum)
if (schema.exclusiveMinimum) this.setExclusiveMinimum(schema.exclusiveMinimum)
}

}
Loading

0 comments on commit 27fbca6

Please sign in to comment.