feat: add formula field type (#457)
* feat: add formula field type * feat: issue for useCollectionField * feat: add formula field type * feat: add formula field type
This commit is contained in:
parent
b8fac535f2
commit
efc4301be6
@ -27,6 +27,7 @@
|
||||
"file-saver": "^2.0.5",
|
||||
"i18next": "^21.6.0",
|
||||
"marked": "^4.0.12",
|
||||
"mathjs": "^10.6.0",
|
||||
"react-beautiful-dnd": "^13.1.0",
|
||||
"react-big-calendar": "^0.38.7",
|
||||
"react-drag-listview": "^0.1.9",
|
||||
@ -34,6 +35,7 @@
|
||||
"react-i18next": "^11.15.1",
|
||||
"react-image-lightbox": "^5.1.4",
|
||||
"react-quill": "^1.3.5",
|
||||
"react-contenteditable": "^3.3.6",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"slate": "^0.76.1",
|
||||
"slate-history": "^0.66.0",
|
||||
|
@ -0,0 +1,55 @@
|
||||
import { defaultProps, operators } from './properties';
|
||||
import { IField } from './types';
|
||||
|
||||
export const formula: IField = {
|
||||
name: 'formula',
|
||||
type: 'object',
|
||||
group: 'basic',
|
||||
order: 9,
|
||||
title: '{{t("Formula")}}',
|
||||
sortable: true,
|
||||
default: {
|
||||
type: 'formula',
|
||||
// name,
|
||||
uiSchema: {
|
||||
type: 'number',
|
||||
// title,
|
||||
"x-disabled": true,
|
||||
'x-component': 'Formula.Result',
|
||||
'x-component-props': {
|
||||
stringMode: true,
|
||||
step: '1',
|
||||
},
|
||||
},
|
||||
},
|
||||
properties: {
|
||||
...defaultProps,
|
||||
'expression': {
|
||||
type: 'string',
|
||||
title: '{{t("Expression")}}',
|
||||
required: true,
|
||||
description: '{{t("Input +、-、*、/、( ) to calculate, input @ to open field variables.")}}',
|
||||
'x-component': 'Formula.Expression',
|
||||
'x-decorator': 'FormItem',
|
||||
},
|
||||
'uiSchema.x-component-props.step': {
|
||||
type: 'string',
|
||||
title: '{{t("Precision")}}',
|
||||
'x-component': 'Select',
|
||||
'x-decorator': 'FormItem',
|
||||
required: true,
|
||||
default: '0',
|
||||
enum: [
|
||||
{ value: '0', label: '1' },
|
||||
{ value: '0.1', label: '1.0' },
|
||||
{ value: '0.01', label: '1.00' },
|
||||
{ value: '0.001', label: '1.000' },
|
||||
{ value: '0.0001', label: '1.0000' },
|
||||
{ value: '0.00001', label: '1.00000' },
|
||||
],
|
||||
},
|
||||
},
|
||||
filterable: {
|
||||
operators: operators.number,
|
||||
},
|
||||
};
|
@ -24,4 +24,5 @@ export * from './textarea';
|
||||
export * from './time';
|
||||
export * from './updatedAt';
|
||||
export * from './updatedBy';
|
||||
export * from './formula';
|
||||
|
||||
|
@ -118,6 +118,7 @@ export default {
|
||||
"Number": "数字",
|
||||
"Percent": "百分比",
|
||||
"Password": "密码",
|
||||
"Formula": "公式",
|
||||
"Choices": "选择类型",
|
||||
"Checkbox": "勾选",
|
||||
"Single select": "下拉菜单(单选)",
|
||||
@ -345,6 +346,9 @@ export default {
|
||||
'Role UID': '角色标识',
|
||||
|
||||
'Precision': '精确度',
|
||||
'Formula mode': '计算方式',
|
||||
'Expression': '表达式',
|
||||
'Input +、-、*、/、( ) to calculate, input @ to open field variables.': '英文输入+、-、*、/、( ) 进行运算,输入@打开可用字段变量。',
|
||||
'Accept': '文件格式',
|
||||
'Rich Text': '富文本',
|
||||
'Junction collection': '中间表',
|
||||
|
@ -0,0 +1,46 @@
|
||||
import { onFormValuesChange } from '@formily/core';
|
||||
import { connect, mapReadPretty, useFieldSchema, useFormEffects } from '@formily/react';
|
||||
import { InputNumber } from 'antd';
|
||||
import React, { useState } from 'react';
|
||||
import * as math from 'mathjs';
|
||||
import _ from 'lodash';
|
||||
import { ReadPretty } from '../input-number/ReadPretty';
|
||||
import { useCollection, useCollectionField } from '../../../collection-manager/hooks';
|
||||
|
||||
const AntdCompute = (props) => {
|
||||
const { value, onChange, step } = props;
|
||||
// const { expression } = useCollectionField();
|
||||
const { getField } = useCollection();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const options = getField(fieldSchema.name);
|
||||
const { expression } = options;
|
||||
const [computeValue, setComputeValue] = useState(value);
|
||||
|
||||
useFormEffects(() => {
|
||||
onFormValuesChange((form) => {
|
||||
const scope = _.cloneDeep(form.values);
|
||||
let result;
|
||||
try {
|
||||
result = math.evaluate(expression, scope);
|
||||
result = math.round(result, 9);
|
||||
} catch {}
|
||||
if (result) {
|
||||
setComputeValue(result);
|
||||
if (onChange) {
|
||||
onChange(result);
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return (
|
||||
<InputNumber readOnly value={computeValue} stringMode={true} step={step} />
|
||||
);
|
||||
}
|
||||
|
||||
export const Compute = connect(
|
||||
AntdCompute,
|
||||
mapReadPretty(ReadPretty)
|
||||
);
|
||||
|
||||
export default Compute;
|
@ -0,0 +1 @@
|
||||
export * from './Compute';
|
@ -0,0 +1,46 @@
|
||||
import { onFormValuesChange } from '@formily/core';
|
||||
import { connect, mapReadPretty, useFieldSchema, useFormEffects } from '@formily/react';
|
||||
import { InputNumber } from 'antd';
|
||||
import React, { useState } from 'react';
|
||||
import * as math from 'mathjs';
|
||||
import _ from 'lodash';
|
||||
import { ReadPretty } from '../input-number/ReadPretty';
|
||||
import { useCollection, useCollectionField } from '../../../collection-manager/hooks';
|
||||
|
||||
const AntdCompute = (props) => {
|
||||
const { value, onChange, step } = props;
|
||||
// const { expression } = useCollectionField();
|
||||
const { getField } = useCollection();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const options = getField(fieldSchema.name);
|
||||
const { expression } = options;
|
||||
const [computeValue, setComputeValue] = useState(value);
|
||||
|
||||
useFormEffects(() => {
|
||||
onFormValuesChange((form) => {
|
||||
const scope = _.cloneDeep(form.values);
|
||||
let result;
|
||||
try {
|
||||
result = math.evaluate(expression, scope);
|
||||
result = math.round(result, 9);
|
||||
} catch {}
|
||||
if (result) {
|
||||
setComputeValue(result);
|
||||
if (onChange) {
|
||||
onChange(result);
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return (
|
||||
<InputNumber readOnly value={computeValue} stringMode={true} step={step} />
|
||||
);
|
||||
}
|
||||
|
||||
export const Compute = connect(
|
||||
AntdCompute,
|
||||
mapReadPretty(ReadPretty)
|
||||
);
|
||||
|
||||
export default Compute;
|
@ -0,0 +1,104 @@
|
||||
import { CloseOutlined, LoadingOutlined } from '@ant-design/icons';
|
||||
import { useFormLayout } from '@formily/antd';
|
||||
import { connect, mapProps, mapReadPretty, useFieldSchema } from '@formily/react';
|
||||
import { isValid } from '@formily/shared';
|
||||
import { useRecord } from '@nocobase/client';
|
||||
import { Button, Input, Popover, Tag, Menu, Dropdown } from 'antd';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import ContentEditable from 'react-contenteditable';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useCollectionManager } from '../../../collection-manager/hooks';
|
||||
import { hasIcon, Icon, icons } from '../../../icon';
|
||||
|
||||
const AntdFormulaInput = (props) => {
|
||||
const { value, onChange } = props;
|
||||
const record = useRecord();
|
||||
const { getCollectionFields } = useCollectionManager();
|
||||
const fields = getCollectionFields(record.collectionName || record.name) as any[];
|
||||
|
||||
const inputRef = useRef();
|
||||
const [dropdownVisible, setDropdownVisible] = useState(false);
|
||||
const [formula, setFormula] = useState(null);
|
||||
const [html, setHtml] = useState(null);
|
||||
|
||||
const numColumns = new Map<string, string>();
|
||||
fields.filter(field => field.interface === 'number').forEach(field => {
|
||||
numColumns.set(field.name, field.uiSchema.title);
|
||||
})
|
||||
const keys = Array.from(numColumns.keys());
|
||||
|
||||
let initHtml;
|
||||
if (value) {
|
||||
initHtml = value;
|
||||
numColumns.forEach((value, key) => {
|
||||
initHtml = initHtml.replaceAll(key, `<span contentEditable="false" style="border: 1px solid #aaa; padding: 2px 5px;">${value}</span>`)
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (onChange && formula) {
|
||||
let v = formula;
|
||||
numColumns.forEach((value, key) => {
|
||||
v = v.replaceAll(value, key);
|
||||
})
|
||||
if (v != value) {
|
||||
onChange(v);
|
||||
}
|
||||
}
|
||||
}, [formula])
|
||||
|
||||
const menu = (
|
||||
<Menu onClick={async (args) => {
|
||||
const replaceFormula = formula.replace('@', numColumns.get(args.key));
|
||||
const replaceHtml = html.replace('@', `<span contentEditable="false" style="border: 1px solid #aaa; padding: 2px 5px;">${numColumns.get(args.key)}</span>`);
|
||||
setFormula(replaceFormula);
|
||||
setHtml(replaceHtml);
|
||||
setDropdownVisible(false);
|
||||
}}>
|
||||
{
|
||||
keys.map(key => (<Menu.Item key={key}>{numColumns.get(key)}</Menu.Item>))
|
||||
}
|
||||
</Menu>
|
||||
);
|
||||
|
||||
const handleChange = (e) => {
|
||||
const current = inputRef.current as any;
|
||||
setFormula(e.currentTarget.textContent);
|
||||
setHtml(current.innerHTML);
|
||||
}
|
||||
|
||||
const handleKeyDown = (e) => {
|
||||
const {key} = e;
|
||||
switch (key) {
|
||||
case 'Enter':
|
||||
e.preventDefault();
|
||||
break;
|
||||
case '@':
|
||||
case 'Process':
|
||||
setDropdownVisible(true);
|
||||
break;
|
||||
default:
|
||||
setDropdownVisible(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown overlay={menu} visible={dropdownVisible}>
|
||||
<ContentEditable
|
||||
innerRef={inputRef}
|
||||
className="ant-input"
|
||||
onChange={handleChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
html={html || initHtml || ''}
|
||||
/>
|
||||
</Dropdown>
|
||||
)
|
||||
}
|
||||
|
||||
export const FormulaInput = connect(
|
||||
AntdFormulaInput,
|
||||
mapProps(),
|
||||
);
|
||||
|
||||
export default FormulaInput;
|
@ -0,0 +1,6 @@
|
||||
import { FormulaInput } from './FormulaInput';
|
||||
import { Compute } from './Compute';
|
||||
|
||||
export const Formula: any = () => null;
|
||||
Formula.Expression = FormulaInput;
|
||||
Formula.Result = Compute;
|
@ -32,4 +32,6 @@ export * from './tabs';
|
||||
export * from './time-picker';
|
||||
export * from './tree-select';
|
||||
export * from './upload';
|
||||
export * from './formula-input';
|
||||
export * from './compute';
|
||||
import './index.less';
|
||||
|
@ -18,7 +18,8 @@
|
||||
"flat": "^5.0.2",
|
||||
"glob": "^7.1.6",
|
||||
"sequelize": "^6.9.0",
|
||||
"umzug": "^3.1.1"
|
||||
"umzug": "^3.1.1",
|
||||
"mathjs": "^10.6.1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -0,0 +1,62 @@
|
||||
import { Database } from '../../database';
|
||||
import { mockDatabase } from '..';
|
||||
import { FormulaField } from '../../fields';
|
||||
|
||||
describe('formula field', () => {
|
||||
let db: Database;
|
||||
|
||||
beforeEach(async () => {
|
||||
db = mockDatabase();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await db.close();
|
||||
});
|
||||
|
||||
it('add formula field with old table, already has data.', async() => {
|
||||
const Test = db.collection({
|
||||
name: 'tests',
|
||||
fields: [{ type: 'float', name: 'price' }, { type: 'float', name: 'count' }],
|
||||
});
|
||||
|
||||
await db.sync();
|
||||
|
||||
const test = await Test.model.create<any>({
|
||||
price: '1.2',
|
||||
count: '2',
|
||||
});
|
||||
|
||||
const expression = 'price*count';
|
||||
const field = Test.addField('sum', { type: 'formula', expression });
|
||||
|
||||
await field.sync({});
|
||||
|
||||
const updatedTest = await Test.model.findByPk(test.id);
|
||||
const sum = updatedTest.get('sum');
|
||||
|
||||
const sumField = Test.getField<FormulaField>('sum');
|
||||
expect(sum).toEqual(sumField.caculate(expression, updatedTest.toJSON()));
|
||||
});
|
||||
|
||||
it('auto set formula field with create or update data', async () => {
|
||||
const expression = 'price*count';
|
||||
const Test = db.collection({
|
||||
name: 'tests',
|
||||
fields: [{ type: 'float', name: 'price' }, { type: 'float', name: 'count' }, {name: 'sum', type: 'formula', expression}],
|
||||
});
|
||||
|
||||
await db.sync();
|
||||
|
||||
const test = await Test.model.create<any>({
|
||||
price: '1.2',
|
||||
count: '2',
|
||||
});
|
||||
|
||||
const sumField = Test.getField<FormulaField>('sum');
|
||||
expect(test.get('sum')).toEqual(sumField.caculate(expression, test.toJSON()));
|
||||
|
||||
test.set('count', '6');
|
||||
await test.save();
|
||||
expect(test.get('sum')).toEqual(sumField.caculate(expression, test.toJSON()));
|
||||
})
|
||||
});
|
78
packages/core/database/src/fields/formula-field.ts
Normal file
78
packages/core/database/src/fields/formula-field.ts
Normal file
@ -0,0 +1,78 @@
|
||||
import { DataTypes } from 'sequelize';
|
||||
import { BaseColumnFieldOptions, Field } from './field';
|
||||
import * as math from 'mathjs';
|
||||
|
||||
export class FormulaField extends Field {
|
||||
get dataType() {
|
||||
return DataTypes.FLOAT;
|
||||
}
|
||||
|
||||
caculate(expression, scope) {
|
||||
let result;
|
||||
try {
|
||||
result = math.evaluate(expression, scope);
|
||||
result = math.round(result, 9);
|
||||
} catch {}
|
||||
return result;
|
||||
}
|
||||
|
||||
async initFieldData({ transaction }) {
|
||||
const { expression, name } = this.options;
|
||||
console.log('initFieldData', expression, name);
|
||||
|
||||
const records = await this.collection.repository.find({
|
||||
order: [this.collection.model.primaryKeyAttribute],
|
||||
transaction,
|
||||
});
|
||||
|
||||
for (const record of records) {
|
||||
const scope = record.toJSON();
|
||||
const result = this.caculate(expression, scope);
|
||||
if (result) {
|
||||
await record.update(
|
||||
{
|
||||
[name]: result,
|
||||
},
|
||||
{
|
||||
transaction,
|
||||
silent: true,
|
||||
hooks: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async caculateField(instance) {
|
||||
const { expression, name } = this.options;
|
||||
const scope = instance.toJSON();
|
||||
let result;
|
||||
try {
|
||||
result = math.evaluate(expression, scope);
|
||||
result = math.round(result, 9);
|
||||
} catch {}
|
||||
if (result) {
|
||||
instance.set(name, result);
|
||||
}
|
||||
}
|
||||
|
||||
bind() {
|
||||
super.bind();
|
||||
this.on('afterSync', this.initFieldData.bind(this));
|
||||
this.on('beforeCreate', this.caculateField.bind(this));
|
||||
this.on('beforeUpdate', this.caculateField.bind(this));
|
||||
}
|
||||
|
||||
unbind() {
|
||||
super.unbind();
|
||||
this.off('beforeCreate', this.caculateField.bind(this));
|
||||
this.off('beforeUpdate', this.caculateField.bind(this));
|
||||
this.off('afterSync', this.initFieldData.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
export interface FormulaFieldOptions extends BaseColumnFieldOptions {
|
||||
type: 'formula';
|
||||
|
||||
expression: string;
|
||||
}
|
@ -24,6 +24,7 @@ import { TimeFieldOptions } from './time-field';
|
||||
import { UidFieldOptions } from './uid-field';
|
||||
import { UUIDFieldOptions } from './uuid-field';
|
||||
import { VirtualFieldOptions } from './virtual-field';
|
||||
import { FormulaFieldOptions } from './formula-field'
|
||||
|
||||
export * from './array-field';
|
||||
export * from './belongs-to-field';
|
||||
@ -46,6 +47,7 @@ export * from './time-field';
|
||||
export * from './uid-field';
|
||||
export * from './uuid-field';
|
||||
export * from './virtual-field';
|
||||
export * from './formula-field';
|
||||
|
||||
export type FieldOptions =
|
||||
| BaseFieldOptions
|
||||
@ -62,6 +64,7 @@ export type FieldOptions =
|
||||
| SortFieldOptions
|
||||
| TextFieldOptions
|
||||
| VirtualFieldOptions
|
||||
| FormulaFieldOptions
|
||||
| ArrayFieldOptions
|
||||
| TimeFieldOptions
|
||||
| DateFieldOptions
|
||||
|
84
yarn.lock
84
yarn.lock
@ -2361,6 +2361,13 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.17.9", "@babel/runtime@^7.18.3":
|
||||
version "7.18.3"
|
||||
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.18.3.tgz#c7b654b57f6f63cf7f8b418ac9ca04408c4579f4"
|
||||
integrity sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/template@^7.10.4", "@babel/template@^7.16.7", "@babel/template@^7.4.0", "@babel/template@^7.4.4":
|
||||
version "7.16.7"
|
||||
resolved "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155"
|
||||
@ -7780,6 +7787,11 @@ compare-func@^2.0.0:
|
||||
array-ify "^1.0.0"
|
||||
dot-prop "^5.1.0"
|
||||
|
||||
complex.js@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.npmmirror.com/complex.js/-/complex.js-2.1.1.tgz#0675dac8e464ec431fb2ab7d30f41d889fb25c31"
|
||||
integrity sha512-8njCHOTtFFLtegk6zQo0kkVX1rngygb/KQI6z1qZxlFI3scluC+LVTCFbrkWjBv4vvLlbQ9t88IPMC6k95VTTg==
|
||||
|
||||
component-emitter@^1.2.1, component-emitter@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
|
||||
@ -8692,7 +8704,7 @@ decamelize@^1.0.0, decamelize@^1.1.0, decamelize@^1.1.2, decamelize@^1.2.0:
|
||||
resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
||||
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
|
||||
|
||||
decimal.js@^10.2.1:
|
||||
decimal.js@^10.2.1, decimal.js@^10.3.1:
|
||||
version "10.3.1"
|
||||
resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783"
|
||||
integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==
|
||||
@ -9501,6 +9513,11 @@ escape-html@^1.0.3:
|
||||
resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||
integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
|
||||
|
||||
escape-latex@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmmirror.com/escape-latex/-/escape-latex-1.2.0.tgz#07c03818cf7dac250cce517f4fda1b001ef2bca1"
|
||||
integrity sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==
|
||||
|
||||
escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
@ -10384,6 +10401,11 @@ formstream@^1.1.0:
|
||||
mime "^2.5.2"
|
||||
pause-stream "~0.0.11"
|
||||
|
||||
fraction.js@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.npmmirror.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950"
|
||||
integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==
|
||||
|
||||
fragment-cache@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
|
||||
@ -12475,6 +12497,11 @@ istanbul-reports@^3.0.2:
|
||||
html-escaper "^2.0.0"
|
||||
istanbul-lib-report "^3.0.0"
|
||||
|
||||
javascript-natural-sort@^0.7.1:
|
||||
version "0.7.1"
|
||||
resolved "https://registry.npmmirror.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59"
|
||||
integrity sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==
|
||||
|
||||
javascript-stringify@^2.0.1:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz#27c76539be14d8bd128219a2d731b09337904e79"
|
||||
@ -14341,6 +14368,36 @@ mathjax-full@^3.0.0:
|
||||
mj-context-menu "^0.6.1"
|
||||
speech-rule-engine "^3.3.3"
|
||||
|
||||
mathjs@^10.6.0:
|
||||
version "10.6.0"
|
||||
resolved "https://registry.npmmirror.com/mathjs/-/mathjs-10.6.0.tgz#7d9a36fa98c727d05fadadf1f4dba99fff071ab9"
|
||||
integrity sha512-4oI0CSX7LtcyexTSLV8uo+llj8hB5LvVE9ApjN6rBjBplQaZ4/Gr3jh0zEla9+KaCig5wonZ9oFKD+GKXFL8hg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.17.9"
|
||||
complex.js "^2.1.1"
|
||||
decimal.js "^10.3.1"
|
||||
escape-latex "^1.2.0"
|
||||
fraction.js "^4.2.0"
|
||||
javascript-natural-sort "^0.7.1"
|
||||
seedrandom "^3.0.5"
|
||||
tiny-emitter "^2.1.0"
|
||||
typed-function "^2.1.0"
|
||||
|
||||
mathjs@^10.6.1:
|
||||
version "10.6.1"
|
||||
resolved "https://registry.npmmirror.com/mathjs/-/mathjs-10.6.1.tgz#95b34178eed65cbf7a63d35c468ad3ac912f7ddf"
|
||||
integrity sha512-8iZp6uUKKBoCFoUHze9ydsrSji9/IOEzMhwURyoQXaLL1+ILEZnraw4KzZnUBt/XN6lPJPV+7JO94oil3AmosQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.18.3"
|
||||
complex.js "^2.1.1"
|
||||
decimal.js "^10.3.1"
|
||||
escape-latex "^1.2.0"
|
||||
fraction.js "^4.2.0"
|
||||
javascript-natural-sort "^0.7.1"
|
||||
seedrandom "^3.0.5"
|
||||
tiny-emitter "^2.1.0"
|
||||
typed-function "^2.1.0"
|
||||
|
||||
md5.js@^1.3.4:
|
||||
version "1.3.5"
|
||||
resolved "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
|
||||
@ -17520,7 +17577,7 @@ prop-types-exact@^1.2.0:
|
||||
object.assign "^4.1.0"
|
||||
reflect.ownkeys "^0.2.0"
|
||||
|
||||
prop-types@^15.5.10, prop-types@^15.5.8:
|
||||
prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.7.1:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||
@ -18276,6 +18333,14 @@ react-big-calendar@^0.38.7:
|
||||
react-overlays "^4.1.1"
|
||||
uncontrollable "^7.0.0"
|
||||
|
||||
react-contenteditable@^3.3.6:
|
||||
version "3.3.6"
|
||||
resolved "https://registry.npmmirror.com/react-contenteditable/-/react-contenteditable-3.3.6.tgz#4dac0eeaff268ca1614b52d4290d7b21f3bfb997"
|
||||
integrity sha512-61+Anbmzggel1sP7nwvxq3d2woD3duR5R89RoLGqKan1A+nruFIcmLjw2F+qqk70AyABls0BDKzE1vqS1UIF1g==
|
||||
dependencies:
|
||||
fast-deep-equal "^3.1.3"
|
||||
prop-types "^15.7.1"
|
||||
|
||||
react-docgen-typescript-dumi-tmp@^1.22.1-0:
|
||||
version "1.22.1-0"
|
||||
resolved "https://registry.npmjs.org/react-docgen-typescript-dumi-tmp/-/react-docgen-typescript-dumi-tmp-1.22.1-0.tgz#6f452de05c5c114a6e1dd60b34930afaa7ae39a0"
|
||||
@ -19613,6 +19678,11 @@ sdk-base@^2.0.1:
|
||||
dependencies:
|
||||
get-ready "~1.0.0"
|
||||
|
||||
seedrandom@^3.0.5:
|
||||
version "3.0.5"
|
||||
resolved "https://registry.npmmirror.com/seedrandom/-/seedrandom-3.0.5.tgz#54edc85c95222525b0c7a6f6b3543d8e0b3aa0a7"
|
||||
integrity sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==
|
||||
|
||||
semver-diff@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
|
||||
@ -20933,6 +21003,11 @@ timsort@^0.3.0:
|
||||
resolved "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
|
||||
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
|
||||
|
||||
tiny-emitter@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmmirror.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
|
||||
integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==
|
||||
|
||||
tiny-invariant@1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.npmmirror.com/tiny-invariant/-/tiny-invariant-1.0.6.tgz#b3f9b38835e36a41c843a3b0907a5a7b3755de73"
|
||||
@ -21340,6 +21415,11 @@ type-is@^1.6.16, type-is@^1.6.4:
|
||||
media-typer "0.3.0"
|
||||
mime-types "~2.1.24"
|
||||
|
||||
typed-function@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmmirror.com/typed-function/-/typed-function-2.1.0.tgz#ded6f8a442ba8749ff3fe75bc41419c8d46ccc3f"
|
||||
integrity sha512-bctQIOqx2iVbWGDGPWwIm18QScpu2XRmkC19D8rQGFsjKSgteq/o1hTZvIG/wuDq8fanpBDrLkLq+aEN/6y5XQ==
|
||||
|
||||
typedarray-to-buffer@^3.1.5:
|
||||
version "3.1.5"
|
||||
resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
|
||||
|
Loading…
Reference in New Issue
Block a user