Ver código fonte

fix: #4525、4539、4540、4557、4548

xieyonghong 3 anos atrás
pai
commit
a8c82f2d1b

+ 1 - 1
src/components/AMapComponent/PathSimplifier/index.tsx

@@ -28,6 +28,7 @@ const PathSimplifier = (props: PathSimplifierProps) => {
       speed: 10000,
       ...navOptions,
     });
+
     if (onCreated) {
       onCreated(pathNavRef.current!);
     }
@@ -35,7 +36,6 @@ const PathSimplifier = (props: PathSimplifierProps) => {
 
   const pathSimplifier = useCallback(
     (PathObj: PathSimplifier) => {
-      // @ts-ignore
       pathSimplifierRef.current = new PathObj({
         zIndex: 100,
         getPath: (_pathData: any) => {

+ 47 - 50
src/components/AMapComponent/PathSimplifier/types.d.ts

@@ -14,59 +14,59 @@ type PathSimplifierOptions = {
   renderOptions?: {};
 };
 
-class PathSimplifier {
-  constructor(options: PathSimplifierOptions);
+interface PathSimplifier {
+  new (options: PathSimplifierOptions);
 
   readonly supportCanvas: boolean;
 
-  getZIndexOfPath(pathIndex: number): number;
+  getZIndexOfPath: (pathIndex: number) => number;
 
-  setZIndexOfPath(pathIndex: number, zIndex: number);
+  setZIndexOfPath: (pathIndex: number, zIndex: number) => void;
 
   /**
    * 是否置顶显示pathIndex对应的轨迹
    * @param pathIndex
    * @param isTop isTop为真,设置 zIndex 为 现存最大zIndex+1; isTop为假,设置 zIndex 为 构造参数中 getZIndex 的返回值
    */
-  toggleTopOfPath(pathIndex: number, isTop: boolean);
+  toggleTopOfPath: (pathIndex: number, isTop: boolean) => void;
 
-  getPathData(pathIndex: number): any;
+  getPathData: (pathIndex: number) => any;
 
-  createPathNavigator(pathIndex: number, options: {}): PathNavigator;
+  createPathNavigator: (pathIndex: number, options: {}) => PathNavigator;
 
-  getPathNavigators(): any[];
+  getPathNavigators: () => any[];
 
-  clearPathNavigators();
+  clearPathNavigators: () => void;
 
-  getSelectedPathData(): any;
+  getSelectedPathData: () => any;
 
-  getSelectedPathIndex(): number;
+  getSelectedPathIndex: () => number;
 
-  isSelectedPathIndex(pathIndex: number): boolean;
+  isSelectedPathIndex: (pathIndex: number) => boolean;
 
-  setSelectedPathIndex(pathIndex: number);
+  setSelectedPathIndex: (pathIndex: number) => void;
 
-  render();
+  render: () => void;
 
-  renderLater(delay: number[]);
+  renderLater: (delay: number[]) => void;
 
-  setData(data: any[]);
+  setData: (data: any[]) => void;
 
-  setFitView(pathIndex: number);
+  setFitView: (pathIndex: number) => void;
 
-  on(eventName: String, handler: Function);
+  on: (eventName: string, handler: Function) => void;
 
-  off(eventName: String, handler: Function);
+  off: (eventName: string, handler: Function) => void;
 
-  hide();
+  hide: () => void;
 
-  show();
+  show: () => void;
 
-  isHidden(): boolean;
+  isHidden: () => boolean;
 
-  getRender(): boolean;
+  getRender: () => boolean;
 
-  getRenderOptions(): any;
+  getRenderOptions: () => any;
 }
 
 interface PathNavigatorOptions {
@@ -78,51 +78,48 @@ interface PathNavigatorOptions {
   range?: number[];
 }
 
-class PathNavigator {
-  constructor(options: PathNavigatorOptions);
+interface PathNavigator {
+  new (options: PathNavigatorOptions);
 
-  start(pointIndex?: number);
+  start: (pointIndex?: number) => void;
 
-  pause();
+  pause: () => void;
 
-  resume();
+  resume: () => void;
 
-  stop();
+  stop: () => void;
 
-  destroy();
+  destroy: () => void;
 
-  getCursor(): any;
+  getCursor: () => any;
 
-  getNaviStatus(): string;
+  getNaviStatus: () => string;
 
-  getPathIndex(): number;
+  getPathIndex: () => number;
 
-  getPosition(): [number, number];
+  getPosition: () => [number, number];
 
-  getSpeed(): number;
+  getSpeed: () => number;
 
-  getMovedDistance(): number;
+  getMovedDistance: () => number;
 
-  getPathStartIdx(): number;
+  getPathStartIdx: () => number;
 
-  getPathEndIdx(): number;
+  getPathEndIdx: () => number;
 
-  moveByDistance(distance: number);
+  moveByDistance: (distance: number) => void;
 
-  moveToPoint(idx: number, tail: number);
+  moveToPoint: (idx: number, tail: number) => void;
 
-  isCursorAtPathEnd(): boolean;
+  isCursorAtPathEnd: () => boolean;
 
-  isCursorAtPathStart(): boolean;
+  isCursorAtPathStart: () => boolean;
 
-  setSpeed(speed: number);
+  setSpeed: (speed: number) => void;
 
-  setRange(startIndex: number, endIndex: number);
+  setRange: (startIndex: number, endIndex: number) => void;
 
-  on(eventName: String, handler: Function);
+  on: (eventName: string, handler: Function) => void;
 
-  off(eventName: String, handler: Function);
+  off: (eventName: string, handler: Function) => void;
 }
-
-type PathNavigatorType = PathNavigator;
-type PathSimplifierType = PathSimplifier;

+ 45 - 7
src/pages/rule-engine/Scene/Save/action/action.tsx

@@ -144,7 +144,11 @@ export default observer((props: ActionProps) => {
   const MessageNodes = (
     <>
       <Col span={7}>
-        <Form.Item {...props.restField} name={[name, 'notify', 'notifyType']}>
+        <Form.Item
+          {...props.restField}
+          name={[name, 'notify', 'notifyType']}
+          rules={[{ required: true, message: '请选择通知方式' }]}
+        >
           <Select
             options={messageType}
             fieldNames={{ value: 'id', label: 'name' }}
@@ -159,7 +163,11 @@ export default observer((props: ActionProps) => {
         </Form.Item>
       </Col>
       <Col span={7}>
-        <Form.Item {...props.restField} name={[name, 'notify', 'notifierId']}>
+        <Form.Item
+          {...props.restField}
+          name={[name, 'notify', 'notifierId']}
+          rules={[{ required: true, message: '请选择通知配置' }]}
+        >
           <Select
             options={messageConfig}
             loading={messageConfigLoading}
@@ -174,7 +182,11 @@ export default observer((props: ActionProps) => {
         </Form.Item>
       </Col>
       <Col span={6}>
-        <Form.Item {...props.restField} name={[name, 'notify', 'templateId']}>
+        <Form.Item
+          {...props.restField}
+          name={[name, 'notify', 'templateId']}
+          rules={[{ required: true, message: '请选择通知模板' }]}
+        >
           <Select
             options={messageTemplate}
             loading={messageTemplateLoading}
@@ -210,7 +222,11 @@ export default observer((props: ActionProps) => {
       </div>
       <Row gutter={24}>
         <Col span={4}>
-          <Form.Item {...props.restField} name={[name, 'executor']}>
+          <Form.Item
+            {...props.restField}
+            name={[name, 'executor']}
+            rules={[{ required: true, message: '请选择执行条件' }]}
+          >
             <Select
               options={[
                 { label: '消息通知', value: 'notify' },
@@ -257,7 +273,23 @@ export default observer((props: ActionProps) => {
       {type1 === 'device' &&
       deviceMessageType === MessageTypeEnum.WRITE_PROPERTY &&
       properties.length ? (
-        <Form.Item name={[name, 'device', 'message', 'properties']}>
+        <Form.Item
+          name={[name, 'device', 'message', 'properties']}
+          rules={[
+            {
+              validator: async (_: any, value: any) => {
+                if (value) {
+                  if (!Object.values(value)[0]) {
+                    return Promise.reject(new Error('请输入属性值'));
+                  }
+                } else {
+                  return Promise.reject(new Error('请选择属性'));
+                }
+                return Promise.resolve();
+              },
+            },
+          ]}
+        >
           <WriteProperty properties={properties} type={props.triggerType} form={props.form} />
         </Form.Item>
       ) : null}
@@ -266,7 +298,10 @@ export default observer((props: ActionProps) => {
       properties.length ? (
         <Row gutter={24}>
           <Col span={4}>
-            <Form.Item name={[name, 'device', 'message', 'properties']}>
+            <Form.Item
+              name={[name, 'device', 'message', 'properties']}
+              rules={[{ required: true, message: '请选择属性' }]}
+            >
               <ReadProperty properties={properties} />
             </Form.Item>
           </Col>
@@ -275,7 +310,10 @@ export default observer((props: ActionProps) => {
       {type1 === 'device' &&
       deviceMessageType === MessageTypeEnum.INVOKE_FUNCTION &&
       functionList.length ? (
-        <Form.Item name={[name, 'device', 'message', 'inputs']}>
+        <Form.Item
+          name={[name, 'device', 'message', 'inputs']}
+          rules={[{ required: true, message: '请输入功能值' }]}
+        >
           <FunctionCall functionData={functionList} />
         </Form.Item>
       ) : null}

+ 0 - 2
src/pages/rule-engine/Scene/Save/action/device/deviceModal.tsx

@@ -108,8 +108,6 @@ export default (props: DeviceModelProps) => {
     },
   ];
 
-  console.log(selectKeys);
-
   return (
     <>
       {visible && (

+ 24 - 5
src/pages/rule-engine/Scene/Save/action/device/index.tsx

@@ -155,7 +155,10 @@ export default (props: DeviceProps) => {
   return (
     <>
       <Col span={5}>
-        <Form.Item name={[name, 'device', 'productId']}>
+        <Form.Item
+          name={[name, 'device', 'productId']}
+          rules={[{ required: true, message: '请选择产品' }]}
+        >
           <Select
             showSearch
             options={productList}
@@ -185,17 +188,29 @@ export default (props: DeviceProps) => {
             <Select options={sourceList} style={{ width: 120 }} />
           </Form.Item>
           {selector === SourceEnum.fixed && (
-            <Form.Item name={[name, 'device', 'selectorValues']} {...props.restField}>
+            <Form.Item
+              name={[name, 'device', 'selectorValues']}
+              {...props.restField}
+              rules={[{ required: true, message: '请选择设备' }]}
+            >
               <Device productId={productId} />
             </Form.Item>
           )}
           {selector === SourceEnum.tag && (
-            <Form.Item name={[name, 'device', 'selectorValues']} {...props.restField}>
+            <Form.Item
+              name={[name, 'device', 'selectorValues']}
+              {...props.restField}
+              rules={[{ required: true, message: '请选择标签' }]}
+            >
               <TagModal tagData={tagList} />
             </Form.Item>
           )}
           {selector === SourceEnum.relation && (
-            <Form.Item name={[name, 'device', 'selectorValues']} {...props.restField}>
+            <Form.Item
+              name={[name, 'device', 'selectorValues']}
+              {...props.restField}
+              rules={[{ required: true, message: '请选择关系人' }]}
+            >
               <Select style={{ width: 300 }} />
             </Form.Item>
           )}
@@ -223,7 +238,11 @@ export default (props: DeviceProps) => {
       </Col>
       <Col span={4}>
         {messageType === MessageTypeEnum.INVOKE_FUNCTION ? (
-          <Form.Item name={[name, 'device', 'message', 'functionId']} {...props.restField}>
+          <Form.Item
+            name={[name, 'device', 'message', 'functionId']}
+            {...props.restField}
+            rules={[{ required: true, message: '请选择功能' }]}
+          >
             <Select
               showSearch
               options={functionList}

+ 59 - 19
src/pages/rule-engine/Scene/Save/action/messageContent.tsx

@@ -7,6 +7,7 @@ import {
   UserList,
 } from '@/pages/rule-engine/Scene/Save/action/VariableItems';
 import { InputFile } from '@/pages/rule-engine/Scene/Save/components';
+import { useCallback } from 'react';
 
 interface MessageContentProps {
   name: number;
@@ -20,6 +21,63 @@ interface MessageContentProps {
 const rowGutter = 12;
 
 export default (props: MessageContentProps) => {
+  const getRules = useCallback(
+    (item: any, type: string): any[] => {
+      const rules = [];
+      if (item.required) {
+        rules.push({
+          validator: async (_: any, value: any) => {
+            if (!value.value) {
+              if (['date'].includes(type)) {
+                return Promise.reject(new Error('请选择' + item.name));
+              } else {
+                return Promise.reject(new Error('请输入' + item.name));
+              }
+            }
+            return Promise.resolve();
+          },
+        });
+      }
+
+      if (type === 'link') {
+        rules.push({ max: 64, message: '最多64个字符' });
+      }
+
+      if (type === 'user') {
+        if (props.notifyType === 'email') {
+          rules.push({
+            validator: async (_: any, value: any) => {
+              if (value.value) {
+                const reg = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
+                if (!reg.test(value.value)) {
+                  return Promise.reject(new Error('请输入正确的邮箱地址'));
+                }
+              }
+              return Promise.resolve();
+            },
+          });
+        }
+
+        if (['sms', 'voice'].includes(props.notifyType)) {
+          rules.push({
+            validator: async (_: any, value: any) => {
+              if (value.value) {
+                const reg = /^[1][3-9]\d{9}$/;
+                if (!reg.test(value.value)) {
+                  return Promise.reject(new Error('请输入正确的手机号码'));
+                }
+              }
+              return Promise.resolve();
+            },
+          });
+        }
+      }
+
+      return rules;
+    },
+    [props.notifyType],
+  );
+
   return (
     <>
       {props.template && (
@@ -30,7 +88,7 @@ export default (props: MessageContentProps) => {
                 const type = item.expands?.businessType || item.type;
                 const _name = [props.name, 'notify', 'variables', item.id];
                 let initialValue = undefined;
-                const rules = [];
+                const rules = getRules(item, type);
                 if (type === 'user') {
                   initialValue = {
                     source: 'relation',
@@ -42,24 +100,6 @@ export default (props: MessageContentProps) => {
                     value: undefined,
                   };
                 }
-                if (item.required) {
-                  rules.push({
-                    validator: async (_: any, value: any) => {
-                      console.log(value);
-                      if (!value.value) {
-                        if (['date'].includes(type)) {
-                          return Promise.reject(new Error('请选择' + item.name));
-                        } else {
-                          return Promise.reject(new Error('请输入' + item.name));
-                        }
-                      }
-                      return Promise.resolve();
-                    },
-                  });
-                }
-                if (type === 'link') {
-                  rules.push({ max: 64, message: '最多64个字符' });
-                }
                 return (
                   <Col span={12} key={`${item.id}_${index}`}>
                     <Form.Item

+ 1 - 1
src/pages/rule-engine/Scene/Save/components/InputNumber.tsx

@@ -11,7 +11,6 @@ export default (props: InputNumberProps) => {
   const [unit, setUnit] = useState(props.value?.unit || 'seconds');
 
   useEffect(() => {
-    console.log('timer', props.value);
     setTime(props.value?.time || 0);
     setUnit(props.value?.unit || 'seconds');
   }, [props.value]);
@@ -41,6 +40,7 @@ export default (props: InputNumberProps) => {
       addonAfter={TimeTypeAfter}
       min={0}
       max={9999}
+      placeholder={'请输入时间'}
       onChange={(value) => {
         if (props.onChange) {
           props.onChange({

+ 18 - 10
src/pages/rule-engine/Scene/Save/index.tsx

@@ -71,7 +71,7 @@ export default () => {
         setParallel(_data.parallel);
         setShakeLimit(_data.shakeLimit || DefaultShakeLimit);
 
-        setTriggerValue(_data.terms || []);
+        setTriggerValue({ trigger: _data.terms || [] });
 
         if (_data.trigger?.device?.selectorValues) {
           setRequestParams({ trigger: _data.trigger });
@@ -103,7 +103,7 @@ export default () => {
       }
       formData.terms = triggerData.trigger;
     }
-    console.log(formData);
+    console.log('save', formData);
     if (formData) {
       setLoading(true);
       const resp = formData.id ? await service.updateScene(formData) : await service.save(formData);
@@ -271,7 +271,19 @@ export default () => {
               </Form.Item>
             )}
             {triggerType === TriggerWayType.device && (
-              <Form.Item name={['trigger', 'device']}>
+              <Form.Item
+                name={['trigger', 'device']}
+                rules={[
+                  {
+                    validator: async (_: any, value: any) => {
+                      if (!value) {
+                        return Promise.reject(new Error('请选择产品'));
+                      }
+                      return Promise.resolve();
+                    },
+                  },
+                ]}
+              >
                 <TriggerDevice className={'trigger-type-content'} />
               </Form.Item>
             )}
@@ -280,11 +292,7 @@ export default () => {
           requestParams &&
           requestParams.trigger?.device?.productId ? (
             <Form.Item label={AntiShake}>
-              <TriggerTerm
-                ref={triggerRef}
-                params={requestParams}
-                value={{ trigger: triggerValue }}
-              />
+              <TriggerTerm ref={triggerRef} params={requestParams} value={triggerValue} />
             </Form.Item>
           ) : null}
           <Form.Item hidden name={'parallel'} initialValue={true}>
@@ -305,8 +313,8 @@ export default () => {
                 <Tooltip
                   title={
                     <div>
-                      <div>串行:满足所有执行条件才会触发执行动作</div>
-                      <div>并行:满足任意条件时会触发执行动作</div>
+                      <div>串行:按顺序依次执行动作</div>
+                      <div>并行:同时执行所有动作</div>
                     </div>
                   }
                 >

+ 56 - 24
src/pages/rule-engine/Scene/Save/trigger/device.tsx

@@ -1,5 +1,5 @@
 import { useCallback, useEffect, useState } from 'react';
-import { Col, Row, Select, TreeSelect } from 'antd';
+import { Col, Form, Row, Select, TreeSelect } from 'antd';
 import { ItemGroup, TimingTrigger } from '@/pages/rule-engine/Scene/Save/components';
 import { getProductList } from '@/pages/rule-engine/Scene/Save/action/device/service';
 import { queryOrgTree } from '@/pages/rule-engine/Scene/Save/trigger/service';
@@ -153,29 +153,41 @@ export default (props: TriggerProps) => {
     <div className={classNames(props.className)}>
       <Row gutter={24}>
         <Col span={6}>
-          <Select
-            showSearch
-            value={props.value?.productId}
-            options={productList}
-            placeholder={'请选择产品'}
-            style={{ width: '100%' }}
-            listHeight={220}
-            onChange={(key: any, node: any) => {
-              productIdChange(key, node.metadata);
-              onChange({
-                productId: key,
-                selectorValues: undefined,
-                selector: 'fixed',
-                operation: {
-                  operator: undefined,
+          <Form.Item
+            noStyle
+            rules={[
+              {
+                validator: async (_: any, value: any) => {
+                  console.log('productId', value);
+                  return Promise.resolve();
                 },
-              });
-            }}
-            fieldNames={{ label: 'name', value: 'id' }}
-            filterOption={(input: string, option: any) =>
-              option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0
-            }
-          />
+              },
+            ]}
+          >
+            <Select
+              showSearch
+              value={props.value?.productId}
+              options={productList}
+              placeholder={'请选择产品'}
+              style={{ width: '100%' }}
+              listHeight={220}
+              onChange={(key: any, node: any) => {
+                productIdChange(key, node.metadata);
+                onChange({
+                  productId: key,
+                  selectorValues: undefined,
+                  selector: 'fixed',
+                  operation: {
+                    operator: undefined,
+                  },
+                });
+              }}
+              fieldNames={{ label: 'name', value: 'id' }}
+              filterOption={(input: string, option: any) =>
+                option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              }
+            />
+          </Form.Item>
         </Col>
         {props.value?.productId ? (
           <Col span={12}>
@@ -370,7 +382,27 @@ export default (props: TriggerProps) => {
             />
           </Col>
           <Col span={18}>
-            <span style={{ lineHeight: '32px' }}>定时读取所选属性值,用于条件配置</span>
+            <span style={{ lineHeight: '32px' }}>定时读取所选属性值</span>
+          </Col>
+        </Row>
+      )}
+      {props.value?.operation?.operator === OperatorEnum.reportEvent && (
+        <Row gutter={24}>
+          <Col span={6}>
+            <Select
+              value={props.value?.operation?.eventId}
+              options={events}
+              placeholder={'请选择事件'}
+              style={{ width: '100%' }}
+              fieldNames={{ label: 'name', value: 'id' }}
+              onChange={(value) => {
+                if (props.value) {
+                  const _value = { ...props.value };
+                  _value!.operation!.eventId = value;
+                  onChange(_value);
+                }
+              }}
+            />
           </Col>
         </Row>
       )}

+ 37 - 5
src/pages/rule-engine/Scene/Save/trigger/index.tsx

@@ -150,7 +150,10 @@ export default observer((props: TriggerProps) => {
     <div className={classNames(props.className)}>
       <Row gutter={24}>
         <Col span={6}>
-          <Form.Item name={['trigger', 'device', 'productId']}>
+          <Form.Item
+            name={['trigger', 'device', 'productId']}
+            rules={[{ required: true, message: '请选择产品' }]}
+          >
             <Select
               options={productList}
               placeholder={'请选择产品'}
@@ -211,6 +214,7 @@ export default observer((props: TriggerProps) => {
             <Form.Item
               name={['trigger', 'device', 'operation', 'operator']}
               initialValue={undefined}
+              rules={[{ required: true, message: '请选择触发类型' }]}
             >
               <Select
                 placeholder={'请选择触发类型'}
@@ -230,7 +234,10 @@ export default observer((props: TriggerProps) => {
         <>
           <Row gutter={24}>
             <Col span={6}>
-              <Form.Item name={['trigger', 'device', 'operation', 'functionId']}>
+              <Form.Item
+                name={['trigger', 'device', 'operation', 'functionId']}
+                rules={[{ required: true, message: '请选择功能' }]}
+              >
                 <Select
                   showSearch
                   options={functions}
@@ -277,7 +284,10 @@ export default observer((props: TriggerProps) => {
       {operation === OperatorEnum.writeProperty && (
         <Row>
           <Col span={24}>
-            <Form.Item name={['trigger', 'device', 'operation', 'writeProperties']}>
+            <Form.Item
+              name={['trigger', 'device', 'operation', 'writeProperties']}
+              rules={[{ required: true, message: '请输入修改值' }]}
+            >
               <Operation
                 propertiesList={properties.filter((item) => {
                   if (item.expands) {
@@ -293,7 +303,11 @@ export default observer((props: TriggerProps) => {
       {operation === OperatorEnum.readProperty && (
         <Row gutter={24}>
           <Col span={6}>
-            <Form.Item name={['trigger', 'device', 'operation', 'readProperties']} noStyle>
+            <Form.Item
+              name={['trigger', 'device', 'operation', 'readProperties']}
+              noStyle
+              rules={[{ required: true, message: '请选择属性' }]}
+            >
               <Select
                 mode={'multiple'}
                 options={properties.filter((item) => {
@@ -317,7 +331,25 @@ export default observer((props: TriggerProps) => {
             </Form.Item>
           </Col>
           <Col span={18}>
-            <span style={{ lineHeight: '32px' }}>定时读取所选属性值,用于条件配置</span>
+            <span style={{ lineHeight: '32px' }}>定时读取所选属性值</span>
+          </Col>
+        </Row>
+      )}
+      {operation === OperatorEnum.reportEvent && (
+        <Row gutter={24}>
+          <Col span={6}>
+            <Form.Item
+              name={['trigger', 'device', 'operation', 'eventId']}
+              noStyle
+              rules={[{ required: true, message: '请选择事件' }]}
+            >
+              <Select
+                options={events}
+                placeholder={'请选择事件'}
+                style={{ width: '100%' }}
+                fieldNames={{ label: 'name', value: 'id' }}
+              />
+            </Form.Item>
           </Col>
         </Row>
       )}

+ 5 - 0
yarn.lock

@@ -16469,6 +16469,11 @@ rc@^1.2.8:
     minimist "^1.2.0"
     strip-json-comments "~2.0.1"
 
+react-amap@^1.2.8:
+  version "1.2.8"
+  resolved "https://registry.npmmirror.com/react-amap/-/react-amap-1.2.8.tgz#cb5a6441c5e83acb0d7b2e8a1b20dc539b759d9b"
+  integrity sha512-uHPEUXti+CcwFyCeqGGqR0ACnXJA9D8S/lQYal9AG3XEOrwkaOFbWUavrvXxjcfAclROIWg8uKxzlRpMQnkHFg==
+
 react-attr-converter@^0.3.1:
   version "0.3.1"
   resolved "https://registry.yarnpkg.com/react-attr-converter/-/react-attr-converter-0.3.1.tgz#4a2abf6d907b7ddae4d862dfec80e489ce41ad6e"