mirror of
https://github.com/smartxworks/sunmao-ui.git
synced 2025-02-17 17:40:31 +08:00
feat: classify the properties of the components
This commit is contained in:
parent
1304083729
commit
1a03f331e3
@ -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>
|
||||
|
@ -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') {
|
||||
|
@ -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;
|
@ -10,6 +10,7 @@ export type FieldProps = {
|
||||
schema: Schema & EditorSchema;
|
||||
registry: Registry;
|
||||
stateManager: StateManager;
|
||||
isTopLevel?: boolean;
|
||||
formData: any;
|
||||
onChange: (v: any) => void;
|
||||
};
|
||||
|
@ -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: {},
|
||||
|
Loading…
Reference in New Issue
Block a user