feat: classify the properties of the components

This commit is contained in:
xzdry 2022-02-12 13:28:05 +08:00
parent 1304083729
commit 1a03f331e3
5 changed files with 128 additions and 35 deletions

View File

@ -43,26 +43,20 @@ export const renderField = (properties: {
if (typeof value !== 'object') {
const ref = React.createRef<HTMLTextAreaElement>();
const onBlur = () => {
const operation = type ? genOperation(
registry,
'modifyTraitProperty',
{
componentId: selectedComponentId,
traitIndex: index,
properties: {
[fullKey]: ref.current?.value,
},
}
) : genOperation(
registry,
'modifyComponentProperty',
{
componentId: selectedComponentId,
properties: {
[fullKey]: ref.current?.value,
},
}
);
const operation = type
? genOperation(registry, 'modifyTraitProperty', {
componentId: selectedComponentId,
traitIndex: index,
properties: {
[fullKey]: ref.current?.value,
},
})
: genOperation(registry, 'modifyComponentProperty', {
componentId: selectedComponentId,
properties: {
[fullKey]: ref.current?.value,
},
});
eventBus.send('operation', operation);
};
const onChange = (event: any) => {
@ -146,19 +140,13 @@ export const ComponentForm: React.FC<Props> = observer(props => {
</FormControl>
<VStack width="full" alignItems="start">
<strong>Properties</strong>
<VStack
width="full"
padding="2"
background="white"
border="1px solid"
borderColor="gray.200"
borderRadius="4"
>
<VStack width="full" background="white">
<SchemaField
schema={cImpl.spec.properties}
label=""
key={selectedComponent.id}
formData={properties}
isTopLevel={true}
onChange={newFormData => {
eventBus.send(
'operation',
@ -174,7 +162,13 @@ export const ComponentForm: React.FC<Props> = observer(props => {
</VStack>
</VStack>
<EventTraitForm component={selectedComponent} services={services} />
{ hasFetchTrait ? <FetchTraitForm key={selectedComponent.id} component={selectedComponent} services={services} /> : null }
{hasFetchTrait ? (
<FetchTraitForm
key={selectedComponent.id}
component={selectedComponent}
services={services}
/>
) : null}
<StyleTraitForm component={selectedComponent} services={services} />
<GeneralTraitFormList component={selectedComponent} services={services} />
</VStack>

View File

@ -4,8 +4,8 @@ import {
FormLabel,
FormHelperText,
FormErrorMessage,
Text,
Button,
Tooltip
} from '@chakra-ui/react';
import { isEmpty } from 'lodash-es';
import { AnyKind, UnknownKind } from '@sinclair/typebox';
@ -19,6 +19,7 @@ import BooleanField from './BooleanField';
import NumberField from './NumberField';
import NullField from './NullField';
import MultiSchemaField from './MultiSchemaField';
import TopLevelField from './TopLevelField';
import UnsupportedField from './UnsupportedField';
type TemplateProps = {
@ -57,7 +58,7 @@ const DefaultTemplate: React.FC<TemplateProps> = props => {
return (
<FormControl isRequired={required} id={id} mt="1">
{displayLabel && (
<>
<Tooltip label={description} placement='auto-start'>
<FormLabel>
{label}
{codeMode && (
@ -72,8 +73,7 @@ const DefaultTemplate: React.FC<TemplateProps> = props => {
</Button>
)}
</FormLabel>
{description && <Text fontSize="sm">{description}</Text>}
</>
</Tooltip>
)}
{children}
{errors && <FormErrorMessage>{errors}</FormErrorMessage>}
@ -87,7 +87,7 @@ type Props = FieldProps & {
};
const SchemaField: React.FC<Props> = props => {
const { schema, label, formData, onChange, registry, stateManager } = props;
const { schema, isTopLevel, label, formData, onChange, registry, stateManager } = props;
const [isExpression, setIsExpression] = useState(() => _isExpression(formData));
if (isEmpty(schema)) {
@ -101,6 +101,8 @@ const SchemaField: React.FC<Props> = props => {
Component = widgets.expression;
} else if (schema.widget && widgets[schema.widget]) {
Component = widgets[schema.widget];
} else if (isTopLevel) {
Component = TopLevelField;
}
// type fields
else if (schema.type === 'object') {

View File

@ -0,0 +1,90 @@
import React, { useMemo } from 'react';
import SchemaField from './SchemaField';
import { JSONSchema7 } from 'json-schema';
import { FieldProps } from './fields';
import { sortBy, groupBy } from 'lodash-es';
import {
AccordionPanel,
AccordionItem,
AccordionButton,
AccordionIcon,
Box,
Accordion,
} from '@chakra-ui/react';
type ExpandedSpec = {
category?: string;
weight?: string;
name?: string;
};
type Property = Record<string, JSONSchema7 & ExpandedSpec>;
type Category = {
name: string;
schemas: (JSONSchema7 & ExpandedSpec)[];
};
const TopLevelField: React.FC<FieldProps> = props => {
const { schema, formData, onChange, registry, stateManager } = props;
const categories = useMemo<Category[]>(() => {
const properties = (schema.properties || {}) as Property;
Object.keys(properties).forEach(name => {
const schema = properties[name];
if (!schema.title) {
schema.name = name;
}
});
const grouped = groupBy(properties, c => c.category || 'Basic');
return Object.keys(grouped).map(name => ({
name,
schemas: sortBy(grouped[name], c => c.weight || -Infinity),
}));
}, [schema.properties]);
return (
<Accordion width="full" defaultIndex={[0]} allowMultiple>
{categories.map(category => {
const schemas = category.schemas;
return (
<AccordionItem width="full" key={category.name} background="#F7FAFC">
<AccordionButton>
<Box flex="1" textAlign="left">
{category.name}
</Box>
<AccordionIcon />
</AccordionButton>
<AccordionPanel bg="white">
{schemas.map(schema => {
const name = schema.title || schema.name;
if (typeof schema === 'boolean') {
return null;
}
return (
<SchemaField
key={name}
schema={schema}
label={name!}
formData={formData?.[name!]}
onChange={value => {
onChange({
...formData,
[name!]: value,
});
}}
registry={registry}
stateManager={stateManager}
/>
);
})}
</AccordionPanel>
</AccordionItem>
);
})}
</Accordion>
);
};
export default TopLevelField;

View File

@ -10,6 +10,7 @@ export type FieldProps = {
schema: Schema & EditorSchema;
registry: Registry;
stateManager: StateManager;
isTopLevel?: boolean;
formData: any;
onChange: (v: any) => void;
};

View File

@ -24,6 +24,7 @@ export class SchemaValidator implements ISchemaValidator {
string,
RuntimeComponent<string, string, string, string>
> = {};
private ajv!: Ajv;
private validatorMap!: ValidatorMap;
@ -127,7 +128,12 @@ export class SchemaValidator implements ISchemaValidator {
}
private initAjv() {
this.ajv = new Ajv({}).addKeyword('kind').addKeyword('modifier');
this.ajv = new Ajv({})
.addKeyword('kind')
.addKeyword('modifier')
.addKeyword('widget')
.addKeyword('weight')
.addKeyword('category');
this.validatorMap = {
components: {},