mirror of
https://github.com/smartxworks/sunmao-ui.git
synced 2025-04-06 21:40:23 +08:00
feat(validator): auto fix missing property error
This commit is contained in:
parent
f62c6ce384
commit
dcff01f801
@ -15,6 +15,10 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import React, { useMemo } from 'react';
|
||||
import {
|
||||
ModifyComponentPropertiesLeafOperation,
|
||||
ModifyTraitPropertiesLeafOperation,
|
||||
} from '../operations/leaf';
|
||||
import { EditorServices } from '../types';
|
||||
import { Pagination } from './Pagination';
|
||||
|
||||
@ -35,6 +39,25 @@ export const WarningArea: React.FC<Props> = observer(({ services }) => {
|
||||
return validateResult
|
||||
.slice(currPage * PageSize, currPage * PageSize + PageSize)
|
||||
.map((result, i) => {
|
||||
const onFix = (newProperties: any) => {
|
||||
if (result.traitType && result.traitIndex) {
|
||||
const operation = new ModifyTraitPropertiesLeafOperation(services.registry, {
|
||||
componentId: result.componentId,
|
||||
traitIndex: result.traitIndex,
|
||||
properties: newProperties,
|
||||
});
|
||||
services.appModelManager.do(operation);
|
||||
} else {
|
||||
const operation = new ModifyComponentPropertiesLeafOperation(
|
||||
services.registry,
|
||||
{
|
||||
componentId: result.componentId,
|
||||
properties: newProperties,
|
||||
}
|
||||
);
|
||||
services.appModelManager.do(operation);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Tr key={i}>
|
||||
<Td
|
||||
@ -47,10 +70,22 @@ export const WarningArea: React.FC<Props> = observer(({ services }) => {
|
||||
<Td>{result.traitType || '-'}</Td>
|
||||
<Td>{result.property || '-'}</Td>
|
||||
<Td>{result.message}</Td>
|
||||
<Td>
|
||||
{result.fix ? (
|
||||
<button onClick={() => onFix(result.fix?.())}>fix</button>
|
||||
) : undefined}
|
||||
</Td>
|
||||
</Tr>
|
||||
);
|
||||
});
|
||||
}, [currPage, isCollapsed, setSelectedComponentId, validateResult]);
|
||||
}, [
|
||||
currPage,
|
||||
isCollapsed,
|
||||
services.appModelManager,
|
||||
services.registry,
|
||||
setSelectedComponentId,
|
||||
validateResult,
|
||||
]);
|
||||
|
||||
const savedBadge = useMemo(() => {
|
||||
return <Badge colorScheme="green">Saved</Badge>;
|
||||
@ -114,6 +149,7 @@ export const WarningArea: React.FC<Props> = observer(({ services }) => {
|
||||
<Th>Trait Type</Th>
|
||||
<Th>Property</Th>
|
||||
<Th>Message</Th>
|
||||
<Th>Fix</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>{errorItems}</Tbody>
|
||||
|
@ -95,10 +95,11 @@ export class SchemaValidator implements ISchemaValidator {
|
||||
});
|
||||
|
||||
this.traitRules.forEach(rule => {
|
||||
component.traits.forEach(trait => {
|
||||
component.traits.forEach((trait, i) => {
|
||||
const r = rule.validate({
|
||||
trait,
|
||||
component,
|
||||
traitIndex: i,
|
||||
...baseContext,
|
||||
});
|
||||
if (r.length > 0) {
|
||||
@ -128,6 +129,12 @@ export class SchemaValidator implements ISchemaValidator {
|
||||
});
|
||||
}
|
||||
|
||||
fix() {
|
||||
this.result.forEach(r => {
|
||||
r.fix?.();
|
||||
});
|
||||
}
|
||||
|
||||
private initAjv() {
|
||||
this.ajv = new Ajv({})
|
||||
.addKeyword('kind')
|
||||
|
@ -30,12 +30,14 @@ export interface ComponentValidateContext extends BaseValidateContext {
|
||||
|
||||
export interface TraitValidateContext extends BaseValidateContext {
|
||||
trait: ITraitModel;
|
||||
traitIndex: number;
|
||||
component: IComponentModel;
|
||||
}
|
||||
|
||||
export interface PropertiesValidateContext extends BaseValidateContext {
|
||||
properties: IFieldModel;
|
||||
trait?: ITraitModel;
|
||||
traitIndex?: number;
|
||||
component: IComponentModel;
|
||||
}
|
||||
|
||||
@ -85,7 +87,8 @@ export interface ISchemaValidator {
|
||||
export interface ValidateErrorResult {
|
||||
componentId: string;
|
||||
traitType?: string;
|
||||
traitIndex?: number;
|
||||
property?: string;
|
||||
message: string;
|
||||
fix?: () => void;
|
||||
fix?: () => any;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { get, has } from 'lodash';
|
||||
import { ExpressionKeywords } from '@sunmao-ui/shared';
|
||||
import { cloneDeep, get, has, set } from 'lodash';
|
||||
import { ExpressionKeywords, generateDefaultValueFromSpec } from '@sunmao-ui/shared';
|
||||
import { ComponentId, ModuleId } from '../../AppModel/IAppModel';
|
||||
import {
|
||||
PropertiesValidatorRule,
|
||||
@ -15,6 +15,8 @@ class PropertySchemaValidatorRule implements PropertiesValidatorRule {
|
||||
component,
|
||||
trait,
|
||||
validators,
|
||||
traitIndex,
|
||||
componentIdSpecMap,
|
||||
}: PropertiesValidateContext): ValidateErrorResult[] {
|
||||
const results: ValidateErrorResult[] = [];
|
||||
let validate;
|
||||
@ -47,6 +49,17 @@ class PropertySchemaValidatorRule implements PropertiesValidatorRule {
|
||||
componentId: component.id,
|
||||
property: error.instancePath,
|
||||
traitType: trait?.type,
|
||||
traitIndex,
|
||||
fix: () => {
|
||||
const defaultValue = generateDefaultValueFromSpec(
|
||||
componentIdSpecMap[component.id].spec.properties
|
||||
) as Object;
|
||||
const path = instancePath.split('/').slice(1).join('.');
|
||||
|
||||
const newProperties = cloneDeep(properties.rawValue);
|
||||
set(newProperties, path, get(defaultValue, path));
|
||||
return newProperties;
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -3,8 +3,14 @@ import { generateDefaultValueFromSpec } from '../src/utils/spec';
|
||||
|
||||
describe('generateDefaultValueFromSpec function', () => {
|
||||
it('can parse array', () => {
|
||||
const type = Type.Array(Type.Object({}));
|
||||
expect(generateDefaultValueFromSpec(type)).toMatchObject([]);
|
||||
const type = Type.Array(
|
||||
Type.Object({
|
||||
foo: Type.Number(),
|
||||
})
|
||||
);
|
||||
expect(generateDefaultValueFromSpec(type)).toEqual([{ foo: 0 }]);
|
||||
const type2 = Type.Array(Type.String());
|
||||
expect(generateDefaultValueFromSpec(type2)).toEqual(['']);
|
||||
});
|
||||
it('can parse number', () => {
|
||||
const type = Type.Number();
|
||||
@ -24,7 +30,7 @@ describe('generateDefaultValueFromSpec function', () => {
|
||||
key: Type.String(),
|
||||
value: Type.Array(Type.String()),
|
||||
});
|
||||
expect(generateDefaultValueFromSpec(type)).toMatchObject({ key: '', value: [] });
|
||||
expect(generateDefaultValueFromSpec(type)).toMatchObject({ key: '', value: [''] });
|
||||
});
|
||||
|
||||
it('can parse enum', () => {
|
||||
|
@ -85,7 +85,7 @@ export function generateDefaultValueFromSpec(spec: JSONSchema7): JSONSchema7Type
|
||||
? Array.isArray(spec.items)
|
||||
? getArray(spec.items)
|
||||
: isJSONSchema(spec.items)
|
||||
? []
|
||||
? [generateDefaultValueFromSpec(spec.items)]
|
||||
: null
|
||||
: [];
|
||||
case spec.type === 'number':
|
||||
|
Loading…
x
Reference in New Issue
Block a user