Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions web-app-frontend/src/components/SchemaFormBuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import SimpleNode from './builder/SimpleNode';
import ComplexNode from './builder/ComplexNode';
import NodeTypeSelector from './builder/NodeTypeSelector';
import { Form, InputGroup } from 'react-bootstrap';
import SuggestiveInput from './suggestive-input/SuggestiveInput';

export const initialSchema: SchemaNode = {
nodeType: 'simple',
Expand All @@ -28,7 +29,7 @@ const SchemaFormBuilder: React.FC<{
isRoot?: boolean;
}> = ({ node, onChange, rootDefinitions, isRoot = false }) => {
return (
<div className="border p-3 mb-3">
<>
{isRoot && (
<>
<Form.Group className="mb-3">
Expand All @@ -44,15 +45,16 @@ const SchemaFormBuilder: React.FC<{
<Form.Group className="mb-3">
<InputGroup>
<InputGroup.Text>Schema</InputGroup.Text>
<Form.Control
<SuggestiveInput
mode={'strict'}
value={node.schema}
list={'json-schema-suggestions'}
onChange={(e) => onChange({ ...node, schema: e.target.value })}
maxLength={128}
onChange={(e) => onChange({ ...node, schema: e.value })}
required={true}
suggestions={schemas.map(it => {
return { key: it, value: it };
})}
maxSuggestions={5}
/>
<datalist id={'json-schema-suggestions'}>
{schemas.map(it => <option key={it} value={it} />)}
</datalist>
</InputGroup>
</Form.Group>
</>
Expand Down Expand Up @@ -86,7 +88,7 @@ const SchemaFormBuilder: React.FC<{
onChange={onChange}
/>
)}
</div>
</>
);
};

Expand Down
75 changes: 38 additions & 37 deletions web-app-frontend/src/components/builder/Definitions.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Accordion, Button, Form, InputGroup } from 'react-bootstrap';
import React from 'react';
import React, { useState } from 'react';
import SchemaFormBuilder, { initialSchema } from '../SchemaFormBuilder';
import { SchemaNode } from '../../const/type';
import { LineiconsPlus, LineiconsTrash3 } from '../../const/icons';
Expand All @@ -24,49 +24,49 @@ const Definitions: React.FC<DefinitionsProps> = ({
onChange,
rootDefinitions
}) => {
const [counter, setCounter] = useState(0)

return (
<Accordion className="mt-3">
<Accordion.Item eventKey="definitions">
<Accordion.Header>Definitions</Accordion.Header>
<Accordion.Body>
<Accordion className="mb-3">
{Object.entries(node.definitions || {}).map(([name, defNode], index) => (
<Accordion.Item eventKey={`definition-${index}`}>
{Object.entries(node.definitions || {}).map(([name, defNode]) => (
<Accordion.Item eventKey={`definition-${name}`}>
<Accordion.Header>{name}</Accordion.Header>
<Accordion.Body>
<div key={`definition-${index}`} className="border p-3 mb-3">
<Form.Group className="mb-3">
<InputGroup>
<InputGroup.Text>Name</InputGroup.Text>
<Form.Control
value={name}
onChange={(e) => {
const newDefinitions = renameField(node.definitions || {}, name, e.target.value)
onChange({ ...node, definitions: newDefinitions });
}}
/>
<Button
variant="danger"
onClick={() => {
const newDefinitions = { ...node.definitions };
delete newDefinitions[name];
onChange({ ...node, definitions: newDefinitions });
}}
>
<LineiconsTrash3 />
</Button>
</InputGroup>
</Form.Group>
<SchemaFormBuilder
node={defNode}
onChange={(newDefNode) => {
const newDefinitions = { ...node.definitions };
newDefinitions[name] = newDefNode;
onChange({ ...node, definitions: newDefinitions });
}}
rootDefinitions={rootDefinitions}
/>
</div>
<Form.Group className="mb-3">
<InputGroup>
<InputGroup.Text>Name</InputGroup.Text>
<Form.Control
value={name}
onChange={(e) => {
const newDefinitions = renameField(node.definitions || {}, name, e.target.value)
onChange({ ...node, definitions: newDefinitions });
}}
/>
<Button
variant="danger"
onClick={() => {
const newDefinitions = { ...node.definitions };
delete newDefinitions[name];
onChange({ ...node, definitions: newDefinitions });
}}
>
<LineiconsTrash3 />
</Button>
</InputGroup>
</Form.Group>
<SchemaFormBuilder
node={defNode}
onChange={(newDefNode) => {
const newDefinitions = { ...node.definitions };
newDefinitions[name] = newDefNode;
onChange({ ...node, definitions: newDefinitions });
}}
rootDefinitions={rootDefinitions}
/>
</Accordion.Body>
</Accordion.Item>
))}
Expand All @@ -75,7 +75,8 @@ const Definitions: React.FC<DefinitionsProps> = ({
variant="outline-success"
size="sm"
onClick={() => {
const newName = `definition${Object.keys(node.definitions || {}).length + 1}`;
const newName = `definition-${counter}`;
setCounter(counter + 1)
const newDefinitions = { ...node.definitions || {}, [newName]: initialSchema };
onChange({ ...node, definitions: newDefinitions });
}}
Expand Down
151 changes: 77 additions & 74 deletions web-app-frontend/src/components/builder/ObjectNode.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Accordion, Button, Form, InputGroup } from 'react-bootstrap';
import React from 'react';
import SchemaFormBuilder, { initialSchema } from '../SchemaFormBuilder';
import { ObjectSchemaNode, SchemaNode } from '../../const/type';
import { BaseSchemaNode, ObjectSchemaNode, SchemaNode } from '../../const/type';
import { LineiconsPlus, LineiconsTrash3 } from '../../const/icons';

export interface ObjectNodeProps {
Expand All @@ -15,6 +15,13 @@ const ObjectNode: React.FC<ObjectNodeProps> = ({
onChange,
rootDefinitions
}) => {
const nodePropertyTypes = (node: BaseSchemaNode): string => {
if (node.type === 'undefined') {
return node.type;
}
return node.type.join(', ')
}

return (
<Accordion className="mb-3">
<Accordion.Item eventKey="object-parameters">
Expand Down Expand Up @@ -69,54 +76,52 @@ const ObjectNode: React.FC<ObjectNodeProps> = ({
<Accordion key={index} className="mb-3">
<Accordion.Item eventKey={String(index)}>
<Accordion.Header>
{prop.name || 'Unnamed Property'} ({prop.schema.type})
{prop.name || 'Unnamed Property'} ({nodePropertyTypes(prop.schema)})
</Accordion.Header>
<Accordion.Body>
<div className="border p-3 mb-3">
<div className="d-flex gap-3 mb-3">
<InputGroup className="flex-grow-1">
<InputGroup.Text>Name</InputGroup.Text>
<Form.Control
value={prop.name}
<div className="d-flex gap-3 mb-3">
<InputGroup className="flex-grow-1">
<InputGroup.Text>Name</InputGroup.Text>
<Form.Control
value={prop.name}
onChange={(e) => {
const newProperties = [...node.properties!];
newProperties[index] = { ...prop, name: e.target.value };
onChange({ ...node, properties: newProperties });
}}
/>
<InputGroup.Text>
<Form.Check
type="checkbox"
label="Required"
checked={prop.required}
onChange={(e) => {
const newProperties = [...node.properties!];
newProperties[index] = { ...prop, name: e.target.value };
newProperties[index] = { ...prop, required: e.target.checked };
onChange({ ...node, properties: newProperties });
}}
/>
<InputGroup.Text>
<Form.Check
type="checkbox"
label="Required"
checked={prop.required}
onChange={(e) => {
const newProperties = [...node.properties!];
newProperties[index] = { ...prop, required: e.target.checked };
onChange({ ...node, properties: newProperties });
}}
/>
</InputGroup.Text>
<Button
variant="danger"
onClick={() => {
const newProperties = node.properties?.filter((_, i) => i !== index);
onChange({ ...node, properties: newProperties });
}}
>
<LineiconsTrash3 />
</Button>
</InputGroup>
</div>
<SchemaFormBuilder
node={prop.schema}
onChange={(newSchema) => {
const newProperties = [...node.properties!];
newProperties[index].schema = newSchema;
onChange({ ...node, properties: newProperties });
}}
rootDefinitions={rootDefinitions}
/>
</InputGroup.Text>
<Button
variant="danger"
onClick={() => {
const newProperties = node.properties?.filter((_, i) => i !== index);
onChange({ ...node, properties: newProperties });
}}
>
<LineiconsTrash3 />
</Button>
</InputGroup>
</div>
<SchemaFormBuilder
node={prop.schema}
onChange={(newSchema) => {
const newProperties = [...node.properties!];
newProperties[index].schema = newSchema;
onChange({ ...node, properties: newProperties });
}}
rootDefinitions={rootDefinitions}
/>
</Accordion.Body>
</Accordion.Item>
</Accordion>
Expand Down Expand Up @@ -147,42 +152,40 @@ const ObjectNode: React.FC<ObjectNodeProps> = ({
<Accordion key={index} className="mb-3">
<Accordion.Item eventKey={String(index)}>
<Accordion.Header>
{prop.name || 'Unnamed Property'} ({prop.schema.type})
{prop.name || 'Unnamed Property'} ({nodePropertyTypes(prop.schema)})
</Accordion.Header>
<Accordion.Body>
<div className="border p-3 mb-3">
<div className="d-flex gap-3 mb-3">
<InputGroup className="flex-grow-1">
<InputGroup.Text>Name</InputGroup.Text>
<Form.Control
value={prop.name}
onChange={(e) => {
const newProperties = [...node.patternProperties!];
newProperties[index] = { ...prop, name: e.target.value };
onChange({ ...node, patternProperties: newProperties });
}}
/>
<Button
variant="danger"
onClick={() => {
const newProperties = node.patternProperties?.filter((_, i) => i !== index);
onChange({ ...node, patternProperties: newProperties });
}}
>
<LineiconsTrash3 />
</Button>
</InputGroup>
</div>
<SchemaFormBuilder
node={prop.schema}
onChange={(newSchema) => {
const newProperties = [...node.patternProperties!];
newProperties[index].schema = newSchema;
onChange({ ...node, patternProperties: newProperties });
}}
rootDefinitions={rootDefinitions}
/>
<div className="d-flex gap-3 mb-3">
<InputGroup className="flex-grow-1">
<InputGroup.Text>Name</InputGroup.Text>
<Form.Control
value={prop.name}
onChange={(e) => {
const newProperties = [...node.patternProperties!];
newProperties[index] = { ...prop, name: e.target.value };
onChange({ ...node, patternProperties: newProperties });
}}
/>
<Button
variant="danger"
onClick={() => {
const newProperties = node.patternProperties?.filter((_, i) => i !== index);
onChange({ ...node, patternProperties: newProperties });
}}
>
<LineiconsTrash3 />
</Button>
</InputGroup>
</div>
<SchemaFormBuilder
node={prop.schema}
onChange={(newSchema) => {
const newProperties = [...node.patternProperties!];
newProperties[index].schema = newSchema;
onChange({ ...node, patternProperties: newProperties });
}}
rootDefinitions={rootDefinitions}
/>
</Accordion.Body>
</Accordion.Item>
</Accordion>
Expand Down
19 changes: 11 additions & 8 deletions web-app-frontend/src/components/builder/ReferenceNode.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Form, InputGroup } from 'react-bootstrap';
import React from 'react';
import { SchemaNode } from '../../const/type';
import SuggestiveInput from '../suggestive-input/SuggestiveInput';


export interface ReferenceNodeProps {
Expand All @@ -18,18 +19,20 @@ const ReferenceNode: React.FC<ReferenceNodeProps> = ({
<Form.Group className="mb-3">
<InputGroup>
<InputGroup.Text>Reference</InputGroup.Text>
<Form.Control
<SuggestiveInput
mode={'strict'}
value={node.reference || ''}
list={'reference-suggestions'}
onChange={(e) => onChange({ ...node, reference: e.target.value })}
/>
<datalist id="reference-suggestions">
{
onChange={(e) => onChange({ ...node, reference: e.value })}
required={true}
suggestions={
Object.keys(rootDefinitions || {})
.map(it => `#/$defs/${it}`)
.map(it => <option key={it} value={it} />)
.map(it => {
return { key: it, value: it }
})
}
</datalist>
maxSuggestions={10}
/>
</InputGroup>
</Form.Group>
)
Expand Down
Loading