Skip to content

Commit

Permalink
feat(plugin): use ajv to validate data (#1047)
Browse files Browse the repository at this point in the history
* feat: use ajv to validate data

* style: format codes

* style: format codes

* style: remove extra ;

* style: format codes
  • Loading branch information
juzhiyuan authored Dec 18, 2020
1 parent dd5e4e2 commit 8b07c43
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 20 deletions.
2 changes: 1 addition & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@
"@rjsf/antd": "2.2.0",
"@rjsf/core": "2.2.0",
"@uiw/react-codemirror": "^3.0.1",
"ajv": "^7.0.0-rc.2",
"antd": "^4.4.0",
"classnames": "^2.2.6",
"dayjs": "1.8.28",
"js-beautify": "^1.13.0",
"json-schema": "0.2.5",
"lodash": "^4.17.11",
"moment": "^2.25.3",
"nzh": "1.0.4",
Expand Down
67 changes: 51 additions & 16 deletions web/src/components/Plugin/PluginPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import React, { useEffect, useState } from 'react';
import { Anchor, Layout, Switch, Card, Tooltip, Button, notification, Avatar } from 'antd';
import { SettingFilled } from '@ant-design/icons';
import { PanelSection } from '@api7-dashboard/ui';
import { validate } from 'json-schema';
import Ajv, { DefinedError } from 'ajv';

import { fetchSchema, getList } from './service';
import CodeMirrorDrawer from './CodeMirrorDrawer';
Expand All @@ -43,11 +43,13 @@ const { Sider, Content } = Layout;
// NOTE: use this flag as plugin's name to hide drawer
const NEVER_EXIST_PLUGIN_FLAG = 'NEVER_EXIST_PLUGIN_FLAG';

const ajv = new Ajv();

const PluginPage: React.FC<Props> = ({
readonly = false,
initialData = {},
schemaType = '',
onChange = () => {},
onChange = () => { },
}) => {
const [pluginList, setPlugin] = useState<PluginComponent.Meta[][]>([]);
const [name, setName] = useState<string>(NEVER_EXIST_PLUGIN_FLAG);
Expand All @@ -56,30 +58,63 @@ const PluginPage: React.FC<Props> = ({
getList().then(setPlugin);
}, []);

// NOTE: This function has side effect because it mutates the original schema data
const injectDisableProperty = (schema: Record<string, any>) => {
// NOTE: The frontend will inject the disable property into schema just like the manager-api does
if (!schema.properties) {
// eslint-disable-next-line
schema.properties = {};
}
// eslint-disable-next-line
(schema.properties as any).disable = {
type: 'boolean',
};
return schema;
};

const validateData = (pluginName: string, value: PluginComponent.Data) => {
fetchSchema(pluginName, schemaType).then((schema) => {
// NOTE: The frontend will inject the disable property into schema just like the manager-api does
if (!schema.properties) {
// eslint-disable-next-line
schema.properties = {}
}
// eslint-disable-next-line
;(schema.properties as any).disable = {
type: "boolean"
if (schema.oneOf) {
(schema.oneOf || []).forEach((item: any) => {
injectDisableProperty(item);
});
} else {
injectDisableProperty(schema);
}

const { valid, errors } = validate(value, schema);
if (valid) {
const validate = ajv.compile(schema);

if (validate(value)) {
setName(NEVER_EXIST_PLUGIN_FLAG);
onChange({ ...initialData, [pluginName]: value });
return;
}
errors?.forEach((item) => {

// eslint-disable-next-line
for (const err of validate.errors as DefinedError[]) {
let description = '';
switch (err.keyword) {
case 'enum':
description = `${err.dataPath} ${err.message}: ${err.params.allowedValues.join(
', ',
)}`;
break;
case 'minItems':
case 'type':
description = `${err.dataPath} ${err.message}`;
break;
case 'oneOf':
case 'required':
description = err.message || '';
break;
default:
description = `${err.schemaPath} ${err.message}`;
}
notification.error({
message: 'Invalid plugin data',
description: item.message,
description,
});
});
}
setName(pluginName);
});
};
Expand Down Expand Up @@ -158,7 +193,7 @@ const PluginPage: React.FC<Props> = ({
if (isChecked) {
validateData(item.name, {
...initialData[item.name],
disable: false
disable: false,
});
} else {
onChange({
Expand Down
4 changes: 2 additions & 2 deletions web/src/components/Plugin/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { JSONSchema7 } from 'json-schema';
import { omit } from 'lodash';
import { request } from 'umi';

import { PLUGIN_MAPPER_SOURCE } from './data';

enum Category {
Expand Down Expand Up @@ -80,7 +80,7 @@ const cachedPluginSchema: Record<string, object> = {
export const fetchSchema = async (
name: string,
schemaType: PluginComponent.Schema,
): Promise<JSONSchema7> => {
): Promise<any> => {
if (!cachedPluginSchema[schemaType][name]) {
const queryString = schemaType !== 'route' ? `?schema_type=${schemaType}` : '';
cachedPluginSchema[schemaType][name] = (
Expand Down
22 changes: 21 additions & 1 deletion web/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3923,6 +3923,16 @@ ajv@^6.12.5:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"

ajv@^7.0.0-rc.2:
version "7.0.0-rc.2"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-7.0.0-rc.2.tgz#9c237b95072c1ee8c38e2df76422f37bacc9ae5e"
integrity sha512-D2iqHvbT3lszv5KSsTvJL9PSPf/2/s45i68vLXJmT124cxK/JOoOFyo/QnrgMKa2FHlVaMIsp1ZN1P4EH3bCKw==
dependencies:
fast-deep-equal "^3.1.1"
json-schema-traverse "^1.0.0"
require-from-string "^2.0.2"
uri-js "^4.2.2"

alphanum-sort@^1.0.0:
version "1.0.2"
resolved "https://registry.npm.taobao.org/alphanum-sort/download/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
Expand Down Expand Up @@ -10654,12 +10664,17 @@ json-schema-traverse@^0.4.1:
resolved "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha1-afaofZUTq4u4/mO9sJecRI5oRmA=

json-schema-traverse@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==

[email protected]:
version "0.2.3"
resolved "https://registry.npm.taobao.org/json-schema/download/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=

json-schema@0.2.5, json-schema@^0.2.5:
json-schema@^0.2.5:
version "0.2.5"
resolved "https://registry.npm.taobao.org/json-schema/download/json-schema-0.2.5.tgz#97997f50972dd0500214e208c407efa4b5d7063b"
integrity sha1-l5l/UJct0FACFOIIxAfvpLXXBjs=
Expand Down Expand Up @@ -15485,6 +15500,11 @@ require-directory@^2.1.1:
resolved "https://registry.npm.taobao.org/require-directory/download/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=

require-from-string@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==

require-main-filename@^2.0.0:
version "2.0.0"
resolved "https://registry.npm.taobao.org/require-main-filename/download/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
Expand Down

0 comments on commit 8b07c43

Please sign in to comment.